mirror of
https://github.com/vrld/hump.git
synced 2024-11-23 12:24:19 +00:00
350 lines
8.9 KiB
ReStructuredText
350 lines
8.9 KiB
ReStructuredText
|
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 == 'enter' 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
|
||
|
|
||
|
|
||
|
.. _callbacks:
|
||
|
|
||
|
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
|
||
|
:func:`Gamestate.switch`.
|
||
|
|
||
|
``enter(previous, ...)``
|
||
|
Called every time when entering the state. See :func:`Gamestate.switch`.
|
||
|
|
||
|
``leave()``
|
||
|
Called when leaving a state. See :func:`Gamestate.switch` and :func:`Gamestate.push`.
|
||
|
|
||
|
``resume()``
|
||
|
Called when re-entering a state by :func:`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 :func:`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()
|
||
|
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
|
||
|
------------------
|
||
|
|
||
|
.. function:: 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()
|
||
|
|
||
|
|
||
|
.. function:: Gamestate.switch(to, ...)
|
||
|
|
||
|
:param Gamestate to: Target gamestate.
|
||
|
:param 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 :func:`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()
|
||
|
|
||
|
|
||
|
|
||
|
.. function:: 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
|
||
|
|
||
|
|
||
|
.. function:: Gamestate.push(to, ...)
|
||
|
|
||
|
:param Gamestate to: Target gamestate.
|
||
|
:param 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
|
||
|
|
||
|
|
||
|
.. function:: 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
|
||
|
|
||
|
|
||
|
.. function:: Gamestate.<callback>(...)
|
||
|
|
||
|
:param 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 :ref:`callbacks`. Mostly useful when not using
|
||
|
:func:`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
|
||
|
|
||
|
|
||
|
.. function:: Gamestate.registerEvents([callbacks])
|
||
|
|
||
|
:param table callbacks: 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
|
||
|
|