Controller Input Subroutines: How many?

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

User avatar
MetalSlime
Posts: 186
Joined: Tue Aug 19, 2008 11:01 pm
Location: Japan

Controller Input Subroutines: How many?

Post by MetalSlime »

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?
Celius
Posts: 2159
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius »

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.
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

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.
UncleSporky
Posts: 388
Joined: Sat Nov 17, 2007 8:44 pm

Post by UncleSporky »

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: Select all

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.
Celius
Posts: 2159
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius »

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.
User avatar
MetalSlime
Posts: 186
Joined: Tue Aug 19, 2008 11:01 pm
Location: Japan

Post by MetalSlime »

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: Select all

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: Select all

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: Select all

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: Select all

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!
Celius
Posts: 2159
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius »

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.
User avatar
MetalSlime
Posts: 186
Joined: Tue Aug 19, 2008 11:01 pm
Location: Japan

Post by MetalSlime »

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?
MetalSlime runs away.
Celius
Posts: 2159
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius »

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.
User avatar
Bregalad
Posts: 8036
Joined: Fri Nov 12, 2004 2:49 pm
Location: Caen, France

Post by Bregalad »

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: Select all

_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).
Useless, lumbering half-wits don't scare us.
UncleSporky
Posts: 388
Joined: Sat Nov 17, 2007 8:44 pm

Post by UncleSporky »

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

Code: Select all

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.
User avatar
Bregalad
Posts: 8036
Joined: Fri Nov 12, 2004 2:49 pm
Location: Caen, France

Post by Bregalad »

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.
Useless, lumbering half-wits don't scare us.
User avatar
MetalSlime
Posts: 186
Joined: Tue Aug 19, 2008 11:01 pm
Location: Japan

Post by MetalSlime »

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: Select all

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!)
UncleSporky
Posts: 388
Joined: Sat Nov 17, 2007 8:44 pm

Post by UncleSporky »

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

Code: Select all

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: Select all

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.
User avatar
Bregalad
Posts: 8036
Joined: Fri Nov 12, 2004 2:49 pm
Location: Caen, France

Post by Bregalad »

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.
Useless, lumbering half-wits don't scare us.
Post Reply