Log In  

Hello, new friends! I discovered Pico-8 a few weeks ago and this is my first post in here!

I'm currently trying to create a framework to manage game state for some future creation, and am hoping to get some feedback on what I've put together so far. Any insight would be greatly appreciated; I'm a web developer and consider myself reasonably proficient in PHP/JS, but this is my first Pico-8 project/first video game/first time working with Lua/first time writing my own FSM ever, so I'm feeling very unsure of myself! I'm looking over it and asking myself questions like; have I over-complicated this? Does the game/level hierarchy make sense? Is it DRY enough? Is there a better way!? etc, etc!

The state hierarchy of the cart looks like this:

App
|_Title Menu State
|_Config Menu State
|_Game State
  |_Init
  |_Running
  | |_Level State
  |   |_Start
  |   |_Running
  |   |_End
  |_Over

So, the first state the app is in is the Title Menu state, where you can either start the game or enter the Config Menu (for picking levels to start on or some other arbitrary config). From either of those, you can enter the Game State. Once we're in the Game State, it initializes, then begins running through the Level States (which just run 3s timers for demo purposes). Each level gets a Start state for saying 'ready, go' or whatever, a Running state for actually playing the game, and an End state for congratulating the player for completing the level or something.

One thing I did which I noticed is different from some of the tutorials I've seen is that I'm calling _init() rather than game_init() or level_init() when I make any state change. I realize this isn't super efficient, but I think it makes sense because any time I make a state change at any level, the program has to flow through the entire FSM hierarchy, which might be easier to debug in the future maybe? Does that make sense, or am I just wasting CPU cycles?

I'm looking forward to learning more from everyone, and hopefully making something actually enjoyable some day! Thanks!!! :)

Cart is attached, and also on GitHub

Cart #dojotizoko-0 | 2020-05-24 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

P#77097 2020-05-24 03:12 ( Edited 2020-05-24 03:28)

2

There's nothing particularly wrong with what you have. You may find it's a bit overkill for most things, though. You're using a lot of extra tokens to manage state. Once you're doing something big, you may find you want that token space back. You're also relying on strings for state, and that might be trickier to track down if you're off by a letter. (Not actually a huge deal, but it is overhead that's not strictly necessary.)

Also, I'm not quite sure what you're gaining by not just doing something like calling title_init() when you want to switch to the title screen. I understand you're sending it back to a central function to make the switch, but you still end up with situations like it running title_update() in the "title" state, then switching state to "config", and having it run config_draw() before ever running a config_update(), because you switched state mid-game-loop.

I mean, the main thing is if it makes it easier for you to think with and manage your code. :D And if that's the case, then yes, it absolutely is a sensible way of managing state.

P#77101 2020-05-24 03:51
1

That framework looks pretty well thought-out and organized. If you're wanting to see if there's a simpler approach, though, here's a system I came up with that's very minimalistic. It just uses the lives variable as a state indicator, with negative lives taking you to the startscreen/menu, positive being in-game, and zero as game over, with the Z or X buttons used here to trigger state changes. For a regular game, you'd just put the various different update functions in the relevant section. Not saying it's proper structure or best practice or anything, I just like paring things back to the basics and building up from there.

웃=-1
function _update60()cls()p=btnp()

if 웃<0then
?"title screen",41,56
?"press ❎",49,72
if(p>8)웃=3

elseif 웃>0then
?'웃'..웃
if(p>8)웃-=1

else
?"game over",47,63
웃-=p
end end
P#77105 2020-05-24 04:33 ( Edited 2020-05-24 04:47)

Oh, wow, thanks @MBoffin! It took me a minute to grasp why config_draw() would be run before config_update() after switching states, but I get it now. So, I could address this by just calling *_update() at the end of *_init(), correct?
eg,

function config_init()
  _update = config_update
  _draw = config_draw
  config_update()
end

btw, that's twice you've helped me today! I started writing this yesterday and trashed it all after looking at your advanced states demo cart. Also, thank you for making your zine, which is what got me started to begin with a few weeks ago; I'm very grateful for all your contributions to education in Pico-8!

P#77106 2020-05-24 04:46 ( Edited 2020-05-24 04:46)

@JadeLombax, thank you for your feedback! I reached that point while I was writing the last few lines where I wasn't sure about any of it anymore, so that's very reassuring to hear. What is the ? syntax you're using? I haven't seen this before! And yes, thank you for the simpler approach. I tend to try to think of every conceivable possibility when I start writing an app, and I'm beginning to figure out that I'm going to have to fight that tendency every step of the way while developing for Pico-8! 😅

P#77107 2020-05-24 04:51
1

I think my main point about the order is that whether you run _init() or you run config_init() directly, either way will still end up with it finishing out the current game loop. In other words, that's pretty normal and not really something to worry about if you're planning for it, so I wasn't totally sure what was being gained by running _init() over config_init() directly. But also, just to clarify, that wasn't a criticism of your system! :) I think what you've created works well and does add more structure to the FSM.

I'm glad the demo cart and zine were useful. :) I'm definitely interested in what you end up creating! :)

P#77108 2020-05-24 05:03
1

@Ridgekuhn

Glad to help. I haven't done a lot of programming, and since learning about Tweetcarts I've found it interesting to pare back my code to the minimum, so my approach is sure to be different from that of a lot of people.

To answer your question, the "?" is just a shortcut for the print() function. It allows you to print in fewer characters, but with the caveat that you can't have anything else on that line of code. Curiously, this isn't just a Pico 8 peculiarity, it goes back to the days of BASIC, and the Commodore 64 had the same shortcut.

P#77109 2020-05-24 05:12 ( Edited 2020-05-24 05:13)

@MBoffin, Now that you mention it, I'm not sure what the point is, either! I initially wrote it that way bc it makes sense to my old-school web developer brain; like when you make a new request to index.php in WordPress or Drupal, it just runs the whole program again. I think I also did that out of fear of causing a recursion (like calling game_init(), changing game.state and then calling game_init() from inside itself), but I realize now that would be prevented by the conditionals on game.state at the start of game_init(). Anyway, heavy criticism is definitely welcome! I will for sure keep you posted whenever I get around to making a playable game, hopefully very soon!

P#77110 2020-05-24 05:16

@JadeLombax, thanks for the lesson, I had no idea! Since I'm still getting comfortable with Lua, I think I'll be keeping things as verbose as possible until I can't anymore, but I will for sure be using that shortcut in the future! :)

P#77111 2020-05-24 05:21
1

I thought about this a lot today and refactored it by replacing all the conditionals with a couple central functions inspired by @MBoffin's comment. I like this a lot better because the app doesn't have to check whether it's in a state or not, it either is or it isn't, which seems less error-prone. I saved a dozen tokens or so doing that, and then I burned up a couple dozen more with the new namespacing convention! 😂

I think I'm okay with it for now. It feels easily readable and versatile, and should be easy to strip down quite a bit when I need the extra tokens in an actual project, especially if I don't need the level fsm since that's where the majority of the token use is. Thanks again to you both!!! 🙌

Cart #mataraneni-0 | 2020-05-25 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
1

P#77155 2020-05-25 05:37 ( Edited 2020-05-25 05:38)

[Please log in to post a comment]

Follow Lexaloffle:          
Generated 2024-04-16 16:56:47 | 0.104s | Q:28