hump.gamestate

Gamestate = require "hump.gamestate"

A gamestate encapsulates independent data an behaviour in a single table.

A typical game could consist of a menu-state, a level-state and a game-over-state.

Example:

local menu = {} -- previously: Gamestate.new()
local game = {}

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

function menu:keyreleased(key, code)
    if key == 'return' then
        Gamestate.switch(game)
    end
end

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

function game:update(dt)
    Entities.update(dt)
end

function game:draw()
    Entities.draw()
end

function love.load()
    Gamestate.registerEvents()
    Gamestate.switch(menu)
end

Gamestate Callbacks

A gamestate can define all callbacks that LÖVE defines. In addition, there are callbacks for initalizing, entering and leaving a state:

init()
Called once, and only once, before entering the state the first time. See Gamestate.switch().
enter(previous, ...)
Called every time when entering the state. See Gamestate.switch().
leave()
Called when leaving a state. See Gamestate.switch() and Gamestate.pop().
resume()
Called when re-entering a state by Gamestate.pop()-ing another state.
update()
Update the game state. Called every frame.
draw()
Draw on the screen. Called every frame.
focus()
Called if the window gets or looses focus.
keypressed()
Triggered when a key is pressed.
keyreleased()
Triggered when a key is released.
mousepressed()
Triggered when a mouse button is pressed.
mousereleased()
Triggered when a mouse button is released.
joystickpressed()
Triggered when a joystick button is pressed.
joystickreleased()
Triggered when a joystick button is released.
quit()
Called on quitting the game. Only called on the active gamestate.

When using Gamestate.registerEvents(), all these callbacks will be called by the corresponding LÖVE callbacks and receive receive the same arguments (e.g. state:update(dt) will be called by love.update(dt)).

Example:

menu = {} -- previously: Gamestate.new()

function menu:init()
    self.background = love.graphics.newImage('bg.jpg')
    Buttons.initialize()
end

function menu:enter(previous) -- runs every time the state is entered
    Buttons.setActive(Buttons.start)
end

function menu:update(dt) -- runs every frame
    Buttons.update(dt)
end

function menu:draw()
    love.graphics.draw(self.background, 0, 0)
    Buttons.draw()
end

function menu:keyreleased(key)
    if key == 'up' then
        Buttons.selectPrevious()
    elseif key == 'down' then
        Buttons.selectNext()
    elseif
        Buttons.active:onClick()
    end
end

function menu:mousereleased(x,y, mouse_btn)
    local button = Buttons.hovered(x,y)
    if button then
        Button.select(button)
        if mouse_btn == 'l' then
            button:onClick()
        end
    end
end

Function Reference

Gamestate.new()
Returns:An empty table.

Deprecated: Use the table constructor instead (see example)

Declare a new gamestate (just an empty table). A gamestate can define several callbacks.

Example:

menu = {}
-- deprecated method:
menu = Gamestate.new()
Gamestate.switch(to, ...)
Arguments:
  • to (Gamestate) – Target gamestate.
  • ... (mixed) – Additional arguments to pass to to:enter(current, ...).
Returns:

The results of to:enter(current, ...).

Switch to a gamestate, with any additional arguments passed to the new state.

Switching a gamestate will call the leave() callback on the current gamestate, replace the current gamestate with to, call the init() function if, and only if, the state was not yet inialized and finally call enter(old_state, ...) on the new gamestate.

Note

Processing of callbacks is suspended until update() is called on the new gamestate, but the function calling Gamestate.switch() can still continue - it is your job to make sure this is handled correctly. See also the examples below.

Examples:

Gamestate.switch(game, level_two)
-- stop execution of the current state by using return
if player.has_died then
    return Gamestate.switch(game, level_two)
end

-- this will not be called when the state is switched
player:update()
Gamestate.Gamestate.current()
Returns:The active gamestate.

Returns the currently activated gamestate.

Example:

function love.keypressed(key)
    if Gamestate.current() ~= menu and key == 'p' then
        Gamestate.push(pause)
    end
end
Gamestate.push(to, ...)
Arguments:
  • to (Gamestate) – Target gamestate.
  • ... (mixed) – Additional arguments to pass to to:enter(current, ...).
Returns:

The results of to:enter(current, ...).

Pushes the to on top of the state stack, i.e. makes it the active state. Semantics are the same as switch(to, ...), except that leave() is not called on the previously active state.

Useful for pause screens, menus, etc.

Note

Processing of callbacks is suspended until update() is called on the new gamestate, but the function calling GS.push() can still continue - it is your job to make sure this is handled correctly. See also the example below.

Example:

-- pause gamestate
Pause = Gamestate.new()
function Pause:enter(from)
    self.from = from -- record previous state
end

function Pause:draw()
    local W, H = love.graphics.getWidth(), love.graphics.getHeight()
    -- draw previous screen
    self.from:draw()
    -- overlay with pause message
    love.graphics.setColor(0,0,0, 100)
    love.graphics.rectangle('fill', 0,0, W,H)
    love.graphics.setColor(255,255,255)
    love.graphics.printf('PAUSE', 0, H/2, W, 'center')
end

-- [...]
function love.keypressed(key)
    if Gamestate.current() ~= menu and key == 'p' then
        return Gamestate.push(pause)
    end
end
Gamestate.pop(...)
Returns:The results of new_state:resume(...).

Calls leave() on the current state and then removes it from the stack, making the state below the current state and calls resume(...) on the activated state. Does not call enter() on the activated state.

Note

Processing of callbacks is suspended until update() is called on the new gamestate, but the function calling GS.pop() can still continue - it is your job to make sure this is handled correctly. See also the example below.

Example:

-- extending the example of Gamestate.push() above
function Pause:keypressed(key)
    if key == 'p' then
        return Gamestate.pop() -- return to previous state
    end
end
Gamestate.<callback>(...)
Arguments:
  • ... (mixed) – Arguments to pass to the corresponding function.
Returns:

The result of the callback function.

Calls a function on the current gamestate. Can be any function, but is intended to be one of the Gamestate Callbacks. Mostly useful when not using Gamestate.registerEvents().

Example:

function love.draw()
    Gamestate.draw() -- <callback> is `draw'
end

function love.update(dt)
    Gamestate.update(dt) -- pass dt to currentState:update(dt)
end

function love.keypressed(key, code)
    Gamestate.keypressed(key, code) -- pass multiple arguments
end
Gamestate.registerEvents([callbacks])
Arguments:
  • callbacks (table) – Names of the callbacks to register. If omitted, register all love callbacks (optional).

Overwrite love callbacks to call Gamestate.update(), Gamestate.draw(), etc. automatically. love callbacks (e.g. love.update()) are still invoked as usual.

This is by done by overwriting the love callbacks, e.g.:

local old_update = love.update
function love.update(dt)
    old_update(dt)
    return Gamestate.current:update(dt)
end

Note

Only works when called in love.load() or any other function that is executed after the whole file is loaded.

Examples:

function love.load()
    Gamestate.registerEvents()
    Gamestate.switch(menu)
end

-- love callback will still be invoked
function love.update(dt)
    Timer.update(dt)
    -- no need for Gamestate.update(dt)
end
function love.load()
    -- only register draw, update and quit
    Gamestate.registerEvents{'draw', 'update', 'quit'}
    Gamestate.switch(menu)
end