Player = {} class("Player").extends(NobleSprite) function Player:init(x, y) Player.super.init(self, "assets/sprites/player", true) -- Animation properties self.animation:addState("run", 8, 14) self.animation.run.frameDuration = 2 self.animation:addState("up", 1, 7) self.animation.up.frameDuration = 6 self.animation:addState("down", 1, 7) self.animation.down.frameDuration = 6 self.animation:addState("boom", 15, 21) self.animation.boom.frameDuration = 6 self.animation.boom.loop = false self.animation:setState("down") self:add() -- Collision properties self:setSize(64, 64) self:moveTo(x, y) self:setZIndex(ZIndex.player) self:setGroups(CollideGroups.player) self:setCollidesWithGroups( { CollideGroups.enemy, CollideGroups.wall }) self:setCollideRect(3, 19, 60, 33) self:setTag(1) -- Physics properties self.fallSpeed = 0.05 self.xVelocity = -0.5 self.yVelocity = self.fallSpeed self.maxXSpeed = 2 self.maxYSpeed = 5 self.acceleration = 0.05 self.friction = 0.95 self.yInertia = 0 self.maxFallSpeed = 0.7 self.frictionAccel = 0.3 -- Player State self.touchingGround = false self.touchingCeiling = false self.touchingWall = false Player.dead = false Player.fullBat = 10000 Player.bat = Player.fullBat Player.dischargeRate = 1 Player.moveRight = false Player.moveLeft = false -- TODO: refactor to use a single variable self.lastDirection = nil self.targetDone = false self.debug = Noble.Settings.get("debug") end function Player:handleInput() if Player.bat <= 0 or Player.dead then self.yInertia = self.yInertia * self.friction return end local crankChange, acceleratedChange = playdate.getCrankChange() -- X velocity if not playdate.buttonIsPressed(playdate.kButtonLeft) and not playdate.buttonIsPressed(playdate.kButtonRight) then self.xVelocity = self.xVelocity * self.friction Player.moveRight = false Player.moveLeft = false self.animation:setState("down") end local isChangingDirection = false if playdate.buttonIsPressed(playdate.kButtonLeft) then if self.lastDirection == "right" then isChangingDirection = true end self:changeToRunState("left") self.lastDirection = "left" Player.moveLeft = true Player.moveRight = false self.xVelocity = self.xVelocity - self.acceleration elseif playdate.buttonIsPressed(playdate.kButtonRight) then if self.lastDirection == "left" then isChangingDirection = true end self:changeToRunState("right") Player.moveRight = true Player.moveLeft = false self.lastDirection = "right" self.xVelocity = self.xVelocity + self.acceleration end if isChangingDirection then self.xVelocity = self.xVelocity * self.frictionAccel end -- Y velocity if crankChange ~= 0 then if Player.moveRight == false and Player.moveLeft == false then if crankChange < 0 then -- TODO: animation depending on inertia if self.animation.current == "down" then -- TODO: ABSOLUTE BULLSHIT self.animation:setState("up") end else if self.animation.current == "up" then self.animation:setState("down") end end end self.yInertia = self.yInertia - (acceleratedChange * 0.02) else self.yInertia = self.yInertia * self.friction end end function Player:changeToRunState(direction) if direction == "left" then self.animation.direction = Noble.Animation.DIRECTION_LEFT self.animation:setState("run") elseif direction == "right" then self.animation.direction = Noble.Animation.DIRECTION_RIGHT self.animation:setState("run") end end function Player:boom(collisionObject) Player.dead = true self.animation:setState("boom") local particleB = ParticlePoly(self.x, self.y) particleB:setThickness(2) particleB:setAngular(-15, 15) particleB:setSize(1, 2) particleB:setSpeed(1, 3) particleB:setMode(Particles.modes.STAY) particleB:setBounds(0, 0, 400, 240) particleB:setColour(Graphics.kColorXOR) particleB:add(20) if collisionObject then collisionObject:remove() end end function Player:handleMovementAndCollisions() if Player.dead then return end local xVel = self.xVelocity local yVel = self.yVelocity + self.yInertia + self.fallSpeed if (self.x < 20 and xVel < 0) or (self.x > 380 and xVel > 0) then -- Screen bounds xVel = 0 end if self.y < -20 and yVel < 0 and Player.bat > 0 then yVel = 0 end local _, _, collisions, length = self:checkCollisions(self.x + xVel, self.y + yVel) self.touchingGround = false self.touchingCeiling = false self.touchingWall = false for i = 1, length do local collision = collisions[i] local collisionType = collision.type local collisionObject = collision.other local collisionTag = collisionObject:getTag() if collisionType == Graphics.sprite.kCollisionTypeSlide then if collision.normal.y == -1 then self.touchingGround = true elseif collision.normal.y == 1 then self.touchingCeiling = true end if collision.normal.x ~= 0 then self.touchingWall = true end end if collisionTag == 3 then -- Ground self:boom() return elseif collisionTag == 154 then -- Baleba if self.debug then return end self:boom(collisionObject) return elseif collisionTag == 2 then -- Tank self:boom() BigBoom() self.targetDone = true local particleC = ParticlePoly(collisionObject.x, collisionObject.y) particleC:setThickness(5) particleC:setAngular(-15, 15) particleC:setSize(1, 10) particleC:setSpeed(1, 3) particleC:setMode(Particles.modes.STAY) particleC:setBounds(0, 0, 400, 240) particleC:setColour(Graphics.kColorXOR) particleC:add(50) collisionObject:fadeout() return end end self:moveTo(self.x + xVel, self.y + yVel) end function Player:handleDischarge(state) if Player.dead then return end if Player.bat <= 0 then Player.bat = 0 self.fallSpeed = 2 self.animation:setState("down") return end if Player.bat < 5000 then self.fallSpeed = self.maxFallSpeed end if Player.bat < 3000 then self.frictionAccel = 0.4 end if state == "run" then Player.dischargeRate = 5 elseif state == "up" then Player.dischargeRate = 10 else Player.dischargeRate = 1 end if self.y < 5 then Player.dischargeRate = 20 end Player.bat = Player.bat - Player.dischargeRate end function Player:update() self:handleMovementAndCollisions() if Player.dead then return end self:handleDischarge(self.animation.currentName) self:handleInput() end function Player:isMovingRight() return Player.moveRight end function Player:isDead() return Player.dead end function Player:getBat() return Player.bat end