I use a system similar to Tokumaru's. The different sections of my game (title screen, gameplay, gameover, pause, etc) are divided into "gamestates". Each gamestate lives in its own file and has an init routine and a main routine (which calls the init routine). I store the addresses of all the main routines in a table and I have a subroutine set_gamestate which takes a gamestate id in A and uses it to grab an address from the table and stick it in a pointer variable (gamestate_ptr).
My main game loop just says:
Code:
forever:
jmp (gamestate_ptr)
and each gamestate ends with "jmp forever", completing the loop.
So for a start menu I might have:
Code:
;table of addresses to main gamestate routines.
; set_gamestate reads from this table to set gamestate_ptr
gamestate_table:
.word startmenu
.word gameplay
;other addresses
Code:
;--------------startmenu.asm-----
startmenu_init:
;draw title screen
;turn screen on
;start music
jmp gamestate_init_done ;this routine adds 3 to gamestate_ptr. To skip init for future iterations
startmenu:
jsr startmenu_init
;wait a frame
;read the controller
lda controller1
and #START_BUTTON ;bitmask that tests start button bit
beq end ;if not pressed, we're done. loop back to forever
;cleanup code (e.g. play sfx, fadeout loop)
;change to gameplay gamestate
end:
jmp forever
Having a gamestate handler like this has a little bit of overhead but it's easy for me to read and debug. Adding a new gamestate is as easy as adding a line to the address table.