diff options
Diffstat (limited to 'player.lua')
-rw-r--r-- | player.lua | 449 |
1 files changed, 0 insertions, 449 deletions
diff --git a/player.lua b/player.lua deleted file mode 100644 index 775dd60..0000000 --- a/player.lua +++ /dev/null @@ -1,449 +0,0 @@ --- `Player` --- Entity controlled by a player. It has a physical body and a sprite. Can play animations and interact with other instances of the same class. --- Collision category: [2] - --- WHOLE CODE HAS FLAG OF "need a cleanup" -require "animated" - --- Metatable of `Player` --- nils initialized in constructor -Player = { - -- General and physics - name = "empty", - body = nil, - shape = nil, - fixture = nil, - sprite = nil, - rotate = 0, -- "angle" would sound better - facing = 1, - max_velocity = 105, - world = nil, -- game world - -- Combat - combo = 0, - lives = 3, - spawntimer = 2, - alive = true, - punchcd = 0.25, - punchdir = 0, -- a really bad thing - -- Movement - inAir = true, - salto = false, - jumpactive = false, - jumpdouble = true, - jumptimer = 0.16, - jumpnumber = 2, - -- Keys - controlset = nil, - -- HUD - portrait_sprite = nil, - portrait_frame = nil, - portrait_sheet = require "nautsicons", - portrait_box = love.graphics.newQuad( 0, 15, 32,32, 80,130), - -- Sounds - sfx = require "sounds", - -- Animations table - animations = require "animations" -} -Player.__index = Player -setmetatable(Player, Animated) - --- Constructor of `Player` -function Player:new (game, world, x, y, name) - -- Meta - local o = {} - setmetatable(o, self) - -- Physics - local group = -1-#game.Nauts - o.body = love.physics.newBody(world, x, y, "dynamic") - o.shape = love.physics.newRectangleShape(10, 16) - o.fixture = love.physics.newFixture(o.body, o.shape, 8) - o.fixture:setUserData(o) - o.fixture:setCategory(2) - o.fixture:setMask(2) - o.fixture:setGroupIndex(group) - o.body:setFixedRotation(true) - -- Misc - o.name = name or "empty" - o:setSprite(newImage("assets/nauts/"..o.name..".png")) - o.world = game - o.punchcd = 0 - -- Animation - o.current = o.animations.default - o:createEffect("respawn") - -- Portrait load for first object created - if self.portrait_sprite == nil then - self.portrait_sprite = love.graphics.newImage("assets/portraits.png") - self.portrait_frame = love.graphics.newImage("assets/menu.png") - end - return o -end - --- Control set managment -function Player:assignControlSet(set) - self.controlset = set -end -function Player:getControlSet() - return self.controlset -end - --- Update callback of `Player` -function Player:update(dt) - -- hotfix? for destroyed bodies - if self.body:isDestroyed() then return end - -- locals - local x, y = self.body:getLinearVelocity() - local isDown = Controller.isDown - local controlset = self:getControlSet() - - -- # VERTICAL MOVEMENT - -- Jumping - if self.jumpactive and self.jumptimer > 0 then - self.body:setLinearVelocity(x,-160) - self.jumptimer = self.jumptimer - dt - end - - -- Salto - if self.salto and (self.current == self.animations.walk or self.current == self.animations.default) then - self.rotate = (self.rotate + 17 * dt * self.facing) % 360 - elseif self.rotate ~= 0 then - self.rotate = 0 - end - - -- # HORIZONTAL MOVEMENT - -- Walking - if isDown(controlset, "left") then - self.facing = -1 - self.body:applyForce(-250, 0) - -- Controlled speed limit - if x < -self.max_velocity then - self.body:applyForce(250, 0) - end - end - if isDown(controlset, "right") then - self.facing = 1 - self.body:applyForce(250, 0) - -- Controlled speed limit - if x > self.max_velocity then - self.body:applyForce(-250, 0) - end - end - - -- Custom linear damping - if not isDown(controlset, "left") and - not isDown(controlset, "right") - then - local face = nil - if x < -12 then - face = 1 - elseif x > 12 then - face = -1 - else - face = 0 - end - self.body:applyForce(40*face,0) - if not self.inAir then - self.body:applyForce(80*face,0) - end - end - - Animated.update(self, dt) - - -- # DEATH - -- We all die in the end. - local m = self.world.map - if (self.body:getX() < m.center_x - m.width*1.5 or self.body:getX() > m.center_x + m.width*1.5 or - self.body:getY() < m.center_y - m.height*1.5 or self.body:getY() > m.center_y + m.height*1.5) and - self.alive - then - self:die() - end - - -- respawn - if self.spawntimer > 0 then - self.spawntimer = self.spawntimer - dt - end - if self.spawntimer <= 0 and not self.alive and self.lives >= 0 then - self:respawn() - end - - -- # PUNCH - -- Cooldown - self.punchcd = self.punchcd - dt - if not self.body:isDestroyed() then -- This is weird - for _,fixture in pairs(self.body:getFixtureList()) do - if fixture:getUserData() ~= self then - fixture:setUserData({fixture:getUserData()[1] - dt, fixture:getUserData()[2]}) - if fixture:getUserData()[1] < 0 then - fixture:destroy() - end - end - end - end - - -- Stop vertical - local c,a = self.current, self.animations - if (c == a.attack_up or c == a.attack_down or c == a.attack) and self.frame < c.frames then - if self.punchdir == 0 then - self.body:setLinearVelocity(0,0) - else - self.body:setLinearVelocity(38*self.facing,0) - end - end - - if self.punchcd <= 0 and self.punchdir == 1 then - self.punchdir = 0 - end -end - --- Controller callbacks -function Player:controlpressed(set, action, key) - if set ~= self:getControlSet() then return end - local isDown = Controller.isDown - local controlset = self:getControlSet() - -- Jumping - if action == "jump" then - if self.jumpnumber > 0 then - -- General jump logics - self.jumpactive = true - --self:playSound(6) - -- Spawn proper effect - if not self.inAir then - self:createEffect("jump") - else - self:createEffect("doublejump") - end - -- Start salto if last jump - if self.jumpnumber == 1 then - self.salto = true - end - -- Animation clear - if (self.current == self.animations.attack) or - (self.current == self.animations.attack_up) or - (self.current == self.animations.attack_down) then - self:setAnimation("default") - end - -- Remove jump - self.jumpnumber = self.jumpnumber - 1 - end - end - - -- Walking - if (action == "left" or action == "right") and - (self.current ~= self.animations.attack) and - (self.current ~= self.animations.attack_up) and - (self.current ~= self.animations.attack_down) then - self:setAnimation("walk") - end - - -- Punching - if action == "attack" and self.punchcd <= 0 then - local f = self.facing - self.salto = false - if isDown(controlset, "up") then - -- Punch up - if self.current ~= self.animations.damage then - self:setAnimation("attack_up") - end - self:hit("up") - elseif isDown(controlset, "down") then - -- Punch down - if self.current ~= self.animations.damage then - self:setAnimation("attack_down") - end - self:hit("down") - else - -- Punch horizontal - if self.current ~= self.animations.damage then - self:setAnimation("attack") - end - if f == 1 then - self:hit("right") - else - self:hit("left") - end - self.punchdir = 1 - end - end -end -function Player:controlreleased(set, action, key) - if set ~= self:getControlSet() then return end - local isDown = Controller.isDown - local controlset = self:getControlSet() - -- Jumping - if action == "jump" then - self.jumpactive = false - self.jumptimer = Player.jumptimer -- take initial from metatable - end - -- Walking - if (action == "left" or action == "right") and not - (isDown(controlset, "left") or isDown(controlset, "right")) and - self.current == self.animations.walk - then - self:setAnimation("default") - end -end - --- Draw of `Player` -function Player:draw(offset_x, offset_y, scale, debug) - -- draw only alive - if not self.alive then return end - -- locals - local offset_x = offset_x or 0 - local offset_y = offset_y or 0 - local scale = scale or 1 - local debug = debug or false - local x, y = self:getPosition() - -- pixel grid ; `approx` selected to prevent floating characters on certain conditions - local approx = math.floor - if (y - math.floor(y)) > 0.5 then approx = math.ceil end - local draw_y = (approx(y) + offset_y) * scale - local draw_x = (math.floor(x) + offset_x) * scale - -- sprite draw - Animated.draw(self, draw_x, draw_y, self.rotate, self.facing*scale, scale, 12, 15) - -- debug draw - if debug then - for _,fixture in pairs(self.body:getFixtureList()) do - if fixture:getCategory() == 2 then - love.graphics.setColor(137, 255, 0, 120) - else - love.graphics.setColor(137, 0, 255, 40) - end - love.graphics.polygon("fill", self.world.camera:translatePoints(self.body:getWorldPoints(fixture:getShape():getPoints()))) - end - for _,contact in pairs(self.body:getContactList()) do - love.graphics.setColor(255, 0, 0, 255) - love.graphics.setPointSize(scale) - love.graphics.points(self.world.camera:translatePoints(contact:getPositions())) - end - end -end - --- getPosition -function Player:getPosition() - return self.body:getPosition() -end - --- Draw HUD of `Player` --- elevation: 1 bottom, 0 top -function Player:drawHUD(x,y,scale,elevation) - -- hud displays only if player is alive - if self.alive then - love.graphics.setColor(255,255,255,255) - love.graphics.draw(self.portrait_frame, self.portrait_box, (x)*scale, (y)*scale, 0, scale, scale) - love.graphics.draw(self.portrait_sprite, self.portrait_sheet[self.name], (x+2)*scale, (y+3)*scale, 0, scale, scale) - local dy = 30 * elevation - love.graphics.setFont(Font) - love.graphics.print((self.combo*10).."%",(x+2)*scale,(y-3+dy)*scale,0,scale,scale) - love.graphics.print(math.max(0, self.lives),(x+24)*scale,(y-3+dy)*scale,0,scale,scale) - end -end - --- Change animation of `Player` --- default, walk, attack, attack_up, attack_down, damage -function Player:nextFrame() - local isDown = Controller.isDown - local controlset = self:getControlSet() - if self.current.repeated or not (self.frame == self.current.frames) then - self.frame = (self.frame % self.current.frames) + 1 - elseif isDown(controlset, "right") or isDown(controlset, "left") then - -- If nonrepeatable animation is finished and player is walking - self:setAnimation("walk") - elseif self.current == self.animations.damage then - self:setAnimation("default") - end -end - --- Spawn `Effect` relative to `Player` -function Player:createEffect(name) - if name == "trail" or name == "hit" then - -- 16px effect: -7 -7 - self.world:createEffect(name, self.body:getX()-8, self.body:getY()-8) - elseif name ~= nil then - -- 24px effect: -12 -15 - self.world:createEffect(name, self.body:getX()-12, self.body:getY()-15) - end -end - --- Punch of `Player` --- direction: left, right, up, down --- creates temporary fixture for player's body that acts as sensor; fixture is deleted after time set in UserData[1]; deleted by Player:update(dt) -function Player:hit(direction) - -- start cooldown - self.punchcd = Player.punchcd -- INITIAL from metatable - -- actual punch - local fixture - if direction == "left" then - fixture = love.physics.newFixture(self.body, love.physics.newPolygonShape(-2,-6, -20,-6, -20,6, -2,6), 0) - end - if direction == "right" then - fixture = love.physics.newFixture(self.body, love.physics.newPolygonShape(2,-6, 20,-6, 20,6, 2,6), 0) - end - if direction == "up" then - fixture = love.physics.newFixture(self.body, love.physics.newPolygonShape(-8,-4, -8,-20, 8,-20, 8,-4), 0) - end - if direction == "down" then - fixture = love.physics.newFixture(self.body, love.physics.newPolygonShape(-8,4, -8,20, 8,20, 8,4), 0) - end - fixture:setSensor(true) - fixture:setCategory(3) - fixture:setMask(1,3) - fixture:setGroupIndex(self.fixture:getGroupIndex()) - fixture:setUserData({0.08, direction}) - -- sound - self:playSound(4) -end - --- Taking damage of `Player` by successful hit test --- currently called from World's startContact -function Player:damage(direction) - local horizontal, vertical = 0, 0 - if direction == "left" then - horizontal = -1 - end - if direction == "right" then - horizontal = 1 - end - if direction == "up" then - vertical = -1 - end - if direction == "down" then - vertical = 1 - end - self:createEffect("hit") - local x,y = self.body:getLinearVelocity() - self.body:setLinearVelocity(x,0) - self.body:applyLinearImpulse((42+10*self.combo)*horizontal, (68+10*self.combo)*vertical + 15) - self:setAnimation("damage") - self.combo = math.min(27, self.combo + 1) - self.punchcd = 0.08 + self.combo*0.006 - self:playSound(2) -end - --- DIE -function Player:die() - self:playSound(1) - self.combo = Player.combo -- INITIAL from metatable - self.lives = self.lives - 1 - self.alive = false - self.spawntimer = Player.spawntimer -- INITIAL from metatable - self.body:setActive(false) - self.world:onNautKilled(self) -end - --- And then respawn. Like Jon Snow. -function Player:respawn() - self.alive = true - self.body:setLinearVelocity(0,0) - self.body:setPosition(self.world:getSpawnPosition()) - self.body:setActive(true) - self:createEffect("respawn") - self:playSound(7) -end - --- Sounds -function Player:playSound(sfx, force) - if self.alive or force then - local source = love.audio.newSource(self.sfx[sfx]) - source:play() - end -end |