Last active
March 16, 2025 11:13
-
-
Save Achie72/875a98d352c7c2da7fd0c548ce5322bc to your computer and use it in GitHub Desktop.
Scene management with state machines
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- 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 |
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
More PICO-8 Tutorials: https://github.com/Achie72/kofi-articles/blob/main/README.md#pico-8-tutorials