2023-09-30 19:19:04 +00:00
|
|
|
-- A superclass for all player and AI-controlled units
|
|
|
|
import "CoreLibs/object"
|
|
|
|
import "CoreLibs/graphics"
|
|
|
|
import "CoreLibs/sprites"
|
2023-10-03 20:16:19 +00:00
|
|
|
import "statemachine"
|
2023-09-30 19:19:04 +00:00
|
|
|
|
|
|
|
local gfx <const> = playdate.graphics
|
2023-10-01 05:48:06 +00:00
|
|
|
local geom <const> = playdate.geometry
|
2023-09-30 19:19:04 +00:00
|
|
|
|
|
|
|
class("Entity").extends(gfx.sprite)
|
|
|
|
|
2023-09-30 19:34:29 +00:00
|
|
|
function Entity:init(img, health, armor)
|
2023-09-30 19:19:04 +00:00
|
|
|
Entity.super.init(self, img)
|
2023-10-03 20:16:19 +00:00
|
|
|
self.type = "entity"
|
2023-09-30 19:19:04 +00:00
|
|
|
self.health = health or 10
|
2023-09-30 19:34:29 +00:00
|
|
|
self.armor = armor or 0
|
2023-10-03 20:16:19 +00:00
|
|
|
self.introAnimator = nil
|
2023-09-30 19:19:04 +00:00
|
|
|
|
2023-09-30 20:02:37 +00:00
|
|
|
-- movement direction, every update() the entity will move along this vector and return
|
|
|
|
-- collision data to the subclass
|
2023-10-01 05:48:06 +00:00
|
|
|
self.vector = geom.vector2D.new(0, 0)
|
2023-09-30 19:19:04 +00:00
|
|
|
self:setCollideRect(0, 0, self:getSize())
|
|
|
|
|
|
|
|
-- most entities will be enemies, so we configure this mask by default
|
2023-09-30 19:47:26 +00:00
|
|
|
-- We don't set a collider mask because collision is a bit too variable
|
|
|
|
-- (but we should always include 0x2 and handle player collisions)
|
|
|
|
self:setGroupMask(0x4)
|
2023-10-03 20:16:19 +00:00
|
|
|
|
|
|
|
-- state machine mapping
|
|
|
|
-- this can be extended by subclasses if they need more states using
|
|
|
|
-- StateMachine:addState()
|
|
|
|
local states = {
|
|
|
|
["INIT"] = {
|
|
|
|
main=self.runInit,
|
|
|
|
transition=self.onInit
|
|
|
|
},
|
|
|
|
["INTRO"] = {
|
|
|
|
main=self.runIntro,
|
|
|
|
transition=self.onIntro,
|
|
|
|
},
|
|
|
|
["READY"] = {
|
|
|
|
main=self.runReady,
|
|
|
|
transition=self.onReady,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
self.fsm = StateMachine.new({self}, states)
|
2023-09-30 19:19:04 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function Entity:damage(amount)
|
2023-09-30 19:34:29 +00:00
|
|
|
if amount < self.armor then return end
|
|
|
|
|
|
|
|
self.health = math.max(self.health - (amount - self.armor), 0)
|
2023-09-30 19:19:04 +00:00
|
|
|
|
|
|
|
if self.health == 0 then
|
2023-10-03 20:16:19 +00:00
|
|
|
self:remove()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function Entity:add()
|
|
|
|
Entity.super.add(self)
|
|
|
|
if self.introAnimator then
|
|
|
|
self.fsm:changeState("INTRO")
|
|
|
|
else
|
|
|
|
self.fsm:changeState("READY")
|
2023-09-30 19:19:04 +00:00
|
|
|
end
|
|
|
|
end
|
2023-09-30 20:02:37 +00:00
|
|
|
|
|
|
|
function Entity:update()
|
2023-10-03 20:16:19 +00:00
|
|
|
-- update state machine
|
|
|
|
self.fsm:execute()
|
|
|
|
end
|
|
|
|
|
|
|
|
-- State machine-controlled functions
|
|
|
|
|
|
|
|
function Entity:onInit()
|
|
|
|
-- noop
|
|
|
|
end
|
|
|
|
|
|
|
|
function Entity:runInit()
|
|
|
|
-- noop
|
|
|
|
end
|
|
|
|
|
|
|
|
function Entity:onIntro()
|
|
|
|
-- noop
|
|
|
|
end
|
|
|
|
|
|
|
|
function Entity:runIntro()
|
|
|
|
if self.introAnimator and not self.introAnimator:ended() then
|
|
|
|
self:moveTo(self.introAnimator:currentValue())
|
|
|
|
else
|
|
|
|
self.fsm:changeState("READY")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function Entity:onReady()
|
|
|
|
-- noop
|
2023-09-30 20:02:37 +00:00
|
|
|
end
|
2023-09-30 22:23:42 +00:00
|
|
|
|
2023-10-03 20:16:19 +00:00
|
|
|
function Entity:runReady()
|
|
|
|
return select(3, self:moveWithCollisions(self.x + self.vector.dx, self.y + self.vector.dy))
|
2023-09-30 22:23:42 +00:00
|
|
|
end
|