Code archives/Miscellaneous/Game state engine
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
| You can use this code to split the game into different states. Extend GenericState into things like "StatePlay", "StateMenu", "StateGamePaused", etc and just call "GameState.Switch( new StatePlay )" when you want to jump from one state to another. Here is a quick example: Strict ' Include the goodies Include "gamestate.bmx" Graphics 800,600,0 ' Switch to the menu state GameState.Switch( New StateMenu ) ' Go! GameState.Run() End ' We're done now. '------------------------------------------------------------ '-------------------- Our extended states '------------------------------------------------------------ ' Create a new kind of state Type StateMenu Extends GenericState Method startup() Print "Loading menu..." EndMethod Method update() If KeyHit( KEY_1 ) Then GameState.switch( New StatePlay ) ' Player wants to play a game EndIf If KeyHit( KEY_2 ) Then GameState.ExitState() ' Exit this state. EndMethod Method draw() Cls DrawText "Game menu 2000 ultra power", 50,50 DrawText "1. Play the game", 50,80 DrawText "2. Quit", 50,100 Flip ; FlushMem EndMethod Method shutdown() Print "Removing menu stuff..." EndMethod Method on_hold() Print "Menu is paused while another state is running." EndMethod Method resume() Print "The menu is back in bussiness!" EndMethod EndType Type StatePlay Extends GenericState Field x,y, xv,yv Field paused_time Method startup() Print "Loading game..." x = Rand(0,800) y = Rand(0,600) xv = Rand(0,1) yv = Rand(0,1) EndMethod Method update() If KeyHit( KEY_ESCAPE ) Then GameState.ExitState() ' Player doesn't want to play anymore... If KeyHit( KEY_P ) Then GameState.Switch( New StatePause ) ' Pause the game If xv Then x:+1 Else x:-1 EndIf If yv Then y:+1 Else y:-1 EndIf If x < 0 Or x > 800 Then xv = Not xv If y < 0 Or y > 600 Then yv = Not yv EndMethod Method draw() Cls DrawRect( x-5,y-5,11,11 ) DrawText "Press Escape to quit, P to pause the game", 0,0 Flip ; FlushMem EndMethod Method shutdown() Print "Game is no more..." EndMethod Method on_hold() Print "Game paused while another state is running." ' Just for fun, save the millisecs() paused_time = MilliSecs() EndMethod Method resume() Print "Game resumed" ' For how long was we on hold? Print "Your little intermission lasted for "+(MilliSecs()-paused_time)+" milliseconds." EndMethod EndType Type StatePause Extends GenericState Method startup() Print "Game paused." SetBlend ALPHABLEND SetColor 0,0,0 SetAlpha 0.5 DrawRect( 0,0, 800,600 ) SetAlpha 1 SetColor 255,255,255 ' Draw the paused message here, only need to draw it once. DrawText "Tea time, eh? Press P to resume.", 100,100 Flip ; FlushMem FlushKeys() EndMethod Method update() ' Just wait for the right key to be pressed If KeyHit( KEY_P ) Then GameState.ExitState() ' Exit the pause state and go back to the play state EndMethod Method draw() ' No need to draw anything. It was done during startup EndMethod Method shutdown() Print "Unpaused." EndMethod Method on_hold() Print "Pause state paused? Funny that..." ' Not that crazy after all. Many games have a game menu that can be reached during a paused game EndMethod Method resume() Print "The pause state is resumed." EndMethod EndType And here you have gamestate.bmx: | |||||
' make a new type that extends this one. Overload the methods.
Type GenericState
' Overload this one and put startup code here (loading images, sounds, etc)
Method startup()
EndMethod
' No drawing here! Only user input and other behind-the-scene stuff
Method update()
EndMethod
' Draw things in this one. But no user input or logic code!
Method draw()
EndMethod
' Save highscore/nullify variables/scream like a banshee
Method shutdown()
EndMethod
' Called when the engine switches to a new state.
Method on_hold()
EndMethod
' Called when the engine is done with the other state and switches back t this one
Method resume()
EndMethod
EndType
Type GameState
Global state_list:TList
Global current_state:GenericState
Function Switch( new_state:GenericState )
If Not state_list Then state_list = CreateList()
state_list.addlast( new_state )
If current_state Then current_state.on_hold()
new_state.startup()
current_state = new_state
EndFunction
' Called by the running state when it doesn't want to play anymore
Function ExitState()
If Not state_list Then RuntimeError("ExitState should only be called by running states!")
current_state.shutdown()
state_list.remove( current_state )
If state_list.Count() > 0 Then
current_state = GenericState( state_list.last() )
current_state.resume()
EndIf
EndFunction
Function Run()
If Not state_list Then RuntimeError("Switch to a new game state before calling GameState.Run()")
While state_list.Count() > 0
current_state.update()
current_state.draw()
Wend
EndFunction
EndType |
Comments
| ||
| The logic and drawing code is separated in the states so that you could implement frame skipping in GameState.Run(). If you want to use delta time then just do it in the update() method of your states. Hope you will find this useful. |
| ||
| Oops, double post. deleted. |
Code Archives Forum