384 lines
9.3 KiB
Lua
384 lines
9.3 KiB
Lua
Player = {}
|
|
Player.type = "Player"
|
|
Player.supertype = Entity.type
|
|
Player.display = Animation:new(animation.nancy.idle)
|
|
setmetatable(Player, Entity)
|
|
|
|
function Player:new(x,y)
|
|
local o = Entity:new(x,y)
|
|
|
|
-- physics
|
|
o.zero_speed = 0.01 -- gameworld pixels
|
|
|
|
o.move_x = 0 -- gameworld pixels
|
|
o.move_speed = 1.3 -- gameworld pixels
|
|
|
|
o.nodrift_frames = 0 -- frames
|
|
|
|
o.air_friction = 0.01 -- gameworld pixels
|
|
o.ground_friction = 0.3 -- gameworld pixels
|
|
o.wall_friction = 0.3 -- gameworld pixels
|
|
|
|
o.jump_impulse = 3.5 -- gameworld pixels
|
|
|
|
o.coyote_value = 5 -- frames
|
|
o.coyote_amount = 5 -- int
|
|
|
|
|
|
-- dash values
|
|
o.dash_timer = 0 -- seconds
|
|
o.dash_time = 0.15 -- seconds
|
|
o.dash_distance = 40 -- gameworld pixels
|
|
o.dash_speed = o.dash_distance / (o.dash_time*60) -- pixels
|
|
o.dash_count = 1 -- int
|
|
o.dash_amount = 10 -- int
|
|
o.dash_cooldown_time = 0.1 -- seconds
|
|
o.dash_cooldown_timer = 0 -- seconds
|
|
|
|
-- hook values
|
|
o.hook_swing_speed = math.rad(0.05)
|
|
o.hook_anchor = nil
|
|
|
|
-- walljump values
|
|
o.walljump_nodrift_amount = 12
|
|
o.walljump_impulse = { x = 2.5, y = 3.5 }
|
|
|
|
-- status
|
|
o.can_jump = true
|
|
o.can_fall = true
|
|
o.can_friction = true
|
|
o.can_hook = true
|
|
o.can_walljump = true
|
|
|
|
o.is_dashing = false
|
|
o.is_hooked = false
|
|
o.is_sliding = false
|
|
o.is_jumping = false
|
|
o.is_on_ground = false
|
|
o.is_on_ladder = false
|
|
|
|
o.mask_type = animation.moth_mask
|
|
o.wall_hit = 0
|
|
|
|
o.respawn_anchor = {
|
|
x = o.pos.x,
|
|
y = o.pos.y
|
|
}
|
|
|
|
-- sprite
|
|
o.target_offset = {x = 0, y = 0}
|
|
o.body = Animation:new(animation.nancy.idle)
|
|
o.mask = Animation:new(animation.moth_mask.idle)
|
|
|
|
o:centerOffset(o.body)
|
|
o:createBox(o.body,0,4,-1,-5)
|
|
|
|
-- lights
|
|
local light_data = {}
|
|
light_data.radius = 40
|
|
light_data.shine_radius = 20
|
|
light_data.flicker = nil
|
|
light_data.color = nil
|
|
o.light = Light:new(o.pos.x,o.pos.y,light_data)
|
|
|
|
o:id()
|
|
|
|
setmetatable(o, self)
|
|
self.__index = self
|
|
return o
|
|
end
|
|
|
|
function Player:doLogic()
|
|
|
|
-- reset coyote_value
|
|
if self.is_on_ground then
|
|
self.coyote_value = self.coyote_amount
|
|
elseif self.coyote_value > 0 then
|
|
self.coyote_value = self.coyote_value - 1
|
|
end
|
|
|
|
-- not dashing, normal movment
|
|
if self.dash_timer <= 0 then
|
|
-- horizontal movement
|
|
if not self.is_hooked then
|
|
if self.nodrift_frames > 0 then
|
|
self.move_x = 0
|
|
elseif Keybind:checkDown(Keybind.move.left) then
|
|
self.move_x = -1
|
|
self.vel.x = math.min(self.vel.x, -self.move_speed)
|
|
elseif Keybind:checkDown(Keybind.move.right) then
|
|
self.move_x = 1
|
|
self.vel.x = math.max(self.vel.x, self.move_speed)
|
|
end
|
|
end
|
|
|
|
-- jump if on ground (coyotevalue) or if 0
|
|
if self.can_jump and Keybind:checkPressed(Keybind.move.jump) then
|
|
if self.can_walljump and self.wall_hit ~= 0 then
|
|
self.is_sliding = false
|
|
self.vel.y = -self.walljump_impulse.y
|
|
self.vel.x = -self.walljump_impulse.x * self.wall_hit
|
|
self.move_x = 0
|
|
self.sprite_flip.x = -self.sprite_flip.x
|
|
self.nodrift_frames = self.walljump_nodrift_amount
|
|
elseif self.coyote_value > 0 then
|
|
self.vel.y = -self.jump_impulse
|
|
self.coyote_value = 0
|
|
end
|
|
end
|
|
end
|
|
|
|
-- dash timer
|
|
self.dash_cooldown_timer = math.max(0,self.dash_cooldown_timer - current_dt)
|
|
|
|
-- try to dash
|
|
if Keybind:checkDown(Keybind.move.dash) then
|
|
if self.dash_cooldown_timer == 0
|
|
and not self.is_dashing
|
|
and self.dash_count > 0 then
|
|
|
|
self:unhook()
|
|
self.nodrift_frames = 0
|
|
|
|
-- state player
|
|
self.is_dashing = true
|
|
self.is_sliding = false
|
|
self.dash_count = self.dash_count - 1
|
|
|
|
-- get dash direction
|
|
local vertical = 0
|
|
if Keybind:checkDown(Keybind.move.down) then vertical = vertical + 1 end
|
|
if Keybind:checkDown(Keybind.move.up) then vertical = vertical - 1 end
|
|
local horizontal = 0
|
|
if Keybind:checkDown(Keybind.move.right) then horizontal = horizontal + 1 end
|
|
if Keybind:checkDown(Keybind.move.left) then horizontal = horizontal - 1 end
|
|
|
|
-- if no direction, then dash forward
|
|
if horizontal == 0 and vertical == 0 then
|
|
horizontal = self.sprite_flip.x
|
|
end
|
|
|
|
-- set dash values
|
|
self.dashDirection = getAngleFromVector(vector(horizontal, vertical))
|
|
self.dash_timer = math.floor(self.dash_time * game.framerate)
|
|
end
|
|
else
|
|
-- not dashing!
|
|
self.is_dashing = false
|
|
end
|
|
|
|
if self.can_hook and Keybind:checkPressed(Keybind.move.hook) then
|
|
if self.is_hooked then
|
|
self:unhook()
|
|
else
|
|
local anchor = self:checkNearest("HookAnchor","hook_specific")
|
|
if anchor then
|
|
self.is_hooked = true
|
|
self.hook_distance = anchor.hook_distance
|
|
self.hook_anchor = {
|
|
x = anchor.pos.x,
|
|
y = anchor.pos.y
|
|
}
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function Player:doPhysics()
|
|
if self.dash_timer <= 0 then
|
|
if self.is_on_ground then
|
|
self.vel.x = self.vel.x * (1-self.ground_friction)
|
|
else
|
|
self.vel.x = self.vel.x * (1-self.air_friction)
|
|
end
|
|
|
|
self.is_sliding = false
|
|
if self.wall_hit == 0 then
|
|
self.vel.y = self.vel.y * (1-self.air_friction)
|
|
elseif self.nodrift_frames ~= self.walljump_nodrift_amount then
|
|
self.is_sliding = true
|
|
self.vel.y = self.vel.y * (1-self.wall_friction)
|
|
end
|
|
|
|
if math.abs(self.vel.x) < self.zero_speed then self.vel.x = 0 end
|
|
end
|
|
|
|
-- reset state
|
|
self.can_fall = true
|
|
self.is_on_ground = false
|
|
|
|
-- adjust timers
|
|
self.dash_timer = self.dash_timer - 1
|
|
self.nodrift_frames = self.nodrift_frames - 1
|
|
|
|
-- DASH STATE
|
|
if self.dash_timer > 0 then
|
|
self.can_fall = false
|
|
-- dash particle
|
|
local particle_data = {
|
|
animation = self.body,
|
|
animation_speed = 0,
|
|
sprite_tint = hex2rgb("#fed100"),
|
|
sprite_alpha = 0.5,
|
|
time = 0.2,
|
|
sprite_flip = {
|
|
x = self.sprite_flip.x,
|
|
y = self.sprite_flip.y
|
|
}
|
|
}
|
|
Particle:new(self.pos.x,self.pos.y,particle_data)
|
|
self.dash_cooldown_timer = self.dash_cooldown_time
|
|
-- dash movement
|
|
self.vel.x = self.dash_speed * math.cos(self.dashDirection)
|
|
self.vel.y = self.dash_speed * math.sin(self.dashDirection)
|
|
end
|
|
|
|
-- hook state
|
|
if self.is_hooked then
|
|
self.move_x = 0
|
|
local hook = vector(self.hook_anchor.x - self.pos.x, self.hook_anchor.y - self.pos.y)
|
|
local dist = math.min(getVectorValue(hook), self.hook_distance)
|
|
|
|
local hook_angle = getAngleFromVector(hook)-math.rad(180)
|
|
|
|
if Keybind:checkDown(Keybind.move.right) then
|
|
hook_angle = hook_angle - self.hook_swing_speed
|
|
end
|
|
|
|
if Keybind:checkDown(Keybind.move.left) then
|
|
hook_angle = hook_angle + self.hook_swing_speed
|
|
|
|
end
|
|
|
|
local particle_data = {
|
|
animation = self.body,
|
|
animation_speed = 0,
|
|
sprite_tint = hex2rgb("#fed100"),
|
|
sprite_alpha = 0.5,
|
|
time = 4,
|
|
time_unit = "frames",
|
|
sprite_flip = {
|
|
x = self.sprite_flip.x,
|
|
y = self.sprite_flip.y
|
|
}
|
|
}
|
|
Particle:new(self.pos.x,self.pos.y,particle_data)
|
|
|
|
local pos_x = self.hook_anchor.x + dist * math.cos(hook_angle)
|
|
local pos_y = self.hook_anchor.y + dist * math.sin(hook_angle)
|
|
self.vel.x = self.vel.x + pos_x - self.pos.x
|
|
self.vel.y = self.vel.y + pos_y - self.pos.y
|
|
|
|
self:moveX(
|
|
pos_x - self.pos.x
|
|
)
|
|
self:moveY(
|
|
pos_y - self.pos.y
|
|
)
|
|
end
|
|
|
|
|
|
if self.can_fall then
|
|
-- not in dash
|
|
self.dash_timer = 0
|
|
self.vel.y = self.vel.y + gravity
|
|
end
|
|
|
|
-- horizontal collision
|
|
self.wall_hit = 0
|
|
self:moveX(
|
|
self.vel.x,
|
|
function()
|
|
self.wall_hit = math.sign(self.vel.x)
|
|
self.vel.x = 0
|
|
end
|
|
)
|
|
|
|
-- vertical collision
|
|
self:moveY(
|
|
self.vel.y,
|
|
function()
|
|
if self.vel.y > 0 then
|
|
self.is_on_ground = true
|
|
self.dash_count = self.dash_amount
|
|
end
|
|
self.vel.y = 0
|
|
end
|
|
)
|
|
|
|
-- if u collision w hazard, respawn
|
|
if self:isCollidingAt(self.pos.x, self.pos.y, LoadedObjects.Hazards) then
|
|
self:respawn()
|
|
end
|
|
|
|
self:adjustLight(self.target_offset.x,self.target_offset.y)
|
|
end
|
|
|
|
function Player:respawn()
|
|
self.pos.x = self.respawn_anchor.x
|
|
self.pos.y = self.respawn_anchor.y
|
|
end
|
|
|
|
function Player:handleAnimation()
|
|
-- flip sprite to look in the direction is moving
|
|
if self.is_hooked then
|
|
if self.vel.x ~= 0 then
|
|
self.sprite_flip.x = math.sign(self.vel.x)
|
|
end
|
|
elseif self.move_x ~= 0 then
|
|
self.sprite_flip.x = math.sign(self.move_x)
|
|
end
|
|
-- animation priority
|
|
if self.is_sliding then
|
|
self.body = self.body:change(animation.nancy.slide)
|
|
self.mask = self.mask:change(self.mask_type.slide)
|
|
elseif self.vel.y > 1.25 then
|
|
self.body = self.body:change(animation.nancy.fall)
|
|
self.mask = self.mask:change(self.mask_type.fall)
|
|
elseif self.vel.y < 0 then
|
|
self.body = self.body:change(animation.nancy.jump)
|
|
self.mask = self.mask:change(self.mask_type.jump)
|
|
elseif self.vel.x + self.move_x ~= 0 and not self.is_hooked then
|
|
self.body = self.body:change(animation.nancy.run)
|
|
self.mask = self.mask:change(self.mask_type.run)
|
|
elseif not self.is_hooked then
|
|
self.body = self.body:change(animation.nancy.idle)
|
|
self.mask = self.mask:change(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
|
|
|
|
if self.is_hooked then
|
|
love.graphics.line(
|
|
-Camera.pos.x + self.pos.x,
|
|
-Camera.pos.y + self.pos.y,
|
|
-Camera.pos.x + self.hook_anchor.x,
|
|
-Camera.pos.y + self.hook_anchor.y
|
|
)
|
|
end
|
|
|
|
self.body:animate()
|
|
self:draw(self.body)
|
|
|
|
if self.dash_count > 0 then
|
|
self:draw(self.mask)
|
|
end
|
|
self.move_x = 0
|
|
end
|
|
|
|
function Player:unhook()
|
|
self.is_hooked = false
|
|
self.hook_anchor = nil
|
|
self.hook_distance = nil
|
|
end
|
|
|
|
function Player:debug()
|
|
Entity.debug(self)
|
|
love.graphics.print("wall_hit: "..self.wall_hit)
|
|
end
|