2021-10-25 23:19:22 +00:00
|
|
|
Player = Entity:New(x,y)
|
|
|
|
|
|
|
|
|
|
|
|
function Player:New(x,y)
|
|
|
|
local o = Entity:New(x,y)
|
|
|
|
|
2022-02-10 17:18:37 +00:00
|
|
|
o.type = "player"
|
2021-10-25 23:19:22 +00:00
|
|
|
-- physics
|
2022-01-29 07:49:45 +00:00
|
|
|
o.moveSpeed = 1.3 -- gameworld pixels
|
|
|
|
o.zeroSpeed = 0.01 -- gameworld pixels
|
|
|
|
o.move_x = 0 -- gameworld pixels
|
2022-01-17 23:14:54 +00:00
|
|
|
|
2022-01-29 07:49:45 +00:00
|
|
|
o.airFriction = 0.01 -- gameworld pixels
|
|
|
|
o.groundFriction = 0.3 -- gameworld pixels
|
2022-01-17 23:14:54 +00:00
|
|
|
|
2022-01-29 07:49:45 +00:00
|
|
|
o.jumpImpulse = 3.5 -- gameworld pixels
|
2022-01-17 23:14:54 +00:00
|
|
|
|
2022-01-29 07:49:45 +00:00
|
|
|
o.coyoteAmount = 5 -- int
|
|
|
|
o.coyoteValue = 5 -- frames
|
2022-01-17 23:14:54 +00:00
|
|
|
|
2022-01-29 07:49:45 +00:00
|
|
|
o.dashCooldownTime = 0.1 -- seconds
|
|
|
|
o.dashCooldownTimer = 0 -- seconds
|
|
|
|
|
2022-02-10 17:18:37 +00:00
|
|
|
-- dash values
|
2022-01-29 07:49:45 +00:00
|
|
|
o.dashTimer = 0 -- seconds
|
|
|
|
o.dashTime = 0.15 -- seconds
|
|
|
|
o.dashDistance = 40 -- gameworld pixels
|
|
|
|
o.dashSpeed = o.dashDistance / (o.dashTime*60) -- pixels
|
|
|
|
o.dashCount = 1 -- int
|
2022-01-30 10:31:18 +00:00
|
|
|
o.dashAmount = 10 -- int
|
2021-10-29 00:17:18 +00:00
|
|
|
|
2022-02-10 17:18:37 +00:00
|
|
|
-- hook values
|
2022-02-12 10:43:56 +00:00
|
|
|
o.hookDistance = 80
|
2022-02-10 17:18:37 +00:00
|
|
|
o.hookedDistance = 80
|
|
|
|
o.hookAnchor = {
|
|
|
|
x = nil,
|
|
|
|
y = nil
|
|
|
|
}
|
|
|
|
|
2021-11-28 02:38:30 +00:00
|
|
|
o.boxCollision = {
|
2022-01-29 07:49:45 +00:00
|
|
|
from = {x = -8, y = -16}, --gameworld pixels
|
|
|
|
to = {x = 8, y = 0} -- gameworld pixels
|
2021-11-28 02:38:30 +00:00
|
|
|
}
|
|
|
|
|
2022-02-10 17:18:37 +00:00
|
|
|
o.lightRange = 10 -- screen pixels
|
2022-01-17 23:14:54 +00:00
|
|
|
|
2021-10-25 23:19:22 +00:00
|
|
|
-- status
|
2022-01-17 23:14:54 +00:00
|
|
|
o.isDashing = false
|
2021-10-25 23:19:22 +00:00
|
|
|
o.isJumping = false
|
2022-02-10 17:18:37 +00:00
|
|
|
o.isHooked = false
|
2022-01-29 07:49:45 +00:00
|
|
|
o.isOnGround = true
|
|
|
|
o.isOnLadder = false
|
2021-10-25 23:19:22 +00:00
|
|
|
o.canJump = true
|
|
|
|
o.canFall = true
|
|
|
|
o.canFriction = true
|
2021-11-28 02:38:30 +00:00
|
|
|
o.maskType = animation.moth_mask
|
2022-02-10 17:18:37 +00:00
|
|
|
|
2022-02-10 14:53:50 +00:00
|
|
|
o.anchorRespawn = {
|
|
|
|
x = o.pos.x,
|
|
|
|
y = o.pos.y
|
|
|
|
}
|
2021-11-28 02:38:30 +00:00
|
|
|
|
|
|
|
-- sprite
|
2022-02-05 11:32:47 +00:00
|
|
|
o.target_offset = {x = 0, y = 0}
|
2021-11-28 02:38:30 +00:00
|
|
|
o.body = Animation:New(animation.nancy.idle)
|
|
|
|
o.mask = Animation:New(animation.moth_mask.idle)
|
2022-01-17 23:14:54 +00:00
|
|
|
o:centerOffset(o.body)
|
2022-01-29 07:49:45 +00:00
|
|
|
o:getBoundingBox(o.body,0,3,-1,-3)
|
2021-10-29 00:17:18 +00:00
|
|
|
|
2021-11-28 02:38:30 +00:00
|
|
|
-- lights
|
|
|
|
o.light = CreateLight(o.pos.x,o.pos.y,o.lightRange)
|
2021-10-29 00:17:18 +00:00
|
|
|
|
2022-02-10 17:18:37 +00:00
|
|
|
table.insert(LoadedObjects.Entities,o)
|
|
|
|
o.id = #LoadedObjects.Entities
|
2022-01-19 22:29:02 +00:00
|
|
|
|
2021-10-25 23:19:22 +00:00
|
|
|
setmetatable(o, self)
|
|
|
|
self.__index = self
|
|
|
|
return o
|
|
|
|
end
|
|
|
|
|
|
|
|
function Player:Smart()
|
2022-02-10 17:18:37 +00:00
|
|
|
self:LightAdjust(self.target_offset.x,self.target_offset.y)
|
|
|
|
|
|
|
|
-- reset coyoteValue
|
|
|
|
if self.isOnGround then
|
|
|
|
self.coyoteValue = self.coyoteAmount
|
|
|
|
elseif self.coyoteValue > 0 then
|
|
|
|
self.coyoteValue = self.coyoteValue - 1
|
|
|
|
end
|
2022-01-17 23:14:54 +00:00
|
|
|
|
|
|
|
if self.dashTimer <= 0 then
|
2022-02-10 17:18:37 +00:00
|
|
|
-- horizontal movement
|
2022-01-19 13:55:15 +00:00
|
|
|
if Keybind:CheckDown(Keybind.move.left) then
|
2022-01-17 23:14:54 +00:00
|
|
|
self.move_x = -self.moveSpeed
|
2022-01-19 13:55:15 +00:00
|
|
|
elseif Keybind:CheckDown(Keybind.move.right) then
|
2022-01-17 23:14:54 +00:00
|
|
|
self.move_x = self.moveSpeed
|
|
|
|
end
|
|
|
|
|
2022-02-10 17:18:37 +00:00
|
|
|
-- jump if on ground (coyotevalue)
|
2022-01-19 13:55:15 +00:00
|
|
|
if Keybind:CheckDown(Keybind.move.jump) then
|
2022-01-29 07:49:45 +00:00
|
|
|
if self.coyoteValue > 0 then
|
2022-01-17 23:14:54 +00:00
|
|
|
self.vel.y = -self.jumpImpulse
|
2022-01-29 07:49:45 +00:00
|
|
|
self.coyoteValue = 0
|
2022-01-17 23:14:54 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-02-10 17:18:37 +00:00
|
|
|
-- dash timer
|
2022-01-17 23:14:54 +00:00
|
|
|
self.dashCooldownTimer = math.max(0,self.dashCooldownTimer - current_dt)
|
2022-02-10 17:18:37 +00:00
|
|
|
|
|
|
|
-- try to dash
|
2022-01-19 13:55:15 +00:00
|
|
|
if Keybind:CheckDown(Keybind.move.dash) then
|
2022-01-17 23:14:54 +00:00
|
|
|
if self.dashCooldownTimer == 0
|
|
|
|
and not self.isDashing
|
|
|
|
and self.dashCount > 0 then
|
2022-02-14 14:56:14 +00:00
|
|
|
self:Unhook()
|
2022-02-10 17:18:37 +00:00
|
|
|
|
|
|
|
-- state player
|
2022-01-17 23:14:54 +00:00
|
|
|
self.isDashing = true
|
2022-02-14 14:56:14 +00:00
|
|
|
self.dashCount = self.dashCount - 1
|
2022-02-10 17:18:37 +00:00
|
|
|
|
|
|
|
-- get dash direction
|
2022-01-17 23:14:54 +00:00
|
|
|
local vertical = 0
|
2022-01-19 13:55:15 +00:00
|
|
|
if Keybind:CheckDown(Keybind.move.down) then vertical = vertical + 1 end
|
|
|
|
if Keybind:CheckDown(Keybind.move.up) then vertical = vertical - 1 end
|
2022-01-17 23:14:54 +00:00
|
|
|
local horizontal = 0
|
2022-01-19 13:55:15 +00:00
|
|
|
if Keybind:CheckDown(Keybind.move.right) then horizontal = horizontal + 1 end
|
|
|
|
if Keybind:CheckDown(Keybind.move.left) then horizontal = horizontal - 1 end
|
2022-01-17 23:14:54 +00:00
|
|
|
|
2022-02-10 17:18:37 +00:00
|
|
|
-- if no direction, then dash forward
|
2022-01-17 23:14:54 +00:00
|
|
|
if horizontal == 0 and vertical == 0 then
|
|
|
|
horizontal = self.sprite_flip.x
|
|
|
|
end
|
|
|
|
|
2022-02-10 17:18:37 +00:00
|
|
|
-- set dash values
|
2022-01-17 23:14:54 +00:00
|
|
|
self.dashDirection = GetAngleFromVector(horizontal, vertical)
|
|
|
|
self.dashTimer = self.dashTime
|
|
|
|
end
|
|
|
|
else
|
2022-02-10 17:18:37 +00:00
|
|
|
-- not dashing!
|
2022-01-17 23:14:54 +00:00
|
|
|
self.isDashing = false
|
|
|
|
end
|
2022-02-10 17:18:37 +00:00
|
|
|
|
2022-02-12 19:03:48 +00:00
|
|
|
if Keybind:CheckPressed(Keybind.move.hook) then
|
|
|
|
if self.isHooked then
|
2022-02-14 14:56:14 +00:00
|
|
|
self:Unhook()
|
2022-02-12 19:03:48 +00:00
|
|
|
else
|
|
|
|
local anchor = self:CheckNearest("decoration",self.hookDistance)
|
|
|
|
if anchor then
|
|
|
|
self.isHooked = true
|
|
|
|
self.hookAnchor = {
|
|
|
|
x = anchor.pos.x,
|
|
|
|
y = anchor.pos.y
|
|
|
|
}
|
|
|
|
end
|
2022-02-10 17:18:37 +00:00
|
|
|
end
|
|
|
|
end
|
2021-11-28 02:38:30 +00:00
|
|
|
end
|
2021-10-25 23:19:22 +00:00
|
|
|
|
2021-11-28 02:38:30 +00:00
|
|
|
function Player:DoPhysics()
|
2022-02-03 05:02:06 +00:00
|
|
|
if self.dashTimer <= 0 then
|
|
|
|
if self.isOnGround then
|
|
|
|
self.vel.x = self.vel.x * (1-self.groundFriction)
|
|
|
|
else
|
|
|
|
self.vel.x = self.vel.x * (1-self.airFriction)
|
|
|
|
end
|
|
|
|
if math.abs(self.vel.x) < self.zeroSpeed then self.vel.x = 0 end
|
|
|
|
end
|
2022-02-10 17:18:37 +00:00
|
|
|
|
2022-01-29 07:49:45 +00:00
|
|
|
-- reset state
|
2022-02-10 17:18:37 +00:00
|
|
|
self.canFall = true
|
2022-01-17 23:14:54 +00:00
|
|
|
self.isOnGround = false
|
2022-01-29 07:49:45 +00:00
|
|
|
-- adjust timers
|
2022-01-17 23:14:54 +00:00
|
|
|
self.dashTimer = self.dashTimer - current_dt
|
2022-01-19 23:53:59 +00:00
|
|
|
|
|
|
|
-- DASH STATE
|
2022-01-17 23:14:54 +00:00
|
|
|
if self.dashTimer > 0 then
|
2022-02-10 17:18:37 +00:00
|
|
|
self.canFall = false
|
2022-01-29 07:49:45 +00:00
|
|
|
-- dash particle
|
2022-01-19 23:53:59 +00:00
|
|
|
local particle_data = {
|
|
|
|
animation = self.body,
|
|
|
|
sprite_tint = HEX2RGB("#fed100"),
|
2022-01-21 14:56:25 +00:00
|
|
|
sprite_alpha = 0.5,
|
2022-01-19 23:53:59 +00:00
|
|
|
sprite_flip = {
|
|
|
|
x = self.sprite_flip.x,
|
|
|
|
y = self.sprite_flip.y
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Particle:New(self.pos.x,self.pos.y,particle_data)
|
2022-01-17 23:14:54 +00:00
|
|
|
self.dashCooldownTimer = self.dashCooldownTime
|
2022-01-29 07:49:45 +00:00
|
|
|
-- dash movement
|
2022-01-17 23:14:54 +00:00
|
|
|
self.vel.x = self.dashSpeed * math.cos(self.dashDirection)
|
|
|
|
self.vel.y = self.dashSpeed * math.sin(self.dashDirection)
|
2022-02-10 17:18:37 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
-- hook state
|
|
|
|
if self.isHooked then
|
|
|
|
local hook = Vector(self.pos.x, self.pos.y, self.hookAnchor.x, self.hookAnchor.y)
|
|
|
|
if GetVectorValue(hook) > self.hookedDistance then
|
2022-02-12 19:03:48 +00:00
|
|
|
local particle_data = {
|
|
|
|
animation = self.body,
|
|
|
|
sprite_tint = HEX2RGB("#fed100"),
|
|
|
|
sprite_alpha = 0.5,
|
|
|
|
sprite_flip = {
|
|
|
|
x = self.sprite_flip.x,
|
|
|
|
y = self.sprite_flip.y
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Particle:New(self.pos.x,self.pos.y,particle_data)
|
|
|
|
local hook_angle = GetAngleFromVector(hook[1],hook[2])-math.rad(180)
|
2022-02-14 14:56:14 +00:00
|
|
|
if Keybind:CheckDown(Keybind.move.right) then hook_angle = hook_angle - math.rad(0.05) end
|
|
|
|
if Keybind:CheckDown(Keybind.move.left) then hook_angle = hook_angle + math.rad(0.05) end
|
2022-02-12 19:03:48 +00:00
|
|
|
local pos_x = self.hookAnchor.x + self.hookedDistance * math.cos(hook_angle)
|
|
|
|
local pos_y = self.hookAnchor.y + self.hookedDistance * math.sin(hook_angle)
|
2022-02-12 10:36:43 +00:00
|
|
|
self.vel.x = self.vel.x + pos_x - self.pos.x
|
|
|
|
self.vel.y = self.vel.y + pos_y - self.pos.y
|
2022-02-12 10:43:56 +00:00
|
|
|
self.pos.x = pos_x
|
|
|
|
self.pos.y = pos_y
|
2022-02-10 17:18:37 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
if self.canFall then
|
2022-02-12 19:03:48 +00:00
|
|
|
-- not in dash
|
2022-01-17 23:14:54 +00:00
|
|
|
self.dashTimer = 0
|
|
|
|
self.vel.y = self.vel.y + gravity
|
|
|
|
end
|
|
|
|
|
2022-02-10 17:18:37 +00:00
|
|
|
-- horizontal collision
|
2022-01-22 22:10:21 +00:00
|
|
|
if not self:isCollidingAt(self.pos.x + self.vel.x + self.move_x, self.pos.y, LoadedObjects.Collisions) then
|
2022-01-17 23:14:54 +00:00
|
|
|
self.pos.x = self.pos.x + self.vel.x + self.move_x
|
|
|
|
else
|
|
|
|
self.vel.x = 0
|
|
|
|
end
|
|
|
|
|
2022-02-10 17:18:37 +00:00
|
|
|
-- vertical collision
|
2022-01-22 22:10:21 +00:00
|
|
|
if not self:isCollidingAt(self.pos.x, self.pos.y + self.vel.y, LoadedObjects.Collisions) then
|
2022-01-17 23:14:54 +00:00
|
|
|
self.pos.y = self.pos.y + self.vel.y
|
|
|
|
else
|
|
|
|
if self.vel.y > 0 then
|
|
|
|
self.isOnGround = true
|
2022-01-29 07:49:45 +00:00
|
|
|
self.dashCount = self.dashAmount
|
2022-01-17 23:14:54 +00:00
|
|
|
end
|
2022-02-10 17:18:37 +00:00
|
|
|
self.vel.y = 0
|
2022-01-17 23:14:54 +00:00
|
|
|
end
|
2022-02-10 14:53:50 +00:00
|
|
|
|
2022-02-10 17:18:37 +00:00
|
|
|
-- if u collision w hazard, respawn
|
2022-02-10 14:53:50 +00:00
|
|
|
if self:isCollidingAt(self.pos.x, self.pos.y, LoadedObjects.Hazards) then
|
|
|
|
self:Respawn()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function Player:Respawn()
|
|
|
|
self.pos.x = self.anchorRespawn.x
|
|
|
|
self.pos.y = self.anchorRespawn.y
|
2021-10-25 23:19:22 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function Player:HandleAnimation()
|
|
|
|
-- flip sprite to look in the direction is moving
|
2022-01-17 23:14:54 +00:00
|
|
|
if self.move_x ~= 0 then self.sprite_flip.x = math.sign(self.move_x) end
|
2021-10-25 23:19:22 +00:00
|
|
|
|
2021-11-28 02:38:30 +00:00
|
|
|
-- animation priority
|
2021-10-29 02:15:53 +00:00
|
|
|
self.body = self.body:ChangeTo(animation.nancy.fall)
|
2022-02-10 17:18:37 +00:00
|
|
|
if self.vel.y > 1.25 then
|
2021-11-28 02:38:30 +00:00
|
|
|
self.mask = self.mask:ChangeTo(self.maskType.fall)
|
|
|
|
elseif self.vel.y < 0 then
|
2021-10-29 02:15:53 +00:00
|
|
|
self.body = self.body:ChangeTo(animation.nancy.jump)
|
2021-11-28 02:38:30 +00:00
|
|
|
self.mask = self.mask:ChangeTo(self.maskType.jump)
|
2022-01-17 23:14:54 +00:00
|
|
|
elseif self.vel.x + self.move_x ~= 0 then
|
2021-10-29 02:15:53 +00:00
|
|
|
self.body = self.body:ChangeTo(animation.nancy.run)
|
2021-11-28 02:38:30 +00:00
|
|
|
self.mask = self.mask:ChangeTo(self.maskType.run)
|
2021-10-25 23:19:22 +00:00
|
|
|
else
|
2021-10-29 02:15:53 +00:00
|
|
|
self.body = self.body:ChangeTo(animation.nancy.idle)
|
2021-11-28 02:38:30 +00:00
|
|
|
self.mask = self.mask:ChangeTo(self.maskType.idle)
|
2021-10-25 23:19:22 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
-- special case: idle animation gets slower by time
|
2021-10-29 02:15:53 +00:00
|
|
|
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
|
2021-10-25 23:19:22 +00:00
|
|
|
end
|
2021-10-29 02:15:53 +00:00
|
|
|
|
2022-02-10 17:18:37 +00:00
|
|
|
if self.isHooked then
|
|
|
|
love.graphics.line(
|
|
|
|
-Camera.pos.x + self.pos.x,
|
|
|
|
-Camera.pos.y + self.pos.y,
|
|
|
|
-Camera.pos.x + self.hookAnchor.x,
|
|
|
|
-Camera.pos.y + self.hookAnchor.y
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2021-10-29 02:15:53 +00:00
|
|
|
self.body:Animate()
|
2022-01-17 23:14:54 +00:00
|
|
|
self:Draw(self.body)
|
|
|
|
if self.dashCount > 0 then
|
|
|
|
self:Draw(self.mask)
|
|
|
|
end
|
2022-02-03 05:02:06 +00:00
|
|
|
self.move_x = 0
|
2021-10-25 23:19:22 +00:00
|
|
|
end
|
2022-02-14 14:56:14 +00:00
|
|
|
|
|
|
|
function Player:Unhook()
|
|
|
|
self.isHooked = false
|
|
|
|
self.hookAnchor = nil
|
|
|
|
end
|