summaryrefslogtreecommitdiffhomepage
path: root/player.lua
diff options
context:
space:
mode:
Diffstat (limited to 'player.lua')
-rw-r--r--player.lua449
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