Object State Tracking part trois

So based on all the great feedback I have implemented 2 types of states.   non-exclusive and exclusive.   All the non-exclusive states can happen at the same time or not at all it doesn’t matter.   For the exclusive states I am starting with these: 

Normal

Super - can eat anything

Crazy - acts erratically 

Ghost - others can not see him 

Sick  -  slow and weak 

Frozen  -  Everything on the screen is frozen but him.  

there is also dead, spawning etc… 

So my state diagram looks like this: 

So as I move around I notice that if I am super and eat something that should make me super again it does nothing because I only transition from the normal state.  Same goes for sick.   If he is sick and manages to eat something that should make him super I would like that to happen.   So in my simple example I realize what I really want is something like this: 

I believe I can handle all this with if statements but suggestions are welcome.  

L

  

Maybe I missed something, some important piece of the puzzle… but in the nicest possible way, Laura, what are you talking about?

if you’re going this route, ie a formal “transition table”, it usually has a form similar to:  oldstate, condition, newstate

(though you can mix that up however you like, fe as a 2d “array” of oldstate “rows” versus newstate “columns”, the cell value containing the transitioning event.  doesn’t matter, same difference - it’s mainly about how you’d be *accessing* it, then there might be an opportunity to improve performance with one design over another)

then, essentially, you scan that table, and IFF you match a given state and also match a given event (aka an “input condition”, aka a “trigger”, etc) THEN you transition to specified new state.

your particular problem could be solved by having “self-resetting” states in that table, like:  “Super”, “eatSuperFruit”, “Super”

so, let’s say your transition table is a 2d array, with oldstate as the first index, event as the second index, and newstate as the cell value, then

local newstate = transitions[entity.state][event] -- easy peasy lookup if (newstate) then -- will be non-nil if that combo actually found in transition table changeState(entity,newstate) end

@laura,
 
For future readers (and @adrianm :) ) , you should link this to your other thread by listing them:

sorry for the confusion and thanks for helping. 

OK, thanks again for the ideas.  I went from this mess of IF STMTS and it was just getting started. 

if hs.state == "normal" then -- can only change in states from normal if obj.mytype == "crazy" then -- yellow hs.state = "crazy" elseif obj.mytype == "sick" then -- green hs.state = "sick" elseif obj.mytype == "super" then -- blue hs.state = "super" elseif obj.mytype == "frozen" then -- white hs.state = "frozen" elseif obj.mytype == "ghost" then -- ghosty hs.state = "ghost" end elseif hs.state == "super" then -- can go from super to super again. if obj.mytype == "super" then -- blue -- delete old stuff. self:endsuper(); hs.state = "super" end end 

To this:  

hs.statetransitions = { normal = { crazy = {"crazy" , nil } , -- new state and function to run. sick = {"sick" , nil } , -- new state and function to run. super = {"super" , nil } , -- new state and function to run. frozen = {"frozen" , nil } , -- new state and function to run. ghost = {"ghost" , nil } -- new state and function to run. } , super = { crazy = { nil , nil } , -- new state and function to run. sick = { nil , nil } , -- new state and function to run. super = {"super" , HF.endsuper } , -- new state and function to run. frozen = { nil , nil } , -- new state and function to run. ghost = { nil , nil } -- new state and function to run. } }

local newstate = hs.statetransitions[hs.state][obj.mytype][1] local newstatefn = hs.statetransitions[hs.state][obj.mytype][2] if (newstate) then if (newstatefn) then newstatefn(self) end -- clean up old state and get ready for new state. hs.state = newstate -- switch to new state end 

I can add new states and transitions by just adding to the table.  Much better.  If you look at the 2 entries so far in the table hero can go from normal state to any of the other states.   But once in super state he can only go back to the super state and will run cleanup routine endsuper to reset things and get ready to start that state again.   

Now I just need to add the rest of the states to the table to fully implement the table described above. 

If this keeps up I might even have a game ready by 2019. :slight_smile:

  cool, it’s nice to see someone grok a general forum answer and make it specific for their needs.  :)

  just one last hint (tho you may not want/need it)…

  you already figured out on your own that the “newstate” looked up need not be just a simple string, and you’ve put a leave-state handling function in there too.  well, why not take a full “state object” (see your part deax post for the thing with the enter/update/leave methods, fe) and put THAT in the transition lookup table!

  ie, you probably don’t really NEED two separate tables (one for states, one for transitions) as your transition table can also hold the states themselves.  now it’s starting to look like a real FSM!  it’s just organizational though, so entirely optional, fine to just keep doing it as however “fits” your project. :slight_smile:

Ya,  I like to put the actual answer in these forums for the people who follow.  I hate when I have a problem and the forum almost answers my question and I still have to figure stuff out.  Call me a hater :0  

As for one big state machine,  sounds cool.  I will have to think on it.   The original reason I separated it was because the state transition happens in the collision listener and you can only set flags in there.   Then I do the real heavy lifting in the game loop.  

Thanks again for all the help.  I have sat here in my attic learning this stuff for years now.  It is tough when they only person you have to talk to is yourself and the trusty dog.   I don’t get many answers out of him. 

Kudos Laura.  I am very happy when I see folks who ask questions and resolve the question, also take the time to post the resolution.

That is the definition of awesome to me.  

This has been a great series of threads!

Maybe I missed something, some important piece of the puzzle… but in the nicest possible way, Laura, what are you talking about?

if you’re going this route, ie a formal “transition table”, it usually has a form similar to:  oldstate, condition, newstate

(though you can mix that up however you like, fe as a 2d “array” of oldstate “rows” versus newstate “columns”, the cell value containing the transitioning event.  doesn’t matter, same difference - it’s mainly about how you’d be *accessing* it, then there might be an opportunity to improve performance with one design over another)

then, essentially, you scan that table, and IFF you match a given state and also match a given event (aka an “input condition”, aka a “trigger”, etc) THEN you transition to specified new state.

your particular problem could be solved by having “self-resetting” states in that table, like:  “Super”, “eatSuperFruit”, “Super”

so, let’s say your transition table is a 2d array, with oldstate as the first index, event as the second index, and newstate as the cell value, then

local newstate = transitions[entity.state][event] -- easy peasy lookup if (newstate) then -- will be non-nil if that combo actually found in transition table changeState(entity,newstate) end

@laura,
 
For future readers (and @adrianm :) ) , you should link this to your other thread by listing them:

sorry for the confusion and thanks for helping. 

OK, thanks again for the ideas.  I went from this mess of IF STMTS and it was just getting started. 

if hs.state == "normal" then -- can only change in states from normal if obj.mytype == "crazy" then -- yellow hs.state = "crazy" elseif obj.mytype == "sick" then -- green hs.state = "sick" elseif obj.mytype == "super" then -- blue hs.state = "super" elseif obj.mytype == "frozen" then -- white hs.state = "frozen" elseif obj.mytype == "ghost" then -- ghosty hs.state = "ghost" end elseif hs.state == "super" then -- can go from super to super again. if obj.mytype == "super" then -- blue -- delete old stuff. self:endsuper(); hs.state = "super" end end 

To this:  

hs.statetransitions = { normal = { crazy = {"crazy" , nil } , -- new state and function to run. sick = {"sick" , nil } , -- new state and function to run. super = {"super" , nil } , -- new state and function to run. frozen = {"frozen" , nil } , -- new state and function to run. ghost = {"ghost" , nil } -- new state and function to run. } , super = { crazy = { nil , nil } , -- new state and function to run. sick = { nil , nil } , -- new state and function to run. super = {"super" , HF.endsuper } , -- new state and function to run. frozen = { nil , nil } , -- new state and function to run. ghost = { nil , nil } -- new state and function to run. } }

local newstate = hs.statetransitions[hs.state][obj.mytype][1] local newstatefn = hs.statetransitions[hs.state][obj.mytype][2] if (newstate) then if (newstatefn) then newstatefn(self) end -- clean up old state and get ready for new state. hs.state = newstate -- switch to new state end 

I can add new states and transitions by just adding to the table.  Much better.  If you look at the 2 entries so far in the table hero can go from normal state to any of the other states.   But once in super state he can only go back to the super state and will run cleanup routine endsuper to reset things and get ready to start that state again.   

Now I just need to add the rest of the states to the table to fully implement the table described above. 

If this keeps up I might even have a game ready by 2019. :slight_smile:

  cool, it’s nice to see someone grok a general forum answer and make it specific for their needs.  :)

  just one last hint (tho you may not want/need it)…

  you already figured out on your own that the “newstate” looked up need not be just a simple string, and you’ve put a leave-state handling function in there too.  well, why not take a full “state object” (see your part deax post for the thing with the enter/update/leave methods, fe) and put THAT in the transition lookup table!

  ie, you probably don’t really NEED two separate tables (one for states, one for transitions) as your transition table can also hold the states themselves.  now it’s starting to look like a real FSM!  it’s just organizational though, so entirely optional, fine to just keep doing it as however “fits” your project. :slight_smile:

Ya,  I like to put the actual answer in these forums for the people who follow.  I hate when I have a problem and the forum almost answers my question and I still have to figure stuff out.  Call me a hater :0  

As for one big state machine,  sounds cool.  I will have to think on it.   The original reason I separated it was because the state transition happens in the collision listener and you can only set flags in there.   Then I do the real heavy lifting in the game loop.  

Thanks again for all the help.  I have sat here in my attic learning this stuff for years now.  It is tough when they only person you have to talk to is yourself and the trusty dog.   I don’t get many answers out of him. 

Kudos Laura.  I am very happy when I see folks who ask questions and resolve the question, also take the time to post the resolution.

That is the definition of awesome to me.  

This has been a great series of threads!