There’s quite a few things you could do to save memory.
To select a few to start with:
- You shouldn’t be calling
audio.on()
in setup()
because that forces the sound on and ignores the user’s sound preferences.
- You don’t need to call
audio.begin()
because arduboy.begin()
already does that.
- You don’t need an
audio
object at all, because arduboy
already has one: arduboy.audio
- (This actually won’t save you any memory because the compiler will be getting rid of the
audio
object anyway.)
- You don’t need an
enable_audio
because you can use arduboy.audio.enabled()
instead.
- In cases where you are doing
if(/*something*/) { tinyfont.print("something"); } else { tinyfont.print("something"); }
it should be cheaper to replace that if
-else
with the conditional operator ?
-:
- E.g. instead of
if (enable_audio) { tinyfont.print("Y"); } else { tinyfont.print("N"); }
you can do: tinyfont.print(arduboy.audio.enabled() ? "Y" : "N");
, which should use less memory. (I.e. 1 function call instead of 2.)
- The same trick may apply in other circumstances, e.g. instead of
if (player.is_super) { super_player_frame_position = 22; } else { super_player_frame_position = 0; }
it may be cheaper to do super_player_frame_position = player.is_super ? 0 : 22;
.
- If you’re using the
FX
library then you shouldn’t be calling arduboy.display()
, you should only be calling FX::display()
.
- See here for more information.
- If you’re using
FX::display(CLEAR_BUFFER)
instead of FX::display()
then you don’t need to call arduboy.clear()
.
- To save RAM instead of progmem, you should wrap your string literals (e.g.
"Y"
, "N"
, "SOUND:"
, etc.) with the F
macro (e.g.F("Y")
, F("N")
, F("SOUND:")
, etc.). The reason for this is quite technical, but basically the F
forces the string to stay in progmem.
The biggest saving you could possibly make would actually be to restructure your code so that you’re not doing while(!arduboy.nextFrame())
everywhere or calling FX::display(CLEAR_BUFFER)
multiple times and instead using a proper state machine.
Basically instead of doing if(game_stage == STAGE_GAME_TITLE)
and then title_screen()
having a loop inside, you should be doing something more like:
void loop()
{
// If it's not time to draw the next frame
if(!arduboy.nextFrame())
// Exit the loop function
return;
// Update the button states
arduboy.pollButtons();
// Check the current game state
switch(game_stage)
{
// If the current game state is 'game title'
case STAGE_GAME_TITLE:
// Call the function that updates and draws the titlescreen
title_screen();
break;
// If the current game state is 'play game'
case STAGE_PLAY_GAME:
// Call the function that updates and draws the gameplay
play_game();
break;
}
// Update the screen and clear the screen buffer
FX::display(CLEAR_BUFFER);
}
Crucially those title_screen()
and play_game()
functions should not get stuck in a loop. They should:
- Update the game logic
- Draw all the things they need to draw
- Return, either explicitly or by reaching the bottom of the function
By doing things that way, you should never need to call arduboy.nextFrame()
, arduboy.pollButtons()
, or FX::display()
more than once.
(You may also find this post useful.)
If, after reading that, you’re wondering how you would adapt something like:
do {
// Blah blah blah
} while (!exit_loop);
And
if (arduboy.justPressed(A_BUTTON)) {
exit_loop = true;
}
The answer is: with states.
Instead of having the do
-while
, you allow control to reach the bottom of the function so it goes back to loop()
, and then when loop()
is called again, control will go back to title_screen()
and everything will happen again without title_screen()
needing a loop inside it.
When you’re ready to leave that loop, you just do game_stage = STAGE_PLAY_GAME;
.
In your case, it looks like you’re intending to only call prepare_level_parameters();
when the title screen has ended, so I think you would want:
if (arduboy.justPressed(A_BUTTON))
{
game_stage = STAGE_PLAY_GAME;
prepare_level_parameters();
}
By setting game_stage
and reaching the end of title_screen()
and then the end of loop()
, the next time loop()
begins, instead of going to title_screen()
it goes to play_game();
because game_stage
is then STAGE_PLAY_GAME
, not STAGE_GAME_TITLE
.
Does that all make sense?
Do you have any questions?
(Unfortunately I don’t know any Polish.)