Fix defend state, add animation tables (not used quite yet), and add onExit functions to the state machine.
This commit is contained in:
parent
9a26eb4b3a
commit
feb7541944
|
@ -16,6 +16,10 @@ function Entity:init(img, health, armor)
|
||||||
self.armor = armor or 0
|
self.armor = armor or 0
|
||||||
self.introAnimator = nil
|
self.introAnimator = nil
|
||||||
|
|
||||||
|
-- For imagetable-based animation
|
||||||
|
self.animationIndex = nil
|
||||||
|
self.animationTimer = nil
|
||||||
|
|
||||||
-- movement direction, every update() the entity will move along this vector and return
|
-- movement direction, every update() the entity will move along this vector and return
|
||||||
-- collision data to the subclass
|
-- collision data to the subclass
|
||||||
self.vector = geom.vector2D.new(0, 0)
|
self.vector = geom.vector2D.new(0, 0)
|
||||||
|
@ -32,15 +36,15 @@ function Entity:init(img, health, armor)
|
||||||
local states = {
|
local states = {
|
||||||
["INIT"] = {
|
["INIT"] = {
|
||||||
main=self.runInit,
|
main=self.runInit,
|
||||||
transition=self.onInit
|
incoming=self.onInit
|
||||||
},
|
},
|
||||||
["INTRO"] = {
|
["INTRO"] = {
|
||||||
main=self.runIntro,
|
main=self.runIntro,
|
||||||
transition=self.onIntro,
|
incoming=self.onIntro,
|
||||||
},
|
},
|
||||||
["READY"] = {
|
["READY"] = {
|
||||||
main=self.runReady,
|
main=self.runReady,
|
||||||
transition=self.onReady,
|
incoming=self.onReady,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
self.fsm = StateMachine.new({self}, states)
|
self.fsm = StateMachine.new({self}, states)
|
||||||
|
@ -68,6 +72,26 @@ end
|
||||||
function Entity:update()
|
function Entity:update()
|
||||||
-- update state machine
|
-- update state machine
|
||||||
self.fsm:execute()
|
self.fsm:execute()
|
||||||
|
|
||||||
|
if self.animationTimer then
|
||||||
|
local targetIndex = math.floor(self.animationTimer.value)
|
||||||
|
if self.animationIndex ~= targetIndex then
|
||||||
|
self:setImage(self.animationTable:getImage(targetIndex))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- animate the entity based on the passed in imageTable. If reverse is true, play the
|
||||||
|
-- animation backwards. duration is how long the animation should be in total
|
||||||
|
function Entity:animate(imgTable, duration, reverse)
|
||||||
|
self.animationTable = imgTable
|
||||||
|
local startValue = 1
|
||||||
|
local endValue = #imgTable
|
||||||
|
if reverse then
|
||||||
|
startValue = #imgTable
|
||||||
|
endValue = 1
|
||||||
|
end
|
||||||
|
self.animationTimer = playdate.timer.new(duration, startValue, endValue)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- State machine-controlled functions
|
-- State machine-controlled functions
|
||||||
|
|
79
src/kani.lua
79
src/kani.lua
|
@ -69,25 +69,7 @@ function Kani:init(ui)
|
||||||
-- the UI gets passed in to Kani so that we can update pieces of it easily.
|
-- the UI gets passed in to Kani so that we can update pieces of it easily.
|
||||||
self.ui = ui
|
self.ui = ui
|
||||||
|
|
||||||
self.inputHandlers = {
|
self.fsm:addState("DEFEND", self.runDefend, self.onDefend, self.onDefendExit)
|
||||||
upButtonDown = function() self.vector.dy = -3 end,
|
|
||||||
downButtonDown = function() self.vector.dy = 3 end,
|
|
||||||
leftButtonDown = function() self.vector.dx = -3 end,
|
|
||||||
rightButtonDown = function() self.vector.dx = 3 end,
|
|
||||||
upButtonUp = function() self.vector.dy = 0 end,
|
|
||||||
downButtonUp = function() self.vector.dy = 0 end,
|
|
||||||
leftButtonUp = function() self.vector.dx = 0 end,
|
|
||||||
rightButtonUp = function() self.vector.dx = 0 end,
|
|
||||||
cranked = function(change, accelChange) self:chargeReserve(change) end,
|
|
||||||
AButtonDown = function()
|
|
||||||
self.firingTimer = playdate.timer.keyRepeatTimerWithDelay(self.weaponChargeSpeed / 2,
|
|
||||||
self.weaponChargeSpeed,
|
|
||||||
self.chargeShot, self)
|
|
||||||
end,
|
|
||||||
AButtonUp = function() self:fire() end,
|
|
||||||
}
|
|
||||||
|
|
||||||
self.fsm:changeState("READY")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Kani:chargeReserve(change)
|
function Kani:chargeReserve(change)
|
||||||
|
@ -138,24 +120,65 @@ end
|
||||||
function Kani:damage(amount)
|
function Kani:damage(amount)
|
||||||
Kani.super.damage(self, amount)
|
Kani.super.damage(self, amount)
|
||||||
self.ui.healthMeter:setValue(self.health)
|
self.ui.healthMeter:setValue(self.health)
|
||||||
|
print("Kani health now at " .. self.health) -- debug
|
||||||
if self.health == 0 then
|
if self.health == 0 then
|
||||||
-- TODO: end game here
|
-- TODO: end game here
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Kani:addInputHandlers()
|
|
||||||
playdate.inputHandlers.push(self.inputHandlers)
|
|
||||||
end
|
|
||||||
|
|
||||||
function Kani:removeInputHandlers()
|
|
||||||
playdate.inputHandlers.pop()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- move that crab!
|
-- move that crab!
|
||||||
function Kani:runReady()
|
function Kani:runReady()
|
||||||
|
-- input handling
|
||||||
|
if playdate.buttonIsPressed(playdate.kButtonDown) then
|
||||||
|
self.vector.dy = 3
|
||||||
|
elseif playdate.buttonIsPressed(playdate.kButtonUp) then
|
||||||
|
self.vector.dy = -3
|
||||||
|
else
|
||||||
|
self.vector.dy = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
if playdate.buttonIsPressed(playdate.kButtonLeft) then
|
||||||
|
self.vector.dx = -3
|
||||||
|
elseif playdate.buttonIsPressed(playdate.kButtonRight) then
|
||||||
|
self.vector.dx = 3
|
||||||
|
else
|
||||||
|
self.vector.dx = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
local change = select(1, playdate.getCrankChange())
|
||||||
|
self:chargeReserve(change)
|
||||||
|
|
||||||
|
if playdate.buttonJustPressed(playdate.kButtonA) then
|
||||||
|
self.firingTimer = playdate.timer.keyRepeatTimerWithDelay(self.weaponChargeSpeed / 2,
|
||||||
|
self.weaponChargeSpeed,
|
||||||
|
self.chargeShot, self)
|
||||||
|
end
|
||||||
|
if playdate.buttonJustReleased(playdate.kButtonA) then
|
||||||
|
self:fire()
|
||||||
|
end
|
||||||
|
|
||||||
|
if playdate.buttonIsPressed(playdate.kButtonB) then
|
||||||
|
print("Triggering entrance to DEFEND mode")
|
||||||
|
self.fsm:changeState("DEFEND")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- collision handling
|
||||||
local collisions = Kani.super.runReady(self)
|
local collisions = Kani.super.runReady(self)
|
||||||
for i=0, #collisions, 1 do
|
for i=0, #collisions, 1 do
|
||||||
-- TODO: handle player-triggered collisions
|
-- TODO: handle player-triggered collisions
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Kani:onDefend()
|
||||||
|
self.armor = 5
|
||||||
|
end
|
||||||
|
|
||||||
|
function Kani:onDefendExit()
|
||||||
|
self.armor = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function Kani:runDefend()
|
||||||
|
if not playdate.buttonIsPressed(playdate.kButtonB) then
|
||||||
|
self.fsm:changeState("READY")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -23,7 +23,6 @@ function setup()
|
||||||
ui = UI()
|
ui = UI()
|
||||||
player = Kani(ui)
|
player = Kani(ui)
|
||||||
player:moveTo(16, 120)
|
player:moveTo(16, 120)
|
||||||
player:addInputHandlers()
|
|
||||||
player:add()
|
player:add()
|
||||||
ui:add()
|
ui:add()
|
||||||
currentWave = newWave()
|
currentWave = newWave()
|
||||||
|
@ -31,13 +30,6 @@ function setup()
|
||||||
|
|
||||||
makeWalls()
|
makeWalls()
|
||||||
drawBackground()
|
drawBackground()
|
||||||
|
|
||||||
-- debug, TODO remove this code
|
|
||||||
playdate.inputHandlers.push({
|
|
||||||
BButtonUp = function()
|
|
||||||
print(gfx.sprite.spriteCount())
|
|
||||||
end
|
|
||||||
})
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function makeWalls()
|
function makeWalls()
|
||||||
|
|
|
@ -10,24 +10,26 @@ end
|
||||||
|
|
||||||
-- params is a table of parameters to always pass to the functions
|
-- params is a table of parameters to always pass to the functions
|
||||||
-- stateTable is a table of initial states. Entries should be of the form:
|
-- stateTable is a table of initial states. Entries should be of the form:
|
||||||
-- name = {main=mainFunc, transition=transFunc}
|
-- name = {main=mainFunc, incoming=inFunc, outgoing=outFunc}
|
||||||
-- where mainFunc and transFunc are functions that should be executed in relation to the state.
|
-- where mainFunc and transFunc are functions that should be executed in relation to the state.
|
||||||
-- the State Machine will call mainFunc on execute()
|
-- the State Machine will call mainFunc on execute()
|
||||||
-- the State Machine will call transFunc when the state is entered
|
-- the State Machine will call inFunc when the state is entered
|
||||||
|
-- the State Machine will call outFunc when the state in exited
|
||||||
function StateMachine:init(params, stateTable)
|
function StateMachine:init(params, stateTable)
|
||||||
self.currentState = nil
|
self.currentState = nil
|
||||||
self.parameters = params or {}
|
self.parameters = params or {}
|
||||||
self.states = stateTable or {}
|
self.states = stateTable or {}
|
||||||
end
|
end
|
||||||
|
|
||||||
function StateMachine:addState(name, mainFunc, transFunc)
|
function StateMachine:addState(name, mainFunc, inFunc, outFunc)
|
||||||
self.states[name] = {main=mainFunc, transition=transFunc}
|
self.states[name] = {main=mainFunc, incoming=inFunc, outgoing=outFunc}
|
||||||
end
|
end
|
||||||
|
|
||||||
-- execute the main function for the current state.
|
-- execute the main function for the current state.
|
||||||
-- returns true if the function was executed, false otherwise
|
-- returns true if the function was executed, false otherwise
|
||||||
function StateMachine:execute()
|
function StateMachine:execute()
|
||||||
if self.currentState == nil or not self.states[self.currentState] then
|
if self.currentState == nil or not self.states[self.currentState]
|
||||||
|
or not self.states[self.currentState].main then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -37,11 +39,22 @@ end
|
||||||
|
|
||||||
-- change to the specified state. returns true if the state change is successful
|
-- change to the specified state. returns true if the state change is successful
|
||||||
function StateMachine:changeState(state)
|
function StateMachine:changeState(state)
|
||||||
if not self.states[state] then return false end
|
if not self.states[state] then
|
||||||
|
print("WARN (StateMachine): tried to enter nonexistent state " .. state)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- run the exit function for the previous state
|
||||||
|
if self.currentState and self.states[self.currentState].outgoing then
|
||||||
|
self.states[self.currentState].outgoing(table.unpack(self.parameters))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- change state
|
||||||
self.currentState = state
|
self.currentState = state
|
||||||
if self.states[state].transition then
|
|
||||||
self.states[state].transition(table.unpack(self.parameters))
|
-- run the entrance function for the new state
|
||||||
|
if self.states[state].incoming then
|
||||||
|
self.states[state].incoming(table.unpack(self.parameters))
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue
Block a user