CC65 pause pattern

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

User avatar
-Basti-
Posts: 40
Joined: Sun Sep 26, 2010 10:29 pm

CC65 pause pattern

Post by -Basti- »

Hello,
I am looking for a pattern to implement a pause functionality, using CC65. My current pattern works some kind of random. Some times it pauses the game, sometimes not. In a simplified model, I implemented my pause functionality as follows:

Code: Select all

static unsigned char pause = 0;   /* 0 = no pause, 1 = pause */

void input_routine(void){
  ...
  if(input&PAD_START){
    pause = (pause == 1) ? 0 : 1;
  }
  ...
} 

void main(void){
  ...
  while(1){
    input_routine();
   
     if(!pause){
      update_routine();
     }
    
    render_routine();
    ppu_wait_nmi();
  }
}
I tried out some combinations with the delay()-function, but nothing worked out too well. Can somebody explain, how to implement a pause functionality properly?

Regards
Sebastian
User avatar
thefox
Posts: 3139
Joined: Mon Jan 03, 2005 10:36 am
Location: Tampere, Finland
Contact:

Re: CC65 pause pattern

Post by thefox »

You have to check for "not pressed" => "pressed" transition, otherwise your pause state will keep toggling (0,1,0,1,0,...) while you hold down the button, ending on a more or less random value.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
User avatar
DRW
Posts: 2070
Joined: Sat Sep 07, 2013 2:59 pm

Re: CC65 pause pattern

Post by DRW »

This is something that you should keep in mind for every button: Your controller update function should always save the input of the previous frame in a separate variable before setting the regular input variable. Because there are usually actions that require one button press only and that are not supposed to get repeated when the button is still pressed.

For example, when the character walks, then you just check for left or right.

But when the character jumps, then you check for "button A is pressed in the current frame, but wasn't pressed in the previous frame". Otherwise the character would keep jumping whenever he touches the ground again if the player keeps holding the button.
This might be desired in a fighting game, but games like "Super Mario Bros." require the player to release the button first and pressing it again before doing the next jump.

By the way, don't use the function "delay" in an NES game. Ever. Unless you want your game to lag. But even if a lag is desired (like in a slow motion scene) then I would simply count the frames and skip certain parts of the logic accordingly instead of using a function whose parameter is in the unit of milliseconds.
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg
pstalcup
Posts: 11
Joined: Fri Jul 22, 2016 9:58 am

Re: CC65 pause pattern

Post by pstalcup »

You may want to consider making a simple state machine, instead. Especially if you're going to have multiple screens (inventory, main menu, etc.), a state machine seems like it would make things simpler.

Consider a case where you have multiple pause screens (a la later zelda games, one screen for story progress, one screen for inventory). Having a state machine can drastically simplify your game logic.
na_th_an
Posts: 558
Joined: Mon May 27, 2013 9:40 am

Re: CC65 pause pattern

Post by na_th_an »

I detect the player pushing START in my main loop. If such things happens, I enter the PAUSE subroutine, which:

1.- Waits until START is depressed.
2.- Plays the "PAUSE" sound effect.
3.- Dims the pal a bit.
4.- Pauses the music.
5.- Waits until START is pressed.
6.- Waits until START is depressed again.
7.- Restores the palette bright.
8.- Unpauses the music.

In some games I keep calling some update subroutines during step #5. For example, in Super Uwol I keep calling the routine which makes the coins flip.
Nicole
Posts: 218
Joined: Sun Mar 27, 2016 7:56 pm

Re: CC65 pause pattern

Post by Nicole »

How I handle this is not by just storing the current and previous input, which would require comparing them each time you need to know what was pressed that frame, but by storing the current input and the input pressed this frame.

You could update them each frame with something like this:

Code: Select all

pressed = current;
current = get_input();
pressed = (pressed ^ current) & current;
or how I actually have it in ASM:

Code: Select all

; with new input in a
    tay
    eor current
    sty current
    and current
    sta pressed
Then, checking if Start was pressed this frame is as simple as if (pressed & PAD_START).

na_th_an wrote:5.- Waits until START is pressed.
6.- Waits until START is depressed again.
I'm not sure I'd recommend that approach. It might be okay for pausing, but it's going to feel a little off for actual gameplay, since it introduces input lag for as long as they press the button.
na_th_an
Posts: 558
Joined: Mon May 27, 2013 9:40 am

Re: CC65 pause pattern

Post by na_th_an »

It's for pausing the game, I haven't found any issues. For actual gameplay I use flags to control the buttons, which work great. I could use them in the Pause routine as well, of course, but I didn't find it necessary to over complicate things. I don't mind the lag when stopping or resuming the game.

Code: Select all

if (pad & PAD_A) {
    if (!fire_button_flag) { 
        fire ();
    }
    fire_button_flag = 1;
} else fire_button_flag = 0;
For pausing it could be...

Code: Select all

if (pad_poll (0) & PAD_START) {
    if (!pause_flag) {
        music_pause ();
        palette_dim ();
        pause_flag = 1;
        while (1) {
            ppu_wait_nmi ();
            if (pad_poll (0) & PAD_START) {
                if (!pause_flag) break;
            } else pause_flag = 0;
        }
        palette_restore ();
        music_resume ();
    }
} else pause_flag = 0;
User avatar
DRW
Posts: 2070
Joined: Sat Sep 07, 2013 2:59 pm

Re: CC65 pause pattern

Post by DRW »

Correct me if I'm wrong, but if (pad & PAD_A) could make problems if you ever check for two buttons at once:

if (pad & (PAD_A | PAD_B))
--> Returns true, if only one of the buttons was pressed, even though you'd only want it to return true if both buttons are pressed.

The correct check should be if ((pad & (buttons)) == (buttons)) with buttons being the value that you want to check for (in your case PAD_A or in my case PAD_A | PAD_B).
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg
Nicole
Posts: 218
Joined: Sun Mar 27, 2016 7:56 pm

Re: CC65 pause pattern

Post by Nicole »

@na_th_an
Sure, but here's what that code would look like using my approach:

Code: Select all

if (pressed & PAD_A) fire ();

Code: Select all

if (pressed & PAD_START) {
    music_pause ();
    palette_dim ();
    while (1) {
        ppu_wait_nmi ();
        if (pressed & PAD_START) break;
    }
    palette_restore ();
    music_resume ();
}
That's why I feel like the flag approach is just overcomplicating things.

@DRW
That's correct, yes.
na_th_an
Posts: 558
Joined: Mon May 27, 2013 9:40 am

Re: CC65 pause pattern

Post by na_th_an »

DRW wrote:Correct me if I'm wrong, but if (pad & PAD_A) could make problems if you ever check for two buttons at once:

if (pad & (PAD_A | PAD_B))
--> Returns true, if only one of the buttons was pressed, even though you'd only want it to return true if both buttons are pressed.

The correct check should be if ((pad & (buttons)) == (buttons)) with buttons being the value that you want to check for (in your case PAD_A or in my case PAD_A | PAD_B).
Yeah, that's what I use when I need two or more inputs pressed at once. There's no need for the comparison if you are just checking one button. I don't know if cc65 notices and optimizes it.

Code: Select all

if (pad & (PAD_A | PAD_B))
This is useful when you don't care which button has been pressed. For example, for one button games (like Sonic).

Code: Select all

if (pad & PAD_A)
and

Code: Select all

if ((pad & PAD_A) == PAD_A)
Are 100% equivalent (this is, when PAD_A is power of two, which it is), but I guess the latter generates worse code, unless cc65 is clever and optimizes it.

@Nicole, yes, you are right. Your approach is very clever. It will come handy when detecting the presses for jump or fire.
User avatar
DRW
Posts: 2070
Joined: Sat Sep 07, 2013 2:59 pm

Re: CC65 pause pattern

Post by DRW »

Sure, for one button, there's no difference. It always works. I just wanted to point out a little detail that might be problematic in a specific situation.

And no, CC65 doesn't optimize it.
if (variable & value)
creates smaller code than
if ((variable & value) == value)
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg
User avatar
-Basti-
Posts: 40
Joined: Sun Sep 26, 2010 10:29 pm

Re: CC65 pause pattern

Post by -Basti- »

Sorry for the delay in responding to my post. I actually found some time to try out some of your hints, but nothing worked out well.
My most promising attempt looks like this:

Code: Select all

static unsigned char pause = 0;   /* 0 = no pause, 1 = pause */
static unsigned char input = pad_poll(0);
static unsigned char lf_input = pad_state(0);

void input_routine(void){
  ...
  if(input&PAD_START){
    if(input != lf_input) pause = !pause;
  }
  ...
} 
This doesn't pause my game in any case. The documentation of pad_state says "get previous pad state without polling ports",
so as far as I understand, it can be used to check, whether START was pressed, the frame before.
na_th_an
Posts: 558
Joined: Mon May 27, 2013 9:40 am

Re: CC65 pause pattern

Post by na_th_an »

I could implement Nicole's solution using shiru's Neslib. It's as easy as this:

Code: Select all

pad_this_frame = pad0; 
pad0 = pad_poll (0);
pad_this_frame = (pad_this_frame ^ pad0) & pad0;
You can use the pad0 variable (i.e. "pad0 & PAD_START") to get info about what buttons are pressed. You can use the pad_this_frame variable (i.e. "pad_this_frame & PAD_START") to get info about what buttons have been just pressed _this frame_, and not before.
User avatar
thefox
Posts: 3139
Joined: Mon Jan 03, 2005 10:36 am
Location: Tampere, Finland
Contact:

Re: CC65 pause pattern

Post by thefox »

-Basti- wrote:

Code: Select all

static unsigned char input = pad_poll(0);
static unsigned char lf_input = pad_state(0);
This calls pad_poll/pad_state once during the initialization of the program, not what you want. (I can't even remember if this is valid in C, or only C++.)
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
User avatar
Jarhmander
Formerly ~J-@D!~
Posts: 521
Joined: Sun Mar 12, 2006 12:36 am
Location: Rive nord de Montréal

Re: CC65 pause pattern

Post by Jarhmander »

thefox wrote:
-Basti- wrote:

Code: Select all

static unsigned char input = pad_poll(0);
static unsigned char lf_input = pad_state(0);
This calls pad_poll/pad_state once during the initialization of the program, not what you want. (I can't even remember if this is valid in C, or only C++.)
Yeah, it's valid C++ but not C. The static initializer should be a constant expression because C doesn't support any kind of dynamic initialization for "globals".
((λ (x) (x x)) (λ (x) (x x)))
Post Reply