Controller Input Subroutines: How many?

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Controller Input Subroutines: How many?
by on (#41802)
Hello, I'm still in the design phase of my little one-screen game and I'm making a list of all subroutines I will have to write. I have a simple question about how to handle Controller Input.

First a little info. My game has a few different gamestates (TitleScreen, Movie, Gameplay, Paused, GameOver). Some gamestates have very few Controller Input possibilities (Paused gamestate only has one: START to unpause). Other gamestates have many Controller Input possibilities (Gameplay).

I will have one ReadController subroutine that will be called outside of gamestates and store button status in RAM. Then within the gamestates I will want to handle that input, so...

My question is:

Should I have just one HandleInput subroutine that will handle all possible gamestate (i.e. all gamestates will call the same subroutine)? or have a separate subroutine for each gamestate (HandleInputTitleScreen, HandleInputMovie, HandInputGameplay, etc)?

or both? or neither?

What's the best way to organize this?

by on (#41803)
I would definitely have different segments of code to handle button presses for different things. But you should have a segment of code that reads button presses, and puts all the button press information into a single byte (1 bit per button), then read from this value in each section. Oh, and also have a "ButtonPressOld" byte which holds the values of the buttons pressed last frame.

by on (#41805)
But you don't need more than one subroutine to interact directly with the input registers and update global variables containing the current and previous states of the buttons. You just call this subroutine from different parts of the game loop.

by on (#41808)
If I had the time I would do it both ways and weigh the resulting data/cycle cost.

I don't see it being that difficult to go

Code:
if (start is pressed)
     if (gamestatus = titlescreen)
          start game
     else if (gamestatus = paused)
          unpause game
     else
          pause game
     endif
endif


But it takes a few more cycles and I also don't see it being that difficult to call different routines.

by on (#41814)
Here's a good method. Store the address of the controller routine at say $40/$41 in ZP. Then when you want to go to the controller routine, do JMP ($40). So if you want to point to a different controller routine, change $40/$41 to the address of the desired routine.

by on (#41821)
Thanks for the replies guys! I have a lot of good ideas to think about. But I think I didn't communicate my question as clearly as I wanted to, because the answers didn't hit the point that was bothering me. I hope it will be a little clearer what I'm asking with this reply.

UncleSporky wrote:
I don't see it being that difficult to go

Code:
if (start is pressed)
     if (gamestatus = titlescreen)
          start game
     else if (gamestatus = paused)
          unpause game
     else
          pause game
     endif
endif


But it takes a few more cycles and I also don't see it being that difficult to call different routines.


In the case of one master subroutine, I was originally thinking of nesting it like this:

Code:
if (gamestate=titlescreen)
   if (start is pressed)
       start game
   if (down is pressed)
       move menu cursor down
     ....
if (gamestate=movie)
   if (start is pressed)
       skip movie
   ...
etc


because button priorities might differ by gamestate and because I want each gamestate to be as separate from the other ones as possible.

The idea behind having one master subroutine would be for readability/organization. It's easier for me if all gamestates are interfacing the Controller Input stuff through the same subroutine:

Code:
check gamestate, jump to correct label
TitleScreen:
    Do some stuff
    JSR HandleInput
    JMP GamestateStuffDone
Movie:
    prepare next frame for drawing
    JSR HandleInput
    JMP GamestateStuffDone
Gameplay:
    Check game timer to see if you're dead
    JSR HandleInput
    UpdateScore
    ....
    ....
    If it's been 60 frames, decrement GameTimer
    JMP GamestateStuffDone
...
etc.


But it comes at the cost of checking the gamestate twice (once to get to the gamestate's main codeblock, which is where the HandleInput call will be, and then once again within HandleInput to take the correct branch).

Having separate subroutines for each gamestate (HandleInputTitleScreen, HandleInputPause, etc) would avoid the double check at the cost of losing a common interface/readability.

Hope I'm explaining my dilemma alright. It's hard to talk about this stuff in words! Basically I want to have the master subroutine, but I'm worried that it's wasteful with such limited resources.

Celius wrote:
Here's a good method. Store the address of the controller routine at say $40/$41 in ZP. Then when you want to go to the controller routine, do JMP ($40). So if you want to point to a different controller routine, change $40/$41 to the address of the desired routine.


so within each gamestate, somewhere I'd have:
Code:
set pointer in $40/$41
jmp ($40)


i.e. different code in each gamestate's main codeblock?

or would I have a master subroutine (HandleInput, see above) that sets the correct pointers and performs the jump?

i.e. each gamestate's main codeblock will have the same call to HandleInput?

Again, thanks for your comments so far!

by on (#41823)
Anywhere where you make a decision to change game modes, you set the pointer to $40/$41. Probably not right before you jump to it.

by on (#41826)
Celius wrote:
Anywhere where you make a decision to change game modes, you set the pointer to $40/$41. Probably not right before you jump to it.


Good idea. So everytime you change a gamestate, you'd set a series of pointers for every set of gamestate-specific routines. Makes a lot of sense. How many different pointers do you usually use for this kind of thing, and for what kinds of functionality (other than controller input handling)?

And a newbie question. If I jump to my Controller Input Routines via a pointer in ZP, how do I get back? Since I'm not using JSR, I can't return with RTS, right? Once I'm done handling the input, how would I get back to where I started?

by on (#41827)
If you know where you're jumping from, all you have to do is something like:

jmp ($40)
Label:
...

;Address jumped to with jmp($40)
;blah code
jmp Label

So you don't really do a variable "Return", but just a direct jump back to a label ahead of "jmp ($40)". If you don't know where you're jumping from, that's a long story. You'd want to do something like "jmp ($42)" where you return in the end of the routine gone to with jmp ($40). $42/$43 hold the address of where you want to return. Actually, all you'd have to do then is something like this:

lda #High(Label)
sta $43
lda #Low(Label)
sta $42
jmp ($40)
Label:
...

;Code gone to with jmp ($40)
;Blah code
jmp ($42)

This is okay to do, however you could eat up a lot of bytes having this sort of set up for lots of different routines.

by on (#41830)
Sorry I didn't read the whole thread (yet), but reading 8 bits of the controller, and storing the result in a byte is really the standard way to do it. I've always do that since my very first demo and all commercial games seems to do that. Then you can take the older controller status eor-ed with #$ff and anded with that byte to detect all '0' to '1' transitions (which means the button has just been pressed), which is often as usefull as just detecting a '1' (wich means the button is hold down).

Do do the unpause thing you'd want to do something like that
Code:
_pause
jsr WaitVBl
jsr ReadController
lda JoyLocked
and #$10
bne _pause

ReadController
   lda JoyData
   eor #$ff$
   pha
   jsr ReadJoypad1    ;This overwrite JoyData with new value
   pla
   and JoyData
   sta JoyLocked
   rts

Where "JoyLocked" is the variable that detects '0' to '1' transitions (you don't want to use JoyData, which is when the button is pressed, I just made those names up and use them in all my programms, but you can use your owns).

by on (#41833)
For organizing something like this, I've thought about a lookup table system. For example:

Code:
VideoRoutine:
.dw TitleVideo, GameVideo, StatusVideo

ControlRoutine:
.dw TitleControl, GameControl, StatusControl


Where GameStatus $01 is the title screen, $02 is the main game etc. You read VideoRoutine modified by (GameStatus * 2) to get to the starting bit. You could use this to organize a lot of other things too such as level music.

What do you more experienced people think of this? Is it wasteful? I like it on the surface but I'm not experienced yet in optimization.

by on (#41834)
Oh, I used to use this "gamestate" technique when I started out. The main loop would be nothing but an instruction that jumps over itself, and the NMI would do a few common things (like sprite DMA) before jumping to a different adress in function of game state. However, this was extremely limited and tedious as your code will always jump to the same adress no matter what, so you neeed a lot of variables and check them to know where to jump, and not only it is tedious, but wastes CPU ressources. I even got a system that get rid of those limitations for the AI of my enemies.

However, Nintendo used that system for some of their earlier games, and Konami seems to use it all the time, so if you know what you do and if that works for you I'd say go for it.

After a quick automated seach in my source files, there is 26 times I call a "WaitVbl" routine. Doing an equivalent programm with the game state mode would correspond to 26 game states and you'd jump to one of those 26 places depending on it, which should be some trouble to handle.

by on (#41836)
Celius wrote:
If you know where you're jumping from, all you have to do is something like:

jmp ($40)
Label:
...

;Address jumped to with jmp($40)
;blah code
jmp Label

.....(cut)......

This is okay to do, however you could eat up a lot of bytes having this sort of set up for lots of different routines.


I thought of another question. Is there an advantage to using this pointer system over just JSRing to subroutines? It looks like it would be harder to keep track of my code with all of this manual jumping. Why not just JSR to a HandleInputTitleScreen subroutine (if I were in the TitleScreen gamestate, for example) instead?

Bregalad wrote:
Then you can take the older controller status eor-ed with #$ff and anded with that byte to detect all '0' to '1' transitions (which means the button has just been pressed), which is often as usefull as just detecting a '1' (wich means the button is hold down).


You're awesome! Figuring out a way to detect 0 to 1 transitions was next on my list of things to figure out. It will be quite necessary for my game to know this. Thank you! :)

UncleSporky wrote:
For organizing something like this, I've thought about a lookup table system.

Code:
VideoRoutine:
.dw TitleVideo, GameVideo, StatusVideo

ControlRoutine:
.dw TitleControl, GameControl, StatusControl


To clarify, would these data words hold the addresses where the routines are located, i.e. the addresses you want to jump to?

Bregalad wrote:
Oh, I used to use this "gamestate" technique when I started out.

....(cut)....

However, Nintendo used that system for some of their earlier games, and Konami seems to use it all the time, so if you know what you do and if that works for you I'd say go for it.


Well, I am just starting out :). This gamestate way seems like a good way to start, since I at least understand it. When I get more experience under my belt I can look at other ways to organize program flow. I think I can cover some of the losses by checking for the most common gamestates first (gameplay, pause) so that most of the time there will only be one check needed.

And I don't have anywhere near 26 gamestates. I have 6. :) And one of them (EndingMovie/Credits) accepts no input and won't be reached very often, so really it's more like I have 5. But I see your point. With a more complex game, it would be extremely tedious jumping between 26 different gamestates!

Thanks for all the help guys. I'm really learning a lot (more than I expected!)

by on (#41837)
MetalSlime wrote:
UncleSporky wrote:
For organizing something like this, I've thought about a lookup table system.

Code:
VideoRoutine:
.dw TitleVideo, GameVideo, StatusVideo

ControlRoutine:
.dw TitleControl, GameControl, StatusControl


To clarify, would these data words hold the addresses where the routines are located, i.e. the addresses you want to jump to?

Yes, those are just labels that get processed as addresses by the assembler. You use them as normal before the routines:

Code:
TitleVideo:
     blah blah
     rts

GameControl:
     blah blah
     rts


Again, I don't know if that's a good way to do it but it feels nicely organized.

by on (#41839)
Quote:
And I don't have anywhere near 26 gamestates. I have 6. Smile And one of them (EndingMovie/Credits) accepts no input and won't be reached very often, so really it's more like I have 5. But I see your point. With a more complex game, it would be extremely tedious jumping between 26 different gamestates!

My game is not really complex either. I just have a title screen, a stage introduction screen and gameplay. I haven't coded any end movie or credits yet. It's just that I don't use gamestates, but I do a "jsr WaitVbl" whenever I have a frame completed, and it returns to the next of the programm. This is not really hard to understand even for newbies.
It's just that when you want for example to draw a window texbox on screen, you so something like draw rows 1&2, wait a VBlank, draw rows 3&4, wait a VBlank, etc... in a loop.
If you don't have a wait VBlank method, but a game state method I have no idea how you're supposed to do that. You should probably have one "sub game state" by possible row, which sounds terribly tedious.

Even more complex Konami games like Castlevania III, Lagrange Point, Bucky o'Hare, and so on are all coded that way. I really have no idea how Konami programmers were able to do it that way, but maybe it's just not as a headache as I can remember, if you use a lot of indirect jumps cleverly.

by on (#41841)
Celius wrote:
Here's a good method. Store the address of the controller routine at say $40/$41 in ZP. Then when you want to go to the controller routine, do JMP ($40). So if you want to point to a different controller routine, change $40/$41 to the address of the desired routine.


I use this approach for a lot of stuff. NMI activities, vblank, etc.. It makes for a cleaner state machine too (In my opinion).

Al

by on (#41843)
Quote:
It makes for a cleaner state machine too (In my opinion).

But it's more likely to get crashes because the adress didn't point to where exepted. But hey, crashes are much less an issue to fix than variable conflicts.

by on (#41881)
Bregalad wrote:
It's just that when you want for example to draw a window texbox on screen, you so something like draw rows 1&2, wait a VBlank, draw rows 3&4, wait a VBlank, etc... in a loop.
If you don't have a wait VBlank method, but a game state method I have no idea how you're supposed to do that. You should probably have one "sub game state" by possible row, which sounds terribly tedious.

Even more complex Konami games like Castlevania III, Lagrange Point, Bucky o'Hare, and so on are all coded that way. I really have no idea how Konami programmers were able to do it that way, but maybe it's just not as a headache as I can remember, if you use a lot of indirect jumps cleverly.

Are you saying that if you have a game state setup, you can't wait for vblank? It sounds like you mean that if you don't wait for vblank the game will continue to draw all the rows as fast as it can and you'll see the whole text box rather than watching it get drawn, which may be true, but why can't you wait for vblank and also have a game state system?

I would do something like this:

mainloop:
jump to subroutine based on game state
jump to another subroutine the same way if you need to, etc.
...
loopdone = 1 (tell NMI that we are done with main loop calculations)
wait for vblank
loopdone = 0
jmp mainloop

You program NMI to do very little (sound processing only) until it hears from the main loop that its calculations are done, which may be one frame, two frames or less than a frame. Either way, the main loop executes exactly once and then waits.

As for doing a text box, you would deal with that within one of the game states, probably the main gameplay one like Final Fantasy's town map. Early on you detect if a textbox is being drawn, and if it is you skip all of the movement processing and such and draw one line of the text box, ending the subroutine. Every vblank a little more will get done until it's finished.

by on (#41905)
Why on earth would you have multiple input routines? The normal is to read all the bits from the joypad and put them in a byte, since, conveniently enough, there are exactly 8 buttons in a NES controller. This routine is always the same, but each "game state" will read this byte and do different things based on its contents.

Unless you are confused by those awkward demos where the programmer branches to different action immediately after reading the bit from the controller register... is that it? That is an awful way to control games. You'd better just stuff the input into a byte (for each controller) and use that to make decisions.

by on (#41910)
tokumaru wrote:
Why on earth would you have multiple input routines? The normal is to read all the bits from the joypad and put them in a byte, since, conveniently enough, there are exactly 8 buttons in a NES controller. This routine is always the same, but each "game state" will read this byte and do different things based on its contents.

Unless you are confused by those awkward demos where the programmer branches to different action immediately after reading the bit from the controller register... is that it? That is an awful way to control games. You'd better just stuff the input into a byte (for each controller) and use that to make decisions.


I think you misunderstood my question, which is my fault since I didn't express it clearly enough. :) I'll quote from my original message:

MetalSlime wrote:
I will have one ReadController subroutine that will be called outside of gamestates and store button status in RAM.


This is where I read the joypad and store the button status in one byte.

MetalSlime wrote:
Then within the gamestates I will want to handle that input, so...


Here, "handle" means "do stuff based on the input you got from reading the joypad".

So this thread is really asking how to organize the "do stuff after you read the joypad" part. Sorry for the confusion.

by on (#41913)
Oh I see. It's my fault, I'm kinda sleepy (nearly 5AM now) and probably read the post too quickly. Sorry about that.

My opinion on that is that if the input must be handled differently in different program sections, everything else probably will be different too, so these sections are basically different sets of main loops.

I handle those in my programs as "program modules". They all set themselves up and eventually enter their main loops. Each of them is free to select which NMI routine to use and whatever else they'd like. Switching to a new module is just a matter of jumping to its reset address, and that's how the program jumps from module to module.

by on (#41920)
I haven't understood most of those "game state" or "module" thing, but my opinion is that you guys are complicating it a lot.

My game engine is just a programm that flows normally, there is none of theese things, and it works very well and I don't feel limited. I admit I had to find a big trick for ennemies AI to trick the stack in order to make the programm much easier to write, and I'm still limited to 1 object = 1 metasprite, which I may get rid of if I feel like it without adding any crap to my game engine.

If your title screen is different of your main gameplay (it should unless you're cloning SMB) just make it a different part of the programm and I don't see any problem. I don't understand what you want crappy thing you want to do with jsr in function of game state. However if that woks for you go ahead, I can't force anyone to use my programming technique.

by on (#41922)
What exactly do you mean by a program that "flows normally"? And how is using indirect jumping to allow you to execute different segments of code depending on the "gamestate" (Title screen mode, main gameplay, etc.) overly complicated? It's not so different from my NMI where I do just a bunch of indirect jumps, and in fact, it's a lot simpler.

by on (#41923)
Celius wrote:
What exactly do you mean by a program that "flows normally"? And how is using indirect jumping to allow you to execute different segments of code depending on the "gamestate" (Title screen mode, main gameplay, etc.) overly complicated? It's not so different from my NMI where I do just a bunch of indirect jumps, and in fact, it's a lot simpler.


BTW Celius, is there an advantage of using indirect jumps instead of JSRs? Is it a speed thing?

by on (#41940)
Oh, no, it's not really a time thing. It's mostly because there is no indirect JSR. It'd be AWESOME if there was a JSR ($xx), because I'd do away with JMP ($xx) all together. I only use it because I can jump to a variable address. You really don't have to use it. It's actually a good idea to have this somewhere in RAM:

JSR $XXXX
RTI

For your NMI Routine. That way you can make $XXXX any address you want, since it's RAM, and still be doing a JSR. I think I might switch to this method instead of using indirect jumps. Oh, but make sure if you're outside of the NMI, and you are changing the address, first make the opcode for "JSR" "RTI" so that if the NMI is executed while you are updating the $XXXX part, it's not partially updated/interrupted, in which case it would crash.

by on (#41941)
I don't think indirect jump is overly complicated, but what the other guy described seemed to be. Why do you want only one loop that does only indirect jumps for all your programm when you could have separate sections with separate loops that does normal jsr ? I really don't see the point. There is no advantage of that game state thing.
When I'm on title screen, I'm in a loop that wait for the player to press "start".
When I'm on a stage introduction screen, I'm in a loop that show some graphic effects and wait for a timer to overflow.
When I'm in gameplay I do a lot of jsr and repeat until I have a game over or stage beaten flag set.

All of these are loops, but they are completely separated, and I have no such thing as a "gamestate" variable. If I wanted to make all those loops into a single "game loop" and check a "game state" and do indirect jsr so that it would have the same effect as the original programm, it would be overly complicated and inneficient to implement. However, if this works for you, go away.

by on (#41943)
Bregalad wrote:
I don't think indirect jump is overly complicated, but what the other guy described seemed to be. Why do you want only one loop that does only indirect jumps for all your programm when you could have separate sections with separate loops that does normal jsr ? I really don't see the point. There is no advantage of that game state thing.
When I'm on title screen, I'm in a loop that wait for the player to press "start".
When I'm on a stage introduction screen, I'm in a loop that show some graphic effects and wait for a timer to overflow.
When I'm in gameplay I do a lot of jsr and repeat until I have a game over or stage beaten flag set.

All of these are loops, but they are completely separated, and I have no such thing as a "gamestate" variable. If I wanted to make all those loops into a single "game loop" and check a "game state" and do indirect jsr so that it would have the same effect as the original programm, it would be overly complicated and inneficient to implement. However, if this works for you, go away.


You can blame bunnyboy, since I jumped into writing my own game after finishing his tutorials. :) His pong game uses the gamestate method: http://www.nintendoage.com/forum/messageview.cfm?catid=22&threadid=8747. I'm a newbie so I don't really know if this gamestate method has any advantages over your own.

One thing I want to make clear is that I haven't made any decision to use indirect jumps yet. This was just a new idea that Celius introduced to me in this thread. Right now my design documents show a gamestate setup using normal JSR. There's just one jump at the beginning of the main loop to choose the right gamestate codeblock.

Anyway I personally don't think gamestates are too complicated, but you bring up a good question: why bother?

I haven't started coding at all yet as I'm just designing the game, so it would be very easy to change my mind and get away from the gamestate method of organizing it. Thanks for bringing this up!

Does anybody know of any advantages to using the gamestate method over a using series of loops like Bregalad? If there aren't any, maybe I should change my design documents.

by on (#41945)
I don't know if it is more or less effective to do so on the NES, but a state setup is just naturally how you do programming. It's organized, efficient, and emphasizes code reusability.

I see a stateless program as just one long stream of consciousness, where every new thing that happens is a result of what came before. Ideally, you want every routine you have to be a self-contained function that takes a number of arguments and results in a predictable output. It needs to be modular so that in the future you could drag and drop that one function into a new program and it would work the same way that it used to, as long as you gave it the same arguments.

In the end I think it is mainly different structures, though. What Bregalad describes sounds point to point, finish-this-then-move-on-to-that. A game state setup is more like nested folders: you open the main folder, then decide which folder to open next, navigating an ordered list of functions that can you can change at any time based on variables. You are in control, you don't have to move entire loops around if you want to change the order of things. Just call a different subroutine.

If everything is just a lot of loops in a straight line, what if you want to display the title screen again for some reason? Yes you could jump to the title screen code, but after that the game starts over at level one automatically, right? With a state you can change a variable and go right back into gameplay again.

I'm not entirely sure I understand the setup Bregalad is talking about...it sounds a lot like there are states anyway, just without a single variable.

What if you have some side scroller levels and some racing levels, with different drawing and input routines? If you have anything in your game to detect which type of level it is and how the routines change, that's a game state. Whenever the player pauses the game, that is a game state (everything is processed differently for the duration). You're probably already following the basic principles without realizing it. My way of organizing things is just taking it a little further than GameIsPaused = 1.

Of course what is most important is that your game runs quickly and smoothly. :)

by on (#41963)
Quote:
I don't know if it is more or less effective to do so on the NES, but a state setup is just naturally how you do programming. It's organized, efficient, and emphasizes code reusability.

It's fun because I'd almost say the exact opposite. Working with gamestate method would be a huge mess because all code would be merged at the same place and doing lots of indirect jumps. This would be hard to modify and unorganized. Plus, the programm have to read a variable, do an indirect jump in function of it, read another, re-do an indirect jump, etc... It's unefficient when you could just jsr to the desired routine straight away. Code reusability ? Well, as long as you use subroutines instead of just in-linging code, there is nothing to worry about that (no matter if you jump to them directly or indirectly).
Quote:
¨
If everything is just a lot of loops in a straight line, what if you want to display the title screen again for some reason? Yes you could jump to the title screen code, but after that the game starts over at level one automatically, right? With a state you can change a variable and go right back into gameplay again.

Don't worry, my loops are *not* in a straight line. If I wanted to show the title screen again during gameplay, I would just make the code that draw the title screen in a routine, and do "jsr DrawTitle" again. I don't see the problem here.

Quote:
I'm not entirely sure I understand the setup Bregalad is talking about...it sounds a lot like there are states anyway, just without a single variable.

Well, I guess there *is* gamestates anyway no matter if you want them or not... but it's just I don't worry about that, and just keep things separed if they must be separed.
Quote:
Of course what is most important is that your game runs quickly and smoothly. Smile

Yes you're right. Konami used the "state" method and does a lot of indirect jumps all the time, yet most of their games runs quickly and smoothly.

Quote:
You can blame bunnyboy, since I jumped into writing my own game after finishing his tutorials. Smile His pong game uses the gamestate method: http://www.nintendoage.com/forum/messag ... eadid=8747. I'm a newbie so I don't really know if this gamestate method has any advantages over your own.

Well, I don't know what will work the best for you. I think the state method worked because a pong clone is extremely simple to code, and so the negative effect of the game state method didn't show up.

I don't remember if I mentionned it yet, but I originally wanted to make a RPG on the NES based on a "Game State" variable, where 0 = Title Screen, 1 = Menu sub-screen, 2 = Field screen and 3 = Battle. In the NMI I just did an indirect jump (altough I only implemented 0 and 1 before giving up that programm).
It worked very well for 0, as nothing very spectacular had to be done. However, for 1, I had a long hard time to figure how to draw text-boxes with this engine. I made a "sub-game state" variable to get more entry points in my routines, but that was still too limited. In the end I ended up using an indirect jump pointer, and whenever a frame was complete, I set this pointer so that on next frame it would do an indirect jump to it. But even that was a headache to handle, so I gave up and made another project :)

That was long ago tough so I don't really remember the details. Maybe what I wrote above isn't exactly correct also. I think I thrown away the source so I can't even look back to see why that was such a pain. I was a newbie to programming back then, so how painfull this was could also be done to my lack of programming skills.

However, more recently I found myself having headache with enemy AI because I had only one entry point, and needed to do lot of switch and if/else branches in function of enemy's state variable. I hated it because while it worked fine, each time I wanted to modify the code to add something to enemy's AI, it was a headache. Now I found a way to trick the stak in order to have a variable entry point, and everything fixes up :wink:
There is sill the inconvenient that if I wanted to call a routine in all cases no matter the enemy's state, I had to do it only once before the indirect jump with the old system, and I have to do it a lot of times with the new. However, again a simple use of the jsr opcode can fix that.

Quote:

What if you have some side scroller levels and some racing levels, with different drawing and input routines?

Well, you'd probably have only one routine reading the controller, but a different engine reading it and interfacing with it.
As for drawing routines, they don't really need to be different. I have a routine that allows me to draw up to 2 name table rows + 1 attribute table rows in NMI (or less if I need less), and another that allows me to draw a metatile without changing the rest. That does all the drawing for me and I never felt any limited with that (other than what the hardware limits you). If I were to do completely disconnected engine where more special screen updates would be needed, I guess I'd still opt for different NMI routines.

by on (#41986)
Then I think one or both of us are confused. :)

A state system in the way I am talking about it is literally just determining what to do next based on a variable, involving a lot of subroutines. The game starts out in a title screen state, and when the player moves past that the state changes to the game, etc.

I think what we are talking about here is just the difference beteen an extended if-then statement and a select case.

Like so:

Code:
if titlescreen = 1 then
     jsr title
else
     jsr gameplay

gameplay:
     if statusscreen = 1 then
          jsr status
     else
          jsr maingame


vs.

Code:
x = gamestate
jsr statetable,x

statetable:
.db title, status, maingame


Is that about right?

by on (#41988)
Maybe he's referring to something like this:

Code:
;In title screen...
if StartPressed = 1
    jmp MainGameLoop    ;switch loops
else
    do other stuff and loop

...

MainGameLoop:
....
if StartPressed = 1
  jmp PausedLoop     ;switch loops
else
 jmp MainGameLoop

PausedLoop:
....
if StartPressed = 1
   jmp MainGameLoop   ;switch loops
else
   jmp PausedLoop



Where you don't check directly which game state you're in; you're just in a loop. Once something happens, go to another loop. This kind of eliminates the need for a game state variable.

by on (#41994)
You need a game state variable if the two players can enter states independently, like in Klax for NES.

by on (#41999)
Game states also help prevent spaghetti code. This whole "if this jump there" thing can make the code pretty unreadable after a while.

The Sonic games have a very interesting scheme where each section has a starting address, and these are arranged in a jump table, so each section has an index. A variable indicates the index of the current section, which is coded as a routine, and the main loop simply jumps to the indicated routine repeatedly. Each section does whatever it needs, and whenever it's done, it sets the index of the next one and ends itself by returning from the routine.

IMO, coding the different sections of the game as individual routines is a pretty clean way of handling game states, specially if you have different source files for each one.

by on (#42008)
tokumaru wrote:
Game states also help prevent spaghetti code. This whole "if this jump there" thing can make the code pretty unreadable after a while.[/quote
Well, I'd say it helps to avoid spaghetti code instead (but is not sufficient to completely avoid it).

Quote:
IMO, coding the different sections of the game as individual routines is a pretty clean way of handling game states, specially if you have different source files for each one.

That's pretty much exactly what I was saying.