I was able to create the bullets for the game my son and I are working on. I wanted to share my solution in the thread. Please let me know if this is the right approach or if there is a way to improve it.
The first thing I did is to create an offscreen global variable I can use throughout the game:
int offscreen = -100;
I then created a bulletBitmap, and 5 sprite instances for it:
ts_sprite bullet1 = { offscreen, offscreen, 3, 4, 0, bulletBitmap };
ts_sprite bullet2 = { offscreen, offscreen, 3, 4, 0, bulletBitmap };
ts_sprite bullet3 = { offscreen, offscreen, 3, 4, 0, bulletBitmap };
ts_sprite bullet4 = { offscreen, offscreen, 3, 4, 0, bulletBitmap };
ts_sprite bullet5 = { offscreen, offscreen, 3, 4, 0, bulletBitmap };
I added these sprites to the spriteList array, but I also created a playerBulletList array, pointing to the same references. This way I could use the spriteList array just for the drawBuffer function, and keep a separate array to iterate through when I'm updating bullets:
int amtSprites = 6;
ts_sprite * spriteList[6] = { &player, &bullet1, &bullet2, &bullet3, &bullet4, &bullet5 };
int amtPlayerBullets = 5;
ts_sprite * playerBulletList[5] = { &bullet1, &bullet2, &bullet3, &bullet4, &bullet5 };
I then added two global variables:
int playerBulletIndex = 0;
int playerLastShot = 0;
playerBulletIndex allows the function to go through an index of bullets, and know which of the 5 I used last, and the playerLastShot variable records the last time in millis when a bullet was last shot.
Here is the function (added to loop() to run in every cycle):
void playerBulletsMovement() {
//Check if button is pressed
if (checkButton(TAButton1) && millis() > playerLastShot + 400) {
ts_sprite *cb = playerBulletList[playerBulletIndex];
cb->x = player.x;
cb->y = player.y;
playerBulletIndex += 1;
if (playerBulletIndex > 4) playerBulletIndex = 0;
playerLastShot = millis();
}
//Update all bullets
for (int playerBulletIndex = 0; playerBulletIndex < amtPlayerBullets; playerBulletIndex++) {
ts_sprite *cb = playerBulletList[playerBulletIndex];
if (cb->y != offscreen) {
cb->y = cb->y -1;
if (cb->y < 0) cb->y = offscreen;
}
}
}
The first part checks if the player pressed Button1 to fire a shot. But so the player doesn't fire indiscriminately, we only allow the player to fire every .4 of a second. So this part of the function only runs when both of these conditions are met.
if (checkButton(TAButton1) && millis() > playerLastShot + 400)
If the condition is met, the next step is to create a variable in order to access the bullet reference I need:
ts_sprite *cb = playerBulletList[playerBulletIndex];
So the first time the player presses Button1, the program requests the first bullet in the playerBulletList.
Right away I set the position of the bullet (currently offscreen) to be where the player is:
cb->x = player.x;
cb->y = player.y;
And then I move the index to the next bullet I can use:
playerBulletIndex += 1;
But I make sure that if the playerBulletIndex goes beyond the size of the array, then I reset the index to the beginning:
if (playerBulletIndex > 4) playerBulletIndex = 0;
Lastly, I store the time in millis since this shot was executed, so it can be compared by this if statement in every loop cycle:
playerLastShot = millis();
The next part of the function runs in every cycle. It is the part of the function that updates the positions of all the bullets. The structure is inspired in how the drawBuffer function works:
//Update all bullets
for (int playerBulletIndex = 0; playerBulletIndex < amtPlayerBullets; playerBulletIndex++) {
ts_sprite *cb = playerBulletList[playerBulletIndex];
if (cb->y != offscreen) {
cb->y = cb->y -1;
if (cb->y < 0) cb->y = offscreen;
}
}
The for loop goes through all the bullets in the playerBulletIndex. The first thing I do is to create a variable to reference one bullet at a time:
ts_sprite *cb = playerBulletList[playerBulletIndex];
Then I check if the bullet is offscreen (because if it is, there is no need to update it):
if (cb->y != offscreen)
I am making a game where bullets fly vertically, from the bottom to the top of the screen:
cb->y = cb->y -1;
And lastly I check if the bullet has left the screen, to move it to the offscreen area and not update it anymore until it's used again:
if (cb->y < 0) cb->y = offscreen;
And that's it! As a last note, the amount of bullets you need may vary depending on how many you effectively can have on the screen at the same time. Be sure to include enough, but not too many as to not waste memory.
Cheers,