From 75145f14851f73a6964db3ee6d5720b2cc437398 Mon Sep 17 00:00:00 2001 From: Kazhnuz Date: Thu, 26 May 2022 13:12:08 +0200 Subject: [PATCH] feat: add a finite state machine to actors --- .../birb/classes/states/init.lua | 102 ++++++++++++++++++ .../birb/modules/world/actors/actor2D.lua | 5 + .../birb/modules/world/actors/actor3D.lua | 5 + .../birb/modules/world/actors/mixins/base.lua | 1 + 4 files changed, 113 insertions(+) create mode 100644 sonic-radiance.love/birb/classes/states/init.lua diff --git a/sonic-radiance.love/birb/classes/states/init.lua b/sonic-radiance.love/birb/classes/states/init.lua new file mode 100644 index 0000000..e370413 --- /dev/null +++ b/sonic-radiance.love/birb/classes/states/init.lua @@ -0,0 +1,102 @@ +-- classes/states :: a finite state machine for objects + +--[[ + Copyright © 2022 Kazhnuz + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + +local StateMachine = Object:extend() + +function StateMachine.addState(self, name, state, isDefault) + if (self.states == nil) then + self.states = {} + self.states.list = {} + end + + self.states.list[name] = state + + if (isDefault == true) then + self.states.default = name + end +end + +function StateMachine.addStates(self, statesPath, default) + local states = require(statesPath) + for i, stateName in ipairs(states) do + local state = require(statesPath .. "." .. stateName) + self:addState(stateName, state) + end + self.states.default = default +end + +function StateMachine:initStates() + if (self.states == nil) then + self.states = {} + self.states.list = {} + end + self.currentState = self.states.default or "none" +end + +function StateMachine:updateState(dt) + self:playStateFunc("update", dt) +end + +function StateMachine:haveState(state) + return (self.states.list[state] ~= nil) +end + +function StateMachine:setState(state) + if (not self:haveState(state)) then + return self.currentState + end + self:playStateFunc("stop", state) + local currentState = self.currentState + self.currentState = state + self:playStateFunc("start", currentState) + return state +end + +function StateMachine:getState() + return self.states.list[self.currentState] +end + +function StateMachine:getStateVar(varName, default) + local state = self:getState() + if (state == nil) then + return nil + end + local var = state[varName] + if (var == nil) then + return default + end + return var +end + +function StateMachine:playStateFunc(funcName, ...) + local state = self:getState() + if (state == nil) then + return + end + local func = state[funcName] + if (func ~= nil) then + func(self, ...) + end +end + +return StateMachine \ No newline at end of file diff --git a/sonic-radiance.love/birb/modules/world/actors/actor2D.lua b/sonic-radiance.love/birb/modules/world/actors/actor2D.lua index 90e4b0b..2897710 100644 --- a/sonic-radiance.love/birb/modules/world/actors/actor2D.lua +++ b/sonic-radiance.love/birb/modules/world/actors/actor2D.lua @@ -29,6 +29,8 @@ local TimedActor = require("birb.modules.world.actors.mixins.timers") local InputActor = require("birb.modules.world.actors.mixins.inputs") local PhysicalActor = require("birb.modules.world.actors.mixins.physics") +local StateMachine = require("birb.classes.states") + local Actor2D = Rect:extend() Actor2D:implement(BaseActor) Actor2D:implement(SpritedActor) @@ -36,6 +38,8 @@ Actor2D:implement(TimedActor) Actor2D:implement(InputActor) Actor2D:implement(PhysicalActor) +Actor2D:implement(StateMachine) + local Hitbox = require "birb.modules.world.actors.utils.hitbox2D" -- INIT FUNCTIONS @@ -49,6 +53,7 @@ function Actor2D:new(world, type, x, y, w, h, isSolid) self:initTimers() self:initSprite() self:initKeys() + self:initStates() end function Actor2D:destroy() diff --git a/sonic-radiance.love/birb/modules/world/actors/actor3D.lua b/sonic-radiance.love/birb/modules/world/actors/actor3D.lua index e99964c..3ce7534 100644 --- a/sonic-radiance.love/birb/modules/world/actors/actor3D.lua +++ b/sonic-radiance.love/birb/modules/world/actors/actor3D.lua @@ -33,6 +33,8 @@ local InputActor = require("birb.modules.world.actors.mixins.inputs") local PhysicalActor = require("birb.modules.world.actors.mixins.physics") local Shape3DActor = require("birb.modules.world.actors.mixins.shapes") +local StateMachine = require("birb.classes.states") + local Actor3D = BasicBox:extend() Actor3D:implement(BaseActor) Actor3D:implement(SpritedActor) @@ -41,6 +43,8 @@ Actor3D:implement(InputActor) Actor3D:implement(PhysicalActor) Actor3D:implement(Shape3DActor) +Actor3D:implement(StateMachine) + -- INIT FUNCTIONS -- Initialise the actor and its base functions @@ -52,6 +56,7 @@ function Actor3D:new(world, type, x, y, z, w, h, d, isSolid) self:initSprite() self:initKeys() self:initShape(Boxes, true) + self:initStates() end function Actor3D:destroy() diff --git a/sonic-radiance.love/birb/modules/world/actors/mixins/base.lua b/sonic-radiance.love/birb/modules/world/actors/mixins/base.lua index 0bfcee3..eb0f7df 100644 --- a/sonic-radiance.love/birb/modules/world/actors/mixins/base.lua +++ b/sonic-radiance.love/birb/modules/world/actors/mixins/base.lua @@ -88,6 +88,7 @@ end function BaseActor:update(dt) self:updateStart(dt) self:applyUpdateFunctions(dt) + self:updateState(dt) self:updateEnd(dt) end