Problem with "wait until the user press START"

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

Post Reply
ludoVIC
Posts: 31
Joined: Fri Jan 08, 2021 8:36 am

Problem with "wait until the user press START"

Post by ludoVIC » Fri Jan 22, 2021 12:14 pm

Hello people, I am following the Nerdy Nights tutorials, basic sections, and trying to modify some code in order to get a better understanding.
Sadly, I am stuck with an example and I don't manage to see the mistake by my own.

The exercise is in principle very simple:
1) set the background to green
2) wait until the user press START
3) set the bg to blue
4) wait until the user press START
5) set the bg to red

The problem is: my code seems to go from (2) directly to (5), ignoring the waiting in the between.
In other words, when start is pressed, the background goes directly from green to red, while I expect to have the pause with the blue picture.
I know that I omitted the classic "memory clear" at the beginning, but I doubt that the problem lies there.

Meanwhile, I noticed another related problem.
I tried to debug my code with fceux, the emulator I am currently using, but, when in debug mode, what is the best way to handle the controller input?

My code is attached, including the assembler (original NESASM3.zip file), the needed "mario.chr" file (unused but needed to assemble) and the .nes.
Thank you in advance for any kind of feedback!
Attachments
NESASM3.zip
(40.92 KiB) Downloaded 19 times
wait_start.nes
(24.02 KiB) Downloaded 19 times
wait_start.asm
(1.3 KiB) Downloaded 18 times
mario.chr
(8 KiB) Downloaded 19 times

User avatar
tokumaru
Posts: 12003
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Problem with "wait until the user press START"

Post by tokumaru » Fri Jan 22, 2021 1:20 pm

Not having looked at the code (pardon my laziness), I assume that you're not frame-limiting your program, which means that when you press start it blasts trough the blue state and reaches the red state before it has time to display the blue.

If that's the case, there are two things you can do:

1- Frame-limit you program: the NES generates pictures at 60fps, and games work by animating everything in the scene bit by bit between frames. For this to work, you have update the game state by one logic frame, wait for that frame to be displayed, then do the update for the next frame, and repeat this forever. If you don't wait for frames to be displayed, you're gonna process several logic frames at once. In your program, the work you have to do each frame is: read the controller, then decide whether to change the color. You're supposed to do this only once per frame, otherwise you'll change the color more than once per frame and not see all the changes. The exact method you can use to implement frame-limiting will vary depending on the program structure you're using (all in NMI, all in main or main + NMI). All in NMI practically gives you free frame-limiting, just do the work of one frame and RTI - your game loop will be called once per frame automatically. All in main requires you to wait for the NMI to fire before looping back and executing another iteration of your game loop. This is commonly achieved by incrementing a counter in the NMI handler (e.g. INC FrameCounter) and waiting for that counter to change in the main thread. For example:

Code: Select all

GameLoop:

  ;do the work of 1 frame here

  lda FrameCounter
Wait:
  cmp FameCounter
  beq Wait

  jmp GameLoop
This solution also works for the main + NMI program structure.

2- Check for changes in the input, not the immediate state of the buttons: even if you frame-limit your program to process input only once per frame, the vast majority of players will hold buttons down for longer than a frame, meaning that the screen would be blue for a single frame, and then red, since start would be pressed for 2 consecutive frames. The solution to that is to trigger the color changes only button transitions from not pressed to pressed, so you can only change colors again if you release the button and press it again. In your program, the simplest way to do that is to save the previous state of the button to another variable before reading the new state, and then check both states when deciding whether to change the color: the old state has to be "not pressed" and the new state has to be "pressed", otherwise, don't change colors. In actual games, there are also actions that should only start on button state changes, such as shooting: you don't want to spawn bullets every frame for as long as the player holds the fire button down, you want to spawn a single bullet in the frame when the button goes from "not pressed" to "pressed" and that's it.

User avatar
tokumaru
Posts: 12003
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Problem with "wait until the user press START"

Post by tokumaru » Fri Jan 22, 2021 1:43 pm

I checked your code and the program is simpler than I expected (there isn't an actual game loop yet), but you're indeed not waiting any time between detecting the first keypress and the second, meaning you'll blast through the blue state so fast that you don't even have time to see it.

The quickest fix here is very simple: before waiting for the second keypress, wait for the button to be released before waiting for it to be pressed again (e.g. make a "WaitForNoStart" subroutine that tests the opposite condition, and returns only when start is NOT pressed, then call that subroutine between the 2 color changes).

ludoVIC
Posts: 31
Joined: Fri Jan 08, 2021 8:36 am

Re: Problem with "wait until the user press START"

Post by ludoVIC » Tue Jan 26, 2021 10:03 am

Thank you very much! Great answer!
My apologies for being a bit in late: before replying, I wanted to be completely sure to have properly understood all your points.
So I wrote the same exercise multiple times and using all the different approaches, and they worked well :D

Another step is done, thanks again :beer:

Post Reply