State pattern

What could be a good way to implement State pattern in Defold?

Do you mean State Pattern as it is described on Wikipedia, or are you referring to something else? There’s a discussion of Finite State Machine on the Lua user wiki, maybe you can use that as an inspiration? There are also a number of Lua projects on GitHub that implements FSMs: https://github.com/kyleconroy/lua-state-machine and https://github.com/cornelisse/LuaFSM.

If you provide some additional information about what it is you wish to do then it becomes easier for us to give you Defold specific help. Remember that Lua uses Defold so anything that can be created using Lua should be immediately useable in Defold. With that said, some Lua libraries and modules rely heavily on OOP constructs and those libs might not be suitable for use in Defold where loose coupling between components is preferred.

3 Likes

Yes, I was referring to the State Pattern as it is described on Wikipedia.
In my simple app I have some actions that can’t be performed until some events have occured, for example waiting for an animation of a sprite to finish before performing some action on that sprite (or on some other objects).
At the moment I have a few boolean variables representing the current state, and everything works, but before things get more complicated and messy I would like to handle this in a more elegant, “best practice” way.
Obviously this is more a Lua related question than Defold specific, I was just curious to know how Defold users implement this design pattern, or, if they don’t, how they handle such cases.
Thanks for support, the implementation on lua wiki seems promising.

Well, here’s my two cents:

Usually when I have some stateful operation, or a sequence of dependent events that must be performed, etc, I tend to implement a solution using coroutines rather than an explicit state machine. Coroutines are a bit like an implicit state machine, in the sense that the state is persisted for you both by the variables on the stack of the coroutine thread, and the progress of the coroutine thread itself.

For my purposes, I wrote some lightweight wrappers around the coroutine apis, allowing the coroutine to yield until a certain defold message is received, and then continue execution.

This allows you to write straight-line code that is usually far easier to understand than any state machine implementation I’ve ever seen…

2 Likes

Thanks ericsroy, I’m new to Lua and I had never heard about coroutines. I had just read about them in Defold manual and I think they will be handy in many cases.

Yes, they can be very elegant. The key is just to find a way to let them interface with the defold messaging system.

1 Like

What about the global state of the game? Like how many enemies remain? Do you use a global table?

Yes, something like that I would probably store in a table inside a shared lua module that can be imported by any of the game object scripts.

Good suggestion! I use coroutines quite frequently to untangle nested asynchronous code and it works like a charm. I have a module that wraps up a lot of this. It will allow you to wait until a certain number of seconds or frames have elapsed, until a collection has been loaded/unloaded, until a callback is invoked (http.request for instance), until a message is received etc. It’s here if you want to take a look: ludobits/ludobits/m/flow.lua at master · britzl/ludobits · GitHub and an example: ludobits/examples/flow/flow.script at master · britzl/ludobits · GitHub

2 Likes

Do you have this available somewhere so that I can take a look? I’m curious to see how you solved it.

1 Like

Very cool britzl, your flow library looks great, very featureful. Mine is basically just an incomplete rip-off of a couple of the patterns from redux-saga (a Node thing).

Here’s the saga module:

Here’s an example of how you might use it to switch scenes by dynamically unloading/loading collection proxies:

And here’s a barebones example of how you can write sagas that never end:

1 Like

Very interesting, I think I will use your module!

1 Like

Thank you for sharing! I like the fact that it is simple and message focused.

Yes, I was just solving the problems that I encountered, as I encountered them. I can totally see the use case for, eg, yielding for a certain number of seconds (like you provide in flow).

However, I would like to continue to avoid using the update() method as much as possible. I wonder if there’s some way of implementing a delay yielder with messages only? Perhaps I would have to rely on animating a property and getting the completion callback or something like that. That would be a bit of a hack though. Can you think of another way?

I agree that the update() function isn’t optimal. I’d like to get rid of it as well…

I think animating a property is the best way to go for now if you don’t want to call update(). You can have a dummy game object with a go.property() and animate that.

1 Like