GLBasic forum

Codesnippets => Code Snippets => Topic started by: Albert on 2012-May-21

Title: StateMachine
Post by: Albert on 2012-May-21
Hi!

I've created this simple state machine for creating simple menus and game states during my LD48.

[attachment deleted by admin]
Title: Re: StateMachine
Post by: Albert on 2012-May-21
Here is how it's work:

Code (glbasic) Select

PROTOTYPE STATEPROTO: state AS TSTATE

TYPE TSTATE
id
typ$ //const enum
pos AS TPOINT
_paused //bool
_visible //bool
_created //bool
_inited //bool
create AS STATEPROTO //first create, load everything
destroy AS STATEPROTO //destroy, unload everything
init AS STATEPROTO //init after create or reset
reset AS STATEPROTO //reset all the stuff then init
update AS STATEPROTO //update
render AS STATEPROTO //draw

FUNCTION _superinit:
self.id=-1
self._paused = TRUE
self._created = FALSE
self._inited = FALSE
self._visible = FALSE
self.pos.set(0,0)
ENDFUNCTION

FUNCTION _isready:
IF (self._created AND self._inited)
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNCTION

FUNCTION _pause:
self._paused=TRUE
ENDFUNCTION

FUNCTION _start:
IF (self._isready())
self._paused=FALSE
ENDIF
ENDFUNCTION
ENDTYPE

// call these super TSTATE functions from your custom functions
FUNCTION state_create: stateid //first create, load everything
ALIAS state AS STATES[stateid]
state.create(state)
state._created=TRUE
state_init(stateid)
ENDFUNCTION

FUNCTION state_destroy: stateid //destroy, unload everything
ALIAS state AS STATES[stateid]
state_destroy(stateid)
state._paused=TRUE
state._inited=FALSE
state._created=FALSE
ENDFUNCTION

FUNCTION state_init: stateid //init after create or reset
ALIAS state AS STATES[stateid]
DBG("state._created:"+state._created,"state_init")
IF (state._created)
DBG("state.init()","state_init")
state.init(state)
state._inited=TRUE
ENDIF
ENDFUNCTION

FUNCTION state_reset: stateid //reset all the stuff then init
ALIAS state AS STATES[stateid]
state.reset(state)
state._inited = FALSE
state.pos.set(0,0)
state_init(stateid)
ENDFUNCTION

FUNCTION state_update: stateid //update
ALIAS state AS STATES[stateid]
IF (NOT state._paused)
state.update(state)
ENDIF
ENDFUNCTION

FUNCTION state_render: stateid //draw
ALIAS state AS STATES[stateid]
state.render(state)
ENDFUNCTION

FUNCTION state_emptyfunction: state AS TSTATE //dummy empty function
ENDFUNCTION

GLOBAL STATES[] AS TSTATE
GLOBAL currStateID
GLOBAL nextStateID
GLOBAL switchingState

FUNCTION newState AS TSTATE: typ$
LOCAL o AS TSTATE
o.typ$ = typ$
o.create = state_emptyfunction
o.destroy = state_emptyfunction
o.reset = state_emptyfunction
o.update = state_emptyfunction
o.render = state_emptyfunction
o._superinit()
RETURN o
ENDFUNCTION

FUNCTION addState: o AS TSTATE
o.id = BOUNDS(STATES[], 0)
DIMPUSH STATES[], o
RETURN o.id
ENDFUNCTION

FUNCTION changeState: stateid
STATES[currStateID]._pause()
currStateID = stateid
STATES[currStateID]._start()
ENDFUNCTION


Code (glbasic) Select

//an empty template, copy this for a new State, and rename all the words with 'Template' in it.

CONSTANT STATETYPE_TEMPLATE$ = "template"


FUNCTION state_Template_create: state AS TSTATE //first create, load everything

ENDFUNCTION

FUNCTION state_Template_destroy: state AS TSTATE //destroy, unload everything

ENDFUNCTION

FUNCTION state_Template_init: state AS TSTATE //init after create or reset
IF (state._created)
ENDIF

ENDFUNCTION

FUNCTION state_Template_reset: state AS TSTATE //reset all the stuff then init

ENDFUNCTION

FUNCTION state_Template_update: state AS TSTATE //update

ENDFUNCTION

FUNCTION state_Template_render: state AS TSTATE //draw

ENDFUNCTION

FUNCTION state_Template_register:
LOCAL state AS TSTATE
state = newState(STATETYPE_TEMPLATE$)
state.create = state_Template_create
state.destroy = state_Template_destroy
state.init = state_Template_init
state.reset = state_Template_reset
state.update = state_Template_update
state.render = state_Template_render
RETURN addState(state)
ENDFUNCTION


So we can create as many sates as we want, we can start/pause them, or reset/destroy.

Each state implements these functions (or use the default empty one):

create: load all the resources (Sprites, images, sounds, music, other resources), call only once

destroy: unload all the resources loaded on create, free all the memory used by state, If you want to use this state again, you have to create again before.

init: can be called only after already created the state, init all the variables, init timers, health points and so on

reset: reset the state, free all the variables initialized during init, then call the init to reinit them

update: process state, make all the calc inside update or ignore it if the state paused

render: render the state, make all your draw inside render
Title: Re: StateMachine
Post by: Albert on 2012-May-21
The main loop using state machine:


Code (glbasic) Select
//gameloop
WHILE NOT KEY(0)
//init
CLEARSCREEN RGB(128,128,128)

IF (switchingState)
IF (transitionStates())
changeState(nextStateID)
ENDIF

//render
state_render(currStateID)
state_render(nextStateID)

ELSE

//process
state_update(currStateID)

//render
state_render(currStateID)
ENDIF

//finish
SHOWSCREEN
WEND

Title: Re: StateMachine
Post by: TI-994A on 2012-May-21
Hi Albert. Really great work, beautifully done! It clearly illustrates working GUI techniques in GLBasic. Thank you for sharing it with us.
Title: Re: StateMachine
Post by: I love my Brick on 2012-May-21
Interesting stuff Albert, summit for me to play with later.

Thanx
Title: Re: StateMachine
Post by: erico on 2012-May-22
Great!
A bit over my possibility of understanding but, I guess a template for LD work always comes in handy to speed us up on such and many more occasions.
Title: Re: StateMachine
Post by: TI-994A on 2012-May-22
Hi guys! Does anyone know why the code fails on some earlier versions of GLBasic? I wasn't able to run the project on v.9.006, but it worked fine on v.10.202.
Title: Re: StateMachine
Post by: Albert on 2012-Jun-22
If you think this stuff is cool, then check out my LD48 entry. Unfinished, but there are some cool features in it, like the simple platform game physics http://www.ludumdare.com/compo/ludum-dare-23/?action=preview&uid=11574
Title: Re: StateMachine
Post by: mentalthink on 2012-Jun-22
Hi Albert thanks for the Code, I use in my game Machine States, and goes very well for make a lot of things into in a Class
Title: Re: StateMachine
Post by: Slim on 2012-Jun-23
Thank you.
Very useful. :good:
Title: Re: StateMachine
Post by: Albert on 2013-May-06
I've compiled to HTML5 and uploaded to Kongregate just to see if this is possible. http://www.kongregate.com/games/Alberton/glbasic-test-game
Not the perfect game to showcase GLBasic true performance but I wanted smthing playable fast.
Title: Re: StateMachine
Post by: erico on 2013-May-07
Super interesting! :good:

I gave a try, works fine, hard to play.