Skip to content

Arx 09 Basic Gamestates: Game and Menu

noooway edited this page Jan 25, 2017 · 2 revisions

The core game mechanics is in place, and it is possible to think about some additional features. Most games start from the main menu screen. This chapter describes some preliminary preparations necessary to implement it.

Typically, at the menu screen some buttons are displayed. While I have not yet described how to implement them, at this point it is not hard to guess that buttons are going to be just another game objects. It fact, Button class is quite similar to the Brick class.

That means, that we would need call the buttons' constructor in love.load and place appropriate callbacks in the love.update and love.draw. However, if we simply put them there, menu elements and game elements will be updated and displayed simultaneously, overlapping, which we certainly do not want. We need a some kind of if-else system to select which objects to display right now. It can be put at the top level, directly into the love.draw and love.update, or we can add some flags inside the objects.

There is a neater way to handle this — gamestates. Gamestate holds an information on what objects to update and display at the current moment of the game. It is possible to transition between them to select different sets of objects. The whole game therefore is viewed as a sequence of gamestates.

I'm going to start from two gamestates - the "menu", and the "game"; in the next part two more will be added - "gamepaused" and "gamefinished". The "menu" state is the first one to appear, displaying a welcome screen. The "game" is where the actual game happens, with bricks, ball, platform, and the rest. "Gamepaused" state is entered, when the player hits an 'Esc' button. And finally there is also the end-game state, displaying a congratulations on finishing the game.

To implement the gamestates, I'm going to use hump.gamestate library. Its principle of operation is following: for each gamestate it is necessary to define a number of callbacks similar to love.load, love.update and love.draw, which are called when the gamestate is active. We use Gamestate.switch function to switch between the gamestates. The first gamestate is activated from the love.load() callback. Here is an example from the documentation:

local menu = {} --(*1)
local game = {}

function menu:draw()  --(*2)
   love.graphics.print("Press Enter to continue", 10, 10)
end

.....

function game:enter() --(*3)
   Entities.clear()
   -- setup entities here
end

function game:update(dt) --(*4)
   Entities.update(dt)
end

function game:draw() --(*4)
   Entities.draw()
end

function love.load() 
   Gamestate.registerEvents()
   Gamestate.switch(menu) --(*5)
end

(*1) - Two gamestates are declared: menu and game.
(*2) - draw callback for the menu gamestate.
(*3) - enter callback is called each time when gamestate is entered.
(*4) - draw and update callbacks for the game gamestate.
(*5) - from the love.load, we switch to the first gamestate (menu).

Ok, let's create the "menu" gamestate according to the example suggestion. In menu.lua:

local Gamestate = require "gamestate" --(*1)
local game = require "game"
local love = love

local menu = menu or {}

if setfenv then
   setfenv(1, menu)
else
   _ENV = menu
end

state_name = "menu"

function menu:enter()  --(*2)
end

function menu:update( dt ) --(*3)
end

function menu:draw() -- (*3)
   love.graphics.print("Menu gamestate. Press Enter to continue", 10, 10)
end

function menu:keyreleased( key, code ) --(*4)
   if key == 'return' then      
      Gamestate.switch( game ) --(*5)
   elseif  key == 'escape' then
      love.event.quit()
   end    
end

function menu:leave() --(*2)
end

return menu

(*1) A menu gamestate is just an ordinary Lua module; it is necessary to load other modules it depends on, and "gamestate" is one of them. It is also necessary to load the "game" gamestate module, since at (*5) transition to this gamestate is performed.
(*2) Right now we do not need any actions on entering or leaving "menu" gamestate, so appropriate callbacks are empty.
(*3) The update function is currently emtpy; draw displays an introductory message.
(*4) The last defined callback is menu:keyreleased, which switches to the "game" gamestate if the "Enter" key is pressed (released, actually), or exits if "Esc" is pressed.

Next is the "game" gamestate. Basically, it contains all the code that was in the main.lua previously, except for different callback names. Contents of love.load are moved to game:enter, love.update to game:update, and love.draw to game:draw. The most noticeable difference is the game:leave() callback. It is a good practice to delete all unnecessary objects on leaving a gamestate: call the objects' destructors and delete references to them:

function game:leave()
   level_sequence = nil
   level_counter = nil
   level_filename = nil
   level = nil
   collider = nil
   ball = nil
   platform = nil
   bricks_container = nil
   walls_container = nil
end

The last thing is changes in the main.lua. It is necessary to load the menu gamestate and initialize the library according to the example.

local Gamestate = require "gamestate"
local menu = require "menu"    --(*1)

function love.load()	
   Gamestate.registerEvents()  --(*2)
   Gamestate.switch( menu )    --(*3)
end
				  
function love.quit()
  print("Thanks for playing! Come back soon!")
end

(*1): menu gamestate is required.
(*2): All the gamestates are registered.
(*3): The game is switched into the "menu" gamestate.

    Home
    Acknowledgements
    Todo

Chapter 1: Prototype

  1. The Ball, The Brick, The Platform
  2. Game Objects as Lua Tables
  3. Bricks and Walls
  4. Detecting Collisions
  5. Resolving Collisions
  6. Levels

    Appendix A: Storing Levels as Strings
    Appendix B: Optimized Collision Detection (draft)

Chapter 2: General Code Structure

  1. Splitting Code into Several Files
  2. Loading Levels from Files
  3. Straightforward Gamestates
  4. Advanced Gamestates
  5. Basic Tiles
  6. Different Brick Types
  7. Basic Sound
  8. 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

  1. Improved Ball Rebounds
  2. Ball Launch From Platform (Two Objects Moving Together)
  3. Mouse Controls
  4. Spawning Bonuses
  5. Bonus Effects
  6. Glue Bonus
  7. Add New Ball Bonus
  8. Life and Next Level Bonuses
  9. Random Bonuses
  10. Menu Buttons
  11. Wall Tiles
  12. Side Panel
  13. Score
  14. Fonts
  15. More Sounds
  16. Final Screen
  17. Packaging

    Appendix D: GUI Layouts
    Appendix E: Love-release and Love.js

Beyond Programming:

  1. Game Design
  2. Minimal Marketing (draft)
  3. Finding a Team (draft)

Archive

Clone this wiki locally