Skip to content

Instantly share code, notes, and snippets.

@Achie72
Last active March 16, 2025 11:13
Show Gist options
  • Save Achie72/875a98d352c7c2da7fd0c548ce5322bc to your computer and use it in GitHub Desktop.
Save Achie72/875a98d352c7c2da7fd0c548ce5322bc to your computer and use it in GitHub Desktop.
Scene management with state machines
-- state machines might sound complicated, but when it comes down
-- they are just if statements that control how our code behaves.
-- based on certain conditions you can jump between "states"
-- and this can help you also organize stuff better, animate more freely, or
-- for example, let's use state machines to create a menu system for our game
function _init()
-- we will start on the game logo scene
-- and we will have the following:
-- menu: to show a nice menu if you want
-- gameplay: where the actual game code runs
-- gameover: for a neat gameover scene
state = "logo"
player = {
x = 1,
y = 1,
health = 10
}
end
-- we will use this to restart any variable we need to be
-- reset between runs
function reset_values()
player = {
x = 1,
y = 1,
health = 10
}
end
-- main thing you need to remember is the goal to "branch" our
-- code when it states are different, so you don't draw the menu when the
-- game is going or vica versa
-- you can do this with simple if statements, i personally like to move them
-- to functions because now i only need to modify things in one palce, if needed
-- so let's modify our update, to to have the so called branching, aka execute different
-- code lines based on the state
function _update()
if state == "logo" then
update_logo()
elseif state == "menu" then
update_menu()
elseif state == "gameplay" then
update_gameplay()
elseif state == "gameover" then
update_gameover()
end
-- old code we had
-- now moved into update_gameplay as it is gameplay
--[[
if btn(0) then
player.x -= 1
end
if btn(1) then
player.x += 1
end
if btn(2) then
player.y -= 1
end
if btn(3) then
player.y += 1
end
]]--
end
-- now let's implement those state updates
-- for the logo, we want to show it for 2 seconds
-- on game load, but not after, because we want to ahve a
-- menu -> gameplay -> gameover gameplay loop
-- so let's use the time() call, to get how long our cart is running
-- and if it is over 2, switch to the menu
function update_logo()
if time() > 2 then
-- see, easily switch between two scenes!
state = "menu"
end
end
-- now for menu, we want to start the game if the players presses btn(5)
function update_menu()
if btnp(4) then
-- see, easily switch between two scenes!
state = "gameplay"
-- we also want to reset any values we need
-- for example reset the player to 10 hp and startpos fo 1,1
-- this will make it so that the last run doesn't mess with the current one
reset_values()
end
end
-- if you had gameplay code before in update, jsut move it into
-- this gameplay function
function update_gameplay()
if btnp(0) then
player.x -= 1
end
if btnp(1) then
player.x += 1
end
if btnp(2) then
player.y -= 1
end
if btnp(3) then
player.y += 1
end
-- we also want the game to be over if we are 0 hp, if players steps on the saw on the screen
-- which we draw at 32,32 or tile 4,4
if player.x == 4 and player.y == 4 then
-- lose some hp
player.health -= 1
end
-- now if we don't ahve hp, go to gameover
if player.health <= 0 then
state = "gameover"
end
end
-- and for last
function update_gameover()
-- we want to go back to the menu
if btnp(5) then
state = "menu"
end
end
-- now we will ahve to do the same thing with draw
-- here i'll show a neat trick!
function _draw()
if state == "logo" then
draw_logo()
elseif state == "menu" then
draw_menu()
elseif state == "gameplay" then
draw_gameplay()
elseif state == "gameover" then
draw_gameover()
end
-- i'll also pritnthe current state in the corner, so
-- you can see it change
print(state, 0, 100, 7)
end
-- a little helper function to print centered text
function print_center(text, x, y, color)
-- get the lenght of the text
-- if you did not know, print returns the position of the last character
-- so fi you print offscreen, starting from 0 you will get the exact lenght of the text
local len = print(text, 0, 400, color)
print(text, x-(len/2), y, color)
end
function draw_logo()
cls()
print_center("awesome logo", 64, 32, 7)
end
function draw_menu()
cls()
print_center("awesome menu", 64, 32, 7)
print_center("press c to start", 64, 48, 12)
end
function draw_gameplay()
cls()
print("웃", player.x*8, player.y*8, 12)
print("✽", 32, 32, 7)
print("health"..player.health,2,92, 12)
end
function draw_gameover()
cls()
-- because we have the gameplay draw in a seperate
-- function we can still call it on gameover,
-- and lay our gameover scene over it, aka create
-- a text over the gameplay
-- we cannot move ingame already, because the update is not on
-- the gameplay part, but you can still call the gameplay draw,
-- as they are now seperated using the functions
-- feel free to remove the draw_game and see how that will look
draw_gameplay()
-- here i'll use a little trick called control codes, don't worry,
-- nto fully needed, but you can draw a background for a text
-- if you append \#<color> in front of it, this color will have to be
-- hex valued, so 10 - a, 11 - b etc..
print_center("\#8gameover",64,32,1)
print_center("press x to menu", 64, 48, 8)
end
@Achie72
Copy link
Author

Achie72 commented Mar 16, 2025

@Achie72
Copy link
Author

Achie72 commented Mar 16, 2025

If you would like to read more like this, feel free to checkout my Ko-fi articles, with many devlogs and code rundowns like this!
https://github.com/Achie72/kofi-articles

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment