| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- local PlayerMain = extend(app.player.base)
- function PlayerMain:activate()
- self.prev = setmetatable({}, self.meta)
- self.inputs = {}
- self.displaces = {}
- self.alpha = 1
- if self.heartbeatSound then self.heartbeatSound:stop() end
- self.heartbeatSound = ctx.sound:loop({sound = 'heartbeat', gui = true})
- if self.heartbeatSound then self.heartbeatSound:pause() end
- ctx.view.target = self
- app.player.base.activate(self)
- end
- function PlayerMain:get(t)
- if t == tick then
- return self
- else
- return self.prev
- end
- end
- function PlayerMain:update()
- if self.ded then
- self.ded = timer.rot(self.ded)
- self:fade()
- return app.player.base.update(self)
- end
- self.prev.x = self.x
- self.prev.y = self.y
- self.prev.z = self.z
- self.prev.angle = self.angle
- local input = self:readInput()
- self:move(input)
- self:turn(input)
- self:slot(input, self.prev.input)
- self:fade()
- if self.heartbeatSound then
- if self.health < self.maxHealth * .5 then
- if self.heartbeatSound:isPaused() then self.heartbeatSound:resume() end
- local prc = self.health / self.maxHealth
- self.heartbeatSound:setVolume(math.min(1 - ((prc - .3) / .2), 1.0))
- elseif not self.heartbeatSound:isPaused() then
- self.heartbeatSound:pause()
- end
- end
- ctx.net:send(app.net.messages.input, input)
- app.player.base.update(self)
- self.prev.input = input
- end
- function PlayerMain:draw()
- if self.ded then return end
- local lerpd = table.interpolate(self.prev, self, tickDelta / tickRate)
- self.drawAngle = lerpd.angle
- self.drawX, self.drawY = ctx.view:three(lerpd.x, lerpd.y, lerpd.z)
- self.drawScale = 1 + (ctx.view:convertZ(lerpd.z) / 500)
- app.player.base.draw(lerpd)
- end
- function PlayerMain:trace(data)
- do return end
- self.x, self.y = data.x / 10, data.y / 10
- self.health, self.shield = data.health, data.shield
- -- Discard inputs before the ack.
- while #self.inputs > 0 and self.inputs[1].tick < data.ack + 1 do
- table.remove(self.inputs, 1)
- end
- -- Server reconciliation: Apply inputs that occurred after the ack.
- for i = 1, #self.inputs do
- self:move(self.inputs[i])
- end
- self.moving = true
- ctx.event:emit('collision.move', {object = self, resolve = true})
- self.moving = nil
- end
- function PlayerMain:readInput()
- assert(not self.inputs[tick])
- local t = {tick = tick}
- for _, k in pairs({'w', 'a', 's', 'd'}) do
- t[k] = ctx.input:keyDown(k)
- end
- t.x = ctx.view:worldMouseX()
- t.y = ctx.view:worldMouseY()
- t.l = ctx.input:mouseDown('l')
- t.r = ctx.input:mouseDown('r')
- for i = 1, 5 do
- if ctx.input:keyDown(tostring(i)) then t.slot = i break end
- end
- t.reload = ctx.input:keyDown('r')
- table.insert(self.inputs, t)
- return t
- end
- function PlayerMain:fade()
- local s = self.ded and self.killer or self
- local function shouldFade(p)
- if p.team == s.team then return false end
- local vision = s.ded and 2 * math.pi or math.pi / 2
- if math.abs(math.anglediff(s.angle, math.direction(s.x, s.y, p.x, p.y))) > vision then return true end
- return ctx.collision:lineTest(s.x, s.y, p.x, p.y, {tag = 'wall', first = true})
- end
- ctx.players:each(function(p)
- if shouldFade(p) then p.alpha = math.max(p.alpha - tickRate, 0)
- else p.alpha = math.min(p.alpha + tickRate, 1) end
- end)
- end
- function PlayerMain:hurt(data)
- ctx.view:screenshake(math.clamp(data.amount, 0, 50) / 2)
- end
- function PlayerMain:die()
- if self.heartbeatSound then self.heartbeatSound:pause() end
- app.player.base.die(self)
- ctx.view:screenshake(20)
- ctx.view.target = nil
- ctx.view.target = self.killer
- end
- return PlayerMain
|