More "elegant" solution to many bullets on screen at once? [Solved]

Recently I’ve been working on a space-themed shoot-'em-up style game, which you may have seen in this post: Space shooter meets Flappy Bird [WIP]. I’ve gotten a good start but the one thing that I keep getting stuck on is all the bullets that’ll be on screen at once. Is there some way (more efficient than over-declaring the bullet variables to ensure that there’s enough space for all of them) to only declare the struct for each bullet as necessary, and if so can anybody show me how to do that? The code is here:

#include <Arduboy2.h>
#include "sprites.h"
Arduboy2 arduboy;

#define gravity 1

int shipX = 8;
int shipY = 32;
int animTimer = 0;
int bg1X = 0;
int bg2X = 127;
bool bulletFired1 = false;
bool bulletFired2 = false;
bool bulletFired3 = false;

struct Bullets {
  int x;
  int y;
};

struct Bullets Bullet1;
struct Bullets Bullet2;
struct Bullets Bullet3;

void setup() {
  arduboy.begin();
  arduboy.setFrameRate(60);
}

void loop() {
  //Code for display
  if (!(arduboy.nextFrameDEV())) {
    return;
  };
  if (arduboy.everyXFrames(10)) {
    if (animTimer == 0) {
      animTimer++;
    } else {
      animTimer = 0;
    }
  } arduboy.clear();


  //Code for inputs and ship movement
  arduboy.pollButtons();
  if (arduboy.pressed(A_BUTTON) && shipY > 1) {
    shipY = shipY - 1;
  };
  if (arduboy.notPressed(A_BUTTON)) {
    if (arduboy.everyXFrames(2)) {
      if (shipY < 57) {
        shipY = shipY + gravity;
      } else if (shipY >= 57) {
        shipY = 57;
      }
    }
  };


  //Code for weapon firing and travel
  if (arduboy.justPressed(B_BUTTON) && bulletFired1 == false) {
    Bullet1.x = shipX + 5;
    Bullet1.y = shipY + 3;
    bulletFired1 = true;
  } else if (arduboy.justPressed(B_BUTTON) && bulletFired2 == false) {
    Bullet2.x = shipX + 5;
    Bullet2.y = shipY + 3;
    bulletFired2 = true;
  } else if (arduboy.justPressed(B_BUTTON) && bulletFired3 == false) {
    Bullet3.x = shipX + 5;
    Bullet3.y = shipY + 3;
    bulletFired3 = true;
  };
  if (bulletFired1 == true && Bullet1.x < 127) {
    Bullet1.x = Bullet1.x + 3;
  } else {
    bulletFired1 = false;
  };
  if (bulletFired2 == true && Bullet2.x < 127) {
    Bullet2.x = Bullet2.x + 3;
  } else {
    bulletFired2 = false;
  };
  if (bulletFired3 == true && Bullet3.x < 127) {
    Bullet3.x = Bullet3.x + 3;
  } else {
    bulletFired3 = false;
  };


  //Code for backgrounds
  if (bg1X > -127) {
    bg1X = bg1X - 1;
  } else if (bg1X <= -127 && bg2X < 0) {
    bg1X = 127;
  };
  if (bg2X > -127) {
    bg2X = bg2X - 1;
  } else if (bg2X <= -127 && bg1X < 0) {
    bg2X = 127;
  };
  if (arduboy.everyXFrames(2)) {
    arduboy.drawBitmap(bg1X, 0, stars, 128, 64);
    arduboy.drawBitmap(bg2X, 0, stars, 128, 64);
  };


  //Code for drawing the ship
  if (animTimer == 0) {
    arduboy.drawBitmap(shipX, shipY, ship1, 14, 6);
  } else if (animTimer == 1) {
    arduboy.drawBitmap(shipX, shipY, ship2, 14, 6);
  };


  //Draw the bullets and display
  if (bulletFired1 == true) {
    arduboy.drawFastHLine(Bullet1.x, Bullet1.y, 3, WHITE);
  };
  if (bulletFired2 == true) {
    arduboy.drawFastHLine(Bullet2.x, Bullet2.y, 3, WHITE);
  };
  if (bulletFired3 == true) {
    arduboy.drawFastHLine(Bullet3.x, Bullet3.y, 3, WHITE);
  };
  arduboy.display();
}

You always have to account for worst case scenarios, so you have to have enough storage available for the maximum bullets that could ever be in use at any given time. Therefore, you may as well just allocate an array of bullet objects for this maximum number, even if having them all in use is rare.

However, you may instead want to have a maximum total number of objects including bullets. This would mean that the maximum number of bullets would be less if other objects were in use. In this case, you could allocate an array of objects for the maximum total objects and have a member of the object indicate what specific type of object it is.

This topic may be of some use:

1 Like

A small tip to save you some typing: you only need the struct part when you first declare the struct, afterwards you can just use the type name as normal:

struct Bullets
{
  int x;
  int y;
};

Bullets bullet1;
Bullets bullet2;
Bullets bullet3;

I’m guessing you’ve accidentally beeng reading C tutorials instead of C++ tutorials.
(They are not the same language. Not by a long shot.)

I think what you really want to ask is “do I really have to write a line of code for every bullet?”. :P

The answer to that is ‘no’. As @MLXXXp said, you can use these things called arrays:

struct Bullets
{
  int x;
  int y;
};

// 10 Bullets, 1 declaration
Bullets bullets[10];

(To save yourself even more typing, you might want to make fired part of the bullet, so you don’t need a load of separate ‘fired’ variables.)

If you’re still stuck after reading the linked thread, feel free to ask more questions, but try your best to be very specific about what you’re having trouble with.

1 Like

Okay, thanks! I think this’ll help with my problem.

1 Like

AAANNDDD… Fixed! Thank you so much for helping with my problem! Uploading the new .hex now!

2 Likes