====== Clean game state engine using closures ====== This trick allows you to separate the different states in your game so that their individual state variables do not bleed into each other. Most games will still have global variables, but those side effects are predictable and expected. Separating things into closures allows you to **encapsulate state with behavior**. It's fairly simple; all you need is a single global variable and some glue in the PICO-8 API: function my_game_state() local msg = "hello, world!" return { update = function(self) if btnp(5) then msg = "goodbye, world!" end return self end, draw = function() cls() print(msg) end } end function _init() state = my_game_state() end function _update() -- this will update itself over time state = state:update() end function _draw() state:draw() end With the above, you'll get a self-contained function that has *everything* you need relating to that game state, in one place. A gotcha to watch out for is **the update member you're returning needs to accept a 'self' argument and MUST return either itself or the result of another game state function**. ===== Switching states ===== Switching between your game states is as simple as returning another function's result. So if we added a ''title_screen'' game state, but wanted to get there from another state, we'd do something like: -- let's pretend there's a cool title_screen function defined here function my_game_state() return { update = function(self) if btnp(6) then -- here's the 'magic' return title_screen() else return self end end, draw = function() -- draw stuff end } end To get a better idea of how it's employed, check out [[https://git.zlg.space/pico8-carts/tree/api/closure-states.p8|ZLG's closure game-state demo]].