Ok, fair enough, Iād forgotten about that one.
Itās fine that you used it, but my example there was a very quickly made example for the sake of demonstration and it could have been much better.
E.g. that int N
should be size_t capacity
, the (void)
s should be ()
, the brackets should be on separate lines and some of those functions could be constexpr
, and most importantly I should have included a licence with it.
I have some better examples somewhere, but every time I try to make a utility library with useful 'collection types (array, list, stack, queue et cetera) I fall into the feature creep trap and end up implementing a large chunk of the C++ standard libraryā¦
Thereās quite a few things you could do, but Iāll just focus on a few for now.
sounds variable and 'String'
Firstly, instead of making sounds
a String
,
youād be better off getting rid of sounds
and then doing something likeā¦
arduboy.print(F(" B - Sound: "));
arduboy.print((arduboy.audio.enabled()) ? F("on") : F("off"));
Then you can just have:
// B Button Toggle Sound On/Off
if (arduboy.justPressed(B_BUTTON)) {
arduboy.audio.toggle();
}
And youāve saved yourself a lot of processing,
some of which is quite expensive.
String
is quite an expensive type, so you should aim to avoid it, or ideally to never have to use it.
Itās expensive because it does something called ādynamic allocationā,
which can cause problems on devices with very small amounts of memory like the Arduboy.
'Sprites' and explosions
Secondly, you could combine your explosion images into a single image,
then make use of Sprites
ā frame
parameter.
E.g. replace explosion_1
through explosion_5
with
//Explosion
unsigned char const explosions[] PROGMEM
{
// Width, Height
8, 8,
// Frame 0
0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3,
// Frame 1
0xc3, 0xc3, 0xc1, 0x0c, 0x0c, 0x00, 0xc3, 0xc3,
// Frame 2
0xc3, 0xc3, 0x4c, 0x0c, 0x30, 0x30, 0xc3, 0xc3,
// Frame 3
0xf3, 0xf3, 0xcc, 0xcc, 0x33, 0x33, 0xcf, 0xcf,
// Frame 4
0xff, 0xff, 0xfc, 0xfc, 0x33, 0x33, 0xff, 0xff,
};
Then you can modify draw_explosion
to be:
void draw_explosion()
{
sound.tones(explosion_sound);
const auto x = (Zones[bullet_zone].area[bullet_area].x - 4)
const auto y = (Zones[bullet_zone].area[bullet_area].y - 4);
for(uint8_t frame = 0; frame < 5; ++frame)
{
Sprites::drawOverwrite(x, y, explosions, 0);
arduboy.display();
delay(20);
}
}
Zones setup
Thirdly, something Iāll mention but I wonāt demonstrate just yet (hopefully Iāll demonstrate later or tomorrow if I can find some time).
In your setUpZones
function, instead of having a long list of assignments,
what you ought to be able to do is to store the default arrangement of Zones
in progmem and then use memcpy_P
to copy that into your zones
array.
Doing a full copy from progmem into RAM should work out cheaper than having lots of individual assignments.
(Thatās not always true, but itās usually true.)
Scoped enums
Fourthly, you should prefer to use an enum class
(āscoped enumā) instead of an enum
(āplain enumā) because enum class
es are ātypesafeā and wonāt cause name clashes.
(You can read more about that here,
but donāt follow their example of using āall capsā for enumerators.)
In your case this would mean doing something like:
enum class GameState
{
Title,
Gameplay,
Lose,
Pause,
};
GameState gameState;
And then in your state switch
your cases would be more like case GameState::Title:
, case GameState::Gameplay
et cetera.
The problem with delay
Finally, ideally you should avoid making your game rely on delay
because doing so gives the game an unsteady framerate, blocks input updating and can cause other problems,
but designing a game without delay
can be difficult and changing your game to avoid delay
would take quite a lot of effort,
so I wonāt discuss that now, instead Iāll say that for your next game you should try to avoid using delay
to see if you can manage it.
If you canāt then donāt worry too much,
but avoiding delay
is what the vast majority of games do because of how a typical game loop works.
Thereās a nice article about game loops here,
and a companion article about having an update function here.
Itās mainly aimed at general computer game development,
so some things either donāt apply to Arduboy or have different nuances,
but most of it is applicable so itās worth reading if you have time.
I can think of a few more things,
or at least some other places you could apply this advice to,
but I wonāt discuss any more suggestions at the moment because I donāt want to bombard you with too much information.
That should give you more than enough to contemplate for the moment.
Feel free to ask questions if you have any.