-
Notifications
You must be signed in to change notification settings - Fork 17
Straightforward Gamestates
A typical game has a menu screen, a congratulations screen and some kind of a pause regime. These different game modes are called gamestates. In this part, a simple implementation for such functionality is discussed.
I'm going to define 4 gamestates: "menu", "game", "gamepaused" and "gamefinished".
In the straightforward implementation it is enough to maintain a simple
variable gamestate
to switch between them.
It is declared in the main.lua
and initialized to the first game state - "menu".
local gamestate = "menu"
After that, in each love callback an if-else structure is necessary to check this variable:
function love.update( dt )
if gamestate == "menu" then
.....
elseif gamestate == "game" then
.....
elseif gamestate == "gamepaused" then
.....
elseif gamestate == "gamefinished" then
.....
end
end
In the "menu" state, a message is shown on the screen. When the Enter is pressed, the game starts (the state is changed to the "game"). On Esc the game is exited.
function love.draw()
if gamestate == "menu" then
love.graphics.print("Menu gamestate. Press Enter to continue.", --(*1)
280, 250)
elseif gamestate == "game" then
.....
end
function love.keyreleased( key, code )
if gamestate == "menu" then
if key == "return" then
gamestate = "game" --(*2)
elseif key == 'escape' then
love.event.quit() --(*3)
end
elseif gamestate == "game" then
.....
end
(*1): display a message on the screen.
(*2): on Enter, start the game
(*3): on Esc - quit.
There is nothing to update in this state, so the corresponding section
of the love.update
is empty:
function love.update( dt )
if gamestate == "menu" then
elseif gamestate == "game" then
.....
end
For the "game" gamestate, the contents of the love.draw
and love.update
are
transferred from the previous part. In love.keyreleased
there is a minor difference: on Esc instead of quitting, the
game switches to "gamepaused" state.
In the "gamepaused" state I want to freeze the ball and platform and display a message on the screen. This can be implemented if the game objects are drawn but not updated.
function love.draw()
.....
elseif gamestate == "gamepaused" then
ball.draw()
platform.draw()
bricks.draw()
walls.draw()
love.graphics.print(
"Game is paused. Press Enter to continue or Esc to quit",
50, 50)
elseif gamestate == "gamefinished" then
.....
end
function love.update( dt )
.....
elseif gamestate == "gamepaused" then --(*1)
elseif gamestate == "gamefinished" then
.....
end
(*1): the "gamepaused" update part is empty.
The love.keyreleased
callback is similar to the "menu".
The "gamefinished" state is entered when there are no more levels.
function switch_to_next_level( bricks, ball, levels ) --(*1)
if bricks.no_more_bricks then
.....
elseif levels.current_level >= #levels.sequence then
gamestate = "gamefinished" --(*2)
end
end
end
(*1): This function is moved from levels
table. An explanation is below.
(*2): When there are no more levels, gamestate is switched to "gamefinished".
"Gamefinished" is similar to the "menu" except that on Enter it resets the level counter and restarts the game from the first level.
function love.keyreleased( key, code )
.....
elseif gamestate == "gamefinished" then
if key == "return" then
levels.current_level = 1
level = levels.require_current_level()
bricks.construct_level( level )
ball.reposition()
gamestate = "game"
elseif key == 'escape' then
love.event.quit()
end
end
end
There is also one minor catch with levels.switch_to_next_level
.
The gamestate
variable is defined in the scope of main.lua
.
If it is simply passed into this function, it will be passed by value and it won't be
possible to change it from "game" to "gamefinished".
There are several solutions to this problem; I've simply moved
this function from levels
table inside the levels.lua
to main.lua
.
function switch_to_next_level( bricks, ball, levels )
if bricks.no_more_bricks then
if levels.current_level < #levels.sequence then
levels.current_level = levels.current_level + 1
level = levels.require_current_level()
bricks.construct_level( level )
ball.reposition()
elseif levels.current_level >= #levels.sequence then
gamestate = "gamefinished"
end
end
end
Feedback is crucial to improve the tutorial!
Let me know if you have any questions, critique, suggestions or just any other ideas.
Chapter 1: Prototype
- The Ball, The Brick, The Platform
- Game Objects as Lua Tables
- Bricks and Walls
- Detecting Collisions
- Resolving Collisions
- Levels
Appendix A: Storing Levels as Strings
Appendix B: Optimized Collision Detection (draft)
Chapter 2: General Code Structure
- Splitting Code into Several Files
- Loading Levels from Files
- Straightforward Gamestates
- Advanced Gamestates
- Basic Tiles
- Different Brick Types
- Basic Sound
- Game Over
Appendix C: Stricter Modules (draft)
Appendix D-1: Intro to Classes (draft)
Appendix D-2: Chapter 2 Using Classes.
Chapter 3 (deprecated): Details
- Improved Ball Rebounds
- Ball Launch From Platform (Two Objects Moving Together)
- Mouse Controls
- Spawning Bonuses
- Bonus Effects
- Glue Bonus
- Add New Ball Bonus
- Life and Next Level Bonuses
- Random Bonuses
- Menu Buttons
- Wall Tiles
- Side Panel
- Score
- Fonts
- More Sounds
- Final Screen
- Packaging
Appendix D: GUI Layouts
Appendix E: Love-release and Love.js
Beyond Programming: