Player = Entity:New(x,y) function Player:New(x,y) local o = Entity:New(x,y) Player.health = 3 Player.coins = 0 -- physics o.vel = { x = 0, y = 0 } -- constants o.acc = 45 o.friction = 20 o.gravity = 9.81 o.climbHeight = 4 o.jumpForce = 5 o.maxSpeed = 600 o.jumpMaxSpeed = 9.5 o.zeroSpeed = 0.001 o.lightRange = 20 -- status o.isJumping = false o.isOnGround = 0 o.coyoteValue = 5 o.isOnLadder = false o.canJump = true o.canFall = true o.canFriction = true o.mask_type = animation.moth_mask -- sprite o.sprite_offset = {x = 8, y = 16} o.target_offset = {x = 0, y = 12} o.body = Animation:New(animation.nancy.idle) o.mask = Animation:New(animation.moth_mask.idle) -- lights setmetatable(o, self) self.__index = self return o end function Player:Smart() -- PLATFORMER INPUT if self.isOnGround > 0 then -- apply friction -- horizontal input (slide~~) if love.keyboard.isDown('a',"left") then self.vel.x = self.vel.x - self.acc*current_dt end if love.keyboard.isDown('d',"right") then self.vel.x = self.vel.x + self.acc*current_dt end if self.canJump then -- vertical input (jump!) if love.keyboard.isDown("up", "w") and self.isJumping ~= true then self.vel.y = self.vel.y - self.jumpForce self.isOnGround = 0 self.isJumping = true end end end -- fall if down input on platforms if not isThereCollisionAt( self.pos.x, self.pos.y + self.vel.y ) and not isThereLadderAt( self.pos.x, self.pos.y + self.vel.y ) and isTherePlatformAt( self.pos.x, self.pos.y + self.vel.y ) and love.keyboard.isDown("down", "s") then self.pos.y = self.pos.y + tileProperties.height/3 self.isOnGround = 0 end end function Player:HandleAnimation() -- flip sprite to look in the direction is moving if self.vel.x ~= 0 then self.sprite_flip.x = math.sign(self.vel.x) end -- animation manager if self.isOnLadder then self.body = self.body:ChangeTo(animation.nancy.jump) self.mask = self.mask:ChangeTo(self.mask_type.jump) elseif self.isOnGround == 0 and self.isJumping and self.vel.y > 1.25 then self.body = self.body:ChangeTo(animation.nancy.fall) self.mask = self.mask:ChangeTo(self.mask_type.fall) elseif self.isOnGround == 0 and self.vel.y < 0 then self.body = self.body:ChangeTo(animation.nancy.jump) self.mask = self.mask:ChangeTo(self.mask_type.jump) elseif self.vel.x ~= 0 then self.body = self.body:ChangeTo(animation.nancy.run) self.mask = self.mask:ChangeTo(self.mask_type.run) else self.body = self.body:ChangeTo(animation.nancy.idle) self.mask = self.mask:ChangeTo(self.mask_type.idle) end -- special case: idle animation gets slower by time if self.body.anim_path == animation.nancy.idle.path then if self.body.anim_speed < 0.5 then self.body.anim_speed = self.body.anim_speed + 0.001 end end self.body:Animate() self.body:Draw( self.pos.x - Camera.pos.x - ( (self.sprite_offset.x) * math.cos(self.sprite_rotation) - (self.sprite_offset.y) * math.sin(self.sprite_rotation)) * self.sprite_scale.x * self.sprite_flip.x, self.pos.y - Camera.pos.y - ( (self.sprite_offset.x) * math.sin(self.sprite_rotation) + (self.sprite_offset.y) * math.cos(self.sprite_rotation)) * self.sprite_scale.y * self.sprite_flip.y, self.sprite_rotation, self.sprite_scale.x * self.sprite_flip.x, self.sprite_scale.y * self.sprite_flip.y ) self.mask:Draw( self.pos.x - Camera.pos.x - ( (self.sprite_offset.x) * math.cos(self.sprite_rotation) - (self.sprite_offset.y) * math.sin(self.sprite_rotation)) * self.sprite_scale.x * self.sprite_flip.x, self.pos.y - Camera.pos.y - ( (self.sprite_offset.x) * math.sin(self.sprite_rotation) + (self.sprite_offset.y) * math.cos(self.sprite_rotation)) * self.sprite_scale.y * self.sprite_flip.y, self.sprite_rotation, self.sprite_scale.x * self.sprite_flip.x, self.sprite_scale.y * self.sprite_flip.y ) --[[ love.graphics.print(self.body.frame .. "/".. self.body.frames.." - "..self.body.subframe.."/"..self.body.speed.." ("..current_dt..")") love.graphics.print(animation.nancy.idle.path,0,20) love.graphics.print(self.body.path,0,30) ]] end function Player:DoPhysics() -- reset physics resolution self.canFall = true self.canJump = true self.canFriction = true -- reset flags self.isOnLadder = false -- truncate to max & min values if math.abs(self.vel.x) > self.maxSpeed then self.vel.x = self.maxSpeed * math.sign(self.vel.x) end if math.abs(self.vel.y) > self.maxSpeed then self.vel.y = self.maxSpeed * math.sign(self.vel.y) end if math.abs(self.vel.x) < self.zeroSpeed then self.vel.x = 0 end if math.abs(self.vel.y) < self.zeroSpeed then self.vel.y = 0 end -- if on air, say so! if self.vel.y > 5 then self.isJumping = true end -- if its on ground, then say so. if self.vel.y > 0 then if isThereAnyCollisionAt( self.pos.x, self.pos.y + self.vel.y ) then self.isOnGround = self.coyoteValue self.isJumping = false end end -- horizontal collisions if isThereAnyCollisionAt(self.pos.x + self.vel.x, self.pos.y) then -- checks for ladders if isThereLadderAt(self.pos.x + self.vel.x, self.pos.y) and self.vel.x ~= 0 and not isThereLadderAt(self.pos.x, self.pos.y) then self.vel.y = 0 self.vel.x = 0 self.pos.y = self.pos.y - 4 * current_dt self.canFall = false self.canJump = false self.canFriction = false self.isOnLadder = true self.isOnGround = self.coyoteValue end -- checks for slopes for i = 1, self.climbHeight do if not isThereCollisionAt(self.pos.x + self.vel.x, self.pos.y - i) and self.isOnGround > 0 then self.pos.x = self.pos.x + self.vel.x * 4/5 self.pos.y = self.pos.y - i self.canFriction = false break end end -- hey, you arent permanently stopped while collisioning, just lose a bit of force! if self.canFriction then self.vel.x = self.vel.x * (1 - math.min(current_dt * self.friction/15, 1)) end else self.pos.x = self.pos.x + self.vel.x end -- vertical collision if self.vel.y > 0 and isThereAnyCollisionAt(self.pos.x, self.pos.y + self.vel.y) then self.isOnGround = self.coyoteValue self.isJumping = false self.vel.y = 0 else self.pos.y = self.pos.y + self.vel.y self.isOnGround = math.max(self.isOnGround - 1, 0) end -- drop. if self.canFall then self.vel.y = self.vel.y + 2*self.gravity * current_dt end -- friction hard in ground, soft in air if self.isOnGround > 0 then self.vel.x = self.vel.x * (1 - math.min(current_dt * self.friction, 1)) else self.vel.x = self.vel.x * (1 - math.min(current_dt * self.friction/20, 1)) end end