当前位置:网站首页>FSM finite state machine
FSM finite state machine
2022-04-23 07:44:00 【0zien0】
When you want to make a function, you need to go through different situations ( Conditions ), When dealing with problems in different ways , In general , Will write a lot if-else Code to judge , This way of writing is confusing when switching between states or adding new states . And if you use a state machine , The functions of each state are relatively independent and clear . 23 A state pattern in a design pattern , Is a better way to realize the function of finite state machine .
When I was a child, I played a very simple game console , It's called “ Electronic pets ”.
Seeing these classic pictures, I don't know if they remind everyone of them . This is the main character of today , I'm going to use the state machine to implement a “ chicken ” The little game .
Numerical design of the game , As follows :
Next on the game code ! The code is pure lua Written .
State base class :
-- State base class
local P = class("FSMState")
FSMState = P
-- Constructors
function P:ctor(owner)
self._owner = owner
self._isPause = false
self._name = "FSMState"
end
-- Pause the state machine
function P:pause()
self._isPause = true
end
-- Continue state machine
function P:resume()
self._isPause = false
end
-- State description
function P:info()
end
-- Set whether the current state is allowed to be switched
function P:condition()
return true
end
-- Timer
function P:update()
end
function P:clear()
self._owner = nil
end
State subclass 1【 Chicken... Eat 】:
-- State base class
local P = class("StateEat", FSMState)
-- Constructors
function P:ctor(owner)
self._owner = owner
self._name = "StateEat"
end
function P:info()
return " The chicken went to dinner "
end
function P:update(dt)
if not self._isPause then
self._owner.satiety = self._owner.satiety + math.random(30, 50)
self._owner.energy = self._owner.energy - math.random(10, 20)
self._owner.clean = self._owner.clean - math.random(5, 10)
self._owner.time = self._owner.time + 1
end
end
return P
State subclass 2【 The chick sleeps 】:
-- State base class
local P = class("StateSleep", FSMState)
-- Constructors
function P:ctor(owner)
self._owner = owner
self._name = "StateSleep"
end
function P:info()
return " The chicken went to bed "
end
function P:update(dt)
if not self._isPause then
self._owner.satiety = self._owner.satiety - math.random(20, 30)
self._owner.energy = self._owner.energy + math.random(50, 80)
self._owner.time = self._owner.time + math.random(8, 10)
self._owner.happy = 70
end
end
return P
The chick sleeps 、 having dinner 、 Take a shower 、 In a daze 、 play ,5 States , Not one by one ……
Next is the more important machine The class
-- State base class
local P = class("FSMMachine")
FSMMachine = P
P.IDLE = function(owner) return require("StateIdle"):create(owner) end
P.EAT = function(owner) return require("StateEat"):create(owner) end
P.PLAY = function(owner) return require("StatePlay"):create(owner) end
P.SLEEP = function(owner) return require("StateSleep"):create(owner) end
P.CLEAN = function(owner) return require("StateClean"):create(owner) end
-- Constructors
function P:ctor()
self._scheduleId = nil -- Timer ID
self._interval = 0.03 -- The time interval of the timer
self._state = nil -- state
self._preState = nil -- Last state [ Save the last state , Achieve freedom “ Restore the previous state ” The function of ]
end
-- Start state machine
function P:start(owner)
self._owner = owner
self._state = require("StateIdle"):create(owner)
-- This class maintains a timer for the entire state machine ( Use here while Loop to force the timer ……, adopt os.clock() To achieve sleep function , Although it will occupy CPU, But it's just a hand training game , Use it like this first )
-- If the chick's satiety is 0, Starve to death , At the end of the game, jump out of the loop
local index = 1
while owner.satiety > 0 do
self:update(index)
index = index + 1
end
print(" The chick died , At the age of " .. math.floor(self._owner.time / 24) .. " God " .. self._owner.time % 24 .. " Hours ")
-- self._scheduleId = display.scheduleScriptFunc(function (dt)
-- self:update(dt)
-- end, 5, false)
end
-- Pause the state machine
function P:pause()
if self._state then
self._state:pause()
end
end
-- Continue state machine
function P:resume()
if self._state then
self._state:resume()
end
end
-- Timer
function P:update(dt)
-- print("zien ", dt)
-- Call the current state of update Function to execute the timer of the current state
if self._state then
self._state:update()
self:checkState()
end
self:sleep1(self._interval)
end
-- Check whether the status needs to be changed
function P:checkState()
if self._owner.satiety < 20 then -- Very hungry
self:changeState(FSMMachine.EAT)
elseif self._owner.energy < 20 then -- Very tired
self:changeState(FSMMachine.SLEEP)
elseif self._owner.happy < 20 then -- Very unhappy
self:changeState(FSMMachine.PLAY)
elseif self._owner.clean < 20 then -- Very dirty
self:changeState(FSMMachine.CLEAN)
elseif self._owner.satiety < 40 then -- hungry
self:changeState(FSMMachine.EAT)
elseif self._owner.energy < 40 then -- Tired out
self:changeState(FSMMachine.SLEEP)
elseif self._owner.happy < 40 then -- unhappy
self:changeState(FSMMachine.PLAY)
elseif self._owner.clean < 40 then -- dirty
self:changeState(FSMMachine.CLEAN)
else -- If everything is normal, you will be in a daze
self:changeState(FSMMachine.IDLE)
end
self:showInfo()
end
-- Output chick status information
function P:showInfo()
local str = " Chicken age :" .. math.floor(self._owner.time / 24) .. " God " .. self._owner.time % 24 .. " Hours "
str = str .. " Satiety :" .. self._owner.satiety
str = str .. " Joy :" .. self._owner.happy
str = str .. " Energy level :" .. self._owner.energy
str = str .. " Cleanliness :" .. self._owner.clean
str = str .. " " .. self._state:info()
print(str)
end
-- State change
function P:changeState(state)
if self._state and self._state:condition() then
local newState = state(self._owner)
if newState then
-- Clear the previous status
if self._preState then
self._preState:clear()
end
self._preState = self._state
self._state = newState
end
end
end
-- Return to the previous status
function P:revert()
if self._preState and self._state then
local tmpState = self._preState
self._preState = self._state
self._state = tmpState
end
end
function P:sleep(n)
if n > 0 then
os.execute("ping -n " .. tonumber(n + 1) .. " localhost > NUL")
end
end
function P:sleep1(n)
local t = os.clock()
while os.clock() < t + n do
end
end
return P
Simply analyze this machine Some functions of :
It's a status table , By using the status of this table , To switch the state of the chicken .
After starting the state machine ,machine Class will maintain a timer , The timer will execute 【 Current effective status 】 Corresponding update function . adopt machine Class to drive the operation of the current state .
Switch between different states according to different conditions . After reaching the conditions , Use the values of the condition table submitted above , You can switch states .
The state pattern is roughly such a sub structure , One machine class , One state Base class , Plus N There are two different functions state Subclasses constitute a general state pattern . Here is a simple entry function .
require "tools.init"
require "init"
math.randomseed(tostring(os.time()):reverse():sub(1, 7)) -- Set random seeds
function main()
local chick = {satiety = 100, happy = 100, energy = 100, clean = 100, time = 0}
local fsm = FSMMachine:new()
fsm:start(chick)
end
main()
The chicken's properties are just the initial settings , Then start the state machine , You can see the chick's life !
The operation effect is roughly as follows :
Boring me , Tried to raise 10 Second chicken , result
Only 3 Just barely raised , I really have a talent for raising chickens =.=!
By the way , This chicken game , It's too simple , There will be more and more complex situations in real projects , Such as :
1. In the state base class, I preset the function of pausing the state machine ;
2. stay machine Class, I preset the function of returning the state of the last execution ;
3. In this game , It is necessary to execute one state before entering the next state , In fact, it is possible that a state is still in the process of implementation , There will be a need to change the State , Specifically, interrupt the current state and directly enter the next state , Or record the next status , Wait for the execution of the current state to end before entering the next state , These all need specific analysis of specific problems .
4. This state machine is also a fully automatic state machine , And all subclass state switching conditions are consistent , So the state switching section is also very simple , Practical application , Probably because of some external changes, the state machine needs to switch states , And each subclass may have its own different state switching conditions .
Simply speaking , It's just a little practice demo, Just for fun ~
The source code is here :
版权声明
本文为[0zien0]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204230623293135.html
边栏推荐
- SAP Excel 已完成文件级验证和修复。此工作簿的某些部分可能已被修复或丢弃。
- Educational Codeforces Round 81 (Rated for Div. 2)
- js之什么是事件?事件三要素以及操作元素
- 10.更新操作
- NPM installation stepping pit
- SAP PI / Po rfc2restful Publishing RFC interface as restful examples (proxy indirect)
- 二叉树的深度
- [hdu6868]Absolute Math(推式子+莫比乌斯反演)
- 对STL容器的理解
- Reflect on the limitations of event bus and the design and implementation of communication mechanism in component development process
猜你喜欢
Authorization+Token+JWT
Design optimization of MySQL database
SAP TRANSLATE使用数据对象掩码示例
SAP 导出Excel文件打开显示:“xxx“的文件格式和扩展名不匹配。文件可能已损坏或不安全。除非您信任其来源,否则请勿打开。是否仍要打开它?
自定义时间格式(YYYY-MM-DD HH:mm:ss 星期X)
超级宝典&编程指南(红蓝宝书)-读书笔记
页面动态显示时间(升级版)
Super classic & Programming Guide (red and blue book) - Reading Notes
Reflection on the systematic design of Android audio and video caching mechanism
js之节点操作,为什么要学习节点操作
随机推荐
SAP pi / PO rfc2soap publishes RFC interface as WS example
What are the total number of all courses of Mr. Tang Xiaoyang, who is very popular in CSDN (question mark)
Mobile game performance optimization
Moment.js中format方法函数的格式
On BFC (block formatting context)
The difference and application of VR, AR and MR, as well as some implementation principles of AR technology
Mvcc (multi version concurrency control)
js之DOM事件
SAP PI/PO rfc2RESTful 发布rfc接口为RESTful示例(Proxy间接法)
js之函数的两种声明方式
2022.3.14 Ali written examination
CSDN很火的汤小洋老师全部课程总共有哪些(问号问号问号)
SAP 03-AMDP CDS Table Function using ‘WITH‘ Clause(Join子查询内容)
npm 安装踩坑
Design optimization of MySQL database
Common DOS commands
ABAP 实现发布RESTful服务供外部调用示例
2.限定查询
ABAP 从CDS VIEW 发布OData Service示例
keytool: command not found