main.lua 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. local PlayerMain = extend(app.player.base)
  2. function PlayerMain:activate()
  3. self.prev = setmetatable({}, self.meta)
  4. self.inputs = {}
  5. self.displaces = {}
  6. self.alpha = 1
  7. if self.heartbeatSound then self.heartbeatSound:stop() end
  8. self.heartbeatSound = ctx.sound:loop({sound = 'heartbeat', gui = true})
  9. if self.heartbeatSound then self.heartbeatSound:pause() end
  10. ctx.view.target = self
  11. app.player.base.activate(self)
  12. end
  13. function PlayerMain:get(t)
  14. if t == tick then
  15. return self
  16. else
  17. return self.prev
  18. end
  19. end
  20. function PlayerMain:update()
  21. if self.ded then
  22. self.ded = timer.rot(self.ded)
  23. self:fade()
  24. return app.player.base.update(self)
  25. end
  26. self.prev.x = self.x
  27. self.prev.y = self.y
  28. self.prev.z = self.z
  29. self.prev.angle = self.angle
  30. local input = self:readInput()
  31. self:move(input)
  32. self:turn(input)
  33. self:slot(input, self.prev.input)
  34. self:fade()
  35. if self.heartbeatSound then
  36. if self.health < self.maxHealth * .5 then
  37. if self.heartbeatSound:isPaused() then self.heartbeatSound:resume() end
  38. local prc = self.health / self.maxHealth
  39. self.heartbeatSound:setVolume(math.min(1 - ((prc - .3) / .2), 1.0))
  40. elseif not self.heartbeatSound:isPaused() then
  41. self.heartbeatSound:pause()
  42. end
  43. end
  44. ctx.net:send(app.net.messages.input, input)
  45. app.player.base.update(self)
  46. self.prev.input = input
  47. end
  48. function PlayerMain:draw()
  49. if self.ded then return end
  50. local lerpd = table.interpolate(self.prev, self, tickDelta / tickRate)
  51. self.drawAngle = lerpd.angle
  52. self.drawX, self.drawY = ctx.view:three(lerpd.x, lerpd.y, lerpd.z)
  53. self.drawScale = 1 + (ctx.view:convertZ(lerpd.z) / 500)
  54. app.player.base.draw(lerpd)
  55. end
  56. function PlayerMain:trace(data)
  57. do return end
  58. self.x, self.y = data.x / 10, data.y / 10
  59. self.health, self.shield = data.health, data.shield
  60. -- Discard inputs before the ack.
  61. while #self.inputs > 0 and self.inputs[1].tick < data.ack + 1 do
  62. table.remove(self.inputs, 1)
  63. end
  64. -- Server reconciliation: Apply inputs that occurred after the ack.
  65. for i = 1, #self.inputs do
  66. self:move(self.inputs[i])
  67. end
  68. self.moving = true
  69. ctx.event:emit('collision.move', {object = self, resolve = true})
  70. self.moving = nil
  71. end
  72. function PlayerMain:readInput()
  73. assert(not self.inputs[tick])
  74. local t = {tick = tick}
  75. for _, k in pairs({'w', 'a', 's', 'd'}) do
  76. t[k] = ctx.input:keyDown(k)
  77. end
  78. t.x = ctx.view:worldMouseX()
  79. t.y = ctx.view:worldMouseY()
  80. t.l = ctx.input:mouseDown('l')
  81. t.r = ctx.input:mouseDown('r')
  82. for i = 1, 5 do
  83. if ctx.input:keyDown(tostring(i)) then t.slot = i break end
  84. end
  85. t.reload = ctx.input:keyDown('r')
  86. table.insert(self.inputs, t)
  87. return t
  88. end
  89. function PlayerMain:fade()
  90. local s = self.ded and self.killer or self
  91. local function shouldFade(p)
  92. if p.team == s.team then return false end
  93. local vision = s.ded and 2 * math.pi or math.pi / 2
  94. if math.abs(math.anglediff(s.angle, math.direction(s.x, s.y, p.x, p.y))) > vision then return true end
  95. return ctx.collision:lineTest(s.x, s.y, p.x, p.y, {tag = 'wall', first = true})
  96. end
  97. ctx.players:each(function(p)
  98. if shouldFade(p) then p.alpha = math.max(p.alpha - tickRate, 0)
  99. else p.alpha = math.min(p.alpha + tickRate, 1) end
  100. end)
  101. end
  102. function PlayerMain:hurt(data)
  103. ctx.view:screenshake(math.clamp(data.amount, 0, 50) / 2)
  104. end
  105. function PlayerMain:die()
  106. if self.heartbeatSound then self.heartbeatSound:pause() end
  107. app.player.base.die(self)
  108. ctx.view:screenshake(20)
  109. ctx.view.target = nil
  110. ctx.view.target = self.killer
  111. end
  112. return PlayerMain