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:
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
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.
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.
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.
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.
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:
pressed = current;
current = get_input();
pressed = (pressed ^ current) & current;
or how I actually have it in ASM:
Code:
; 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.
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:
if (pad & PAD_A) {
if (!fire_button_flag) {
fire ();
}
fire_button_flag = 1;
} else fire_button_flag = 0;
For pausing it could be...
Code:
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;
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).
@na_th_an
Sure, but here's what that code would look like using my approach:
Code:
if (pressed & PAD_A) fire ();
Code:
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.
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:
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:
if (pad & PAD_A)
and
Code:
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.
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)
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:
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.
I could implement Nicole's solution using shiru's Neslib. It's as easy as this:
Code:
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.
-Basti- wrote:
Code:
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++.)
thefox wrote:
-Basti- wrote:
Code:
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".
thefox wrote:
-Basti- wrote:
Code:
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++.)
Sorry my bad, I made a mistake when summarizing my problem.
input and
lf_input are written each frame through my input-routine.
I fooled around a bit more with my code and found out, that using function
pad_trigger instead of
pad_poll solves my problem without comparing any input of the last frame.
Could somebody explain the difference between function
pad_trigger and
pad_poll?
While i am optimizing my input routine at the moment, I wonder if C`s switch-case statement is recommendable instead of a large if-statement cascade, when using CC65?
Yeah, switch is much better, because cc65 doesn't really do much optimization. It ends up producing a cmp #imm / jeq @label cascade instead of "calculate lvalue and rvalue and compare and then jump".
Switch also groups everything with the same MSB together, so it'll be better if it collides with C's type promotion.
-Basti- wrote:
Could somebody explain the difference between function pad_trigger and pad_poll?
Ah! It seems that neslib actually already does the method I described (though in a slightly more roundabout way). So, you don't need to calculate that yourself after all, just use
pad_trigger's value, which is equivalent to
pressed.
EDIT: It's worth noting that
pad_trigger seems to call
pad_poll for some reason, though. You should update the variables each frame like this to avoid polling multiple times in a frame, which could make you miss button presses:
Code:
pressed = pad_trigger(0);
pad = pad_state(0);
I use *only* pad_poll and Nicole's method and I can get both button presses which have just been performed during the current frame and button presses which were performed before. I find it more simple.
Code:
while (1) {
pad_this_frame = pad0;
pad0 = pad_poll (0);
pad_this_frame = (pad_this_frame ^ pad0) & pad0;
if (pad0 & PAD_B) {
// PAD B was pressed sometime in the past and it's still down.
}
if (pad_this_frame & PAD_A) {
// PAD A has been pressed *this* frame, and *not* before
}
}
Seems to work fine.