GBA C++: How to draw multiple animating pixels using arrays?

328 views Asked by At

I am coding a game for a GBA emulator modeled on the classic arcade game 'Phoenix' in which a ship fires bullets up at targets above it. I currently have the game working fine except I want to be able to fire multiple bullets at once.

I created a smaller source file simply to test how I might do this, so there are no bricks or ship etc, only an origin for the bullets and a background colour.

I have tried to create a "magazine" for the ship that contains five bullets by creating an array of 5 'bullet' structures, each containing their own x and y coordinate. Each bullet also has assigned to it a boolean flag to determine if it is fired or not, allowing a loop to search through the arrays when A is pressed to find a bullet that has not yet been fired, and fire it.

I thought that this would work, but as I am a beginner I feel I may have missed something. When it is run, I can fire one bullet, and it animates up the screen as intended, but I cannot fire a second until this first one is off the screen and its flag reset to 'false.'

Perhaps you could help me spot the problem in my code?

Thank you.

#include <stdint.h>
#include "gba.h"

const int MAG_SIZE = 5;
bool bulletFired[MAG_SIZE] = {false};

struct bullet {
    int x;
    int y;
} bullet[MAG_SIZE];


bool isPressed(uint16_t keys, uint16_t key)
{ // Uses REG_KEYINPUT and a specified key mask to determine if the key is pressed

    return (keys & key) == 0; 
}

void DrawBullet(int bulletXPos, int bulletYPos)
{ // Fires bullet from player craft

    PlotPixel8(bulletXPos, bulletYPos, 2);
}

int main() 
{

    REG_DISPCNT = MODE4 | BG2_ENABLE;

    bool isPressed(uint16_t keys, uint16_t key);  
    void DrawBullet(int bulletXPos, int bulletYPos);    

    SetPaletteBG(0, RGB(0, 0, 10)); // Blue
    SetPaletteBG(1, RGB(31, 31 ,31)); // White
    SetPaletteBG(2, RGB(25, 0, 0)); // Red

    ClearScreen8(0);

    while (true)
    {

        WaitVSync();

        ClearScreen8(0);

        uint16_t currKeys = REG_KEYINPUT;

         for (int n = 0; n < 5; n++)
        {
            if ( bulletFired[n] )
            {
                bullet[n].y--;
                DrawBullet(bullet[n].x, bullet[n].y);

                if ( bullet[n].y < 1 )
                {
                    bulletFired[n] = false;
                }
            }
        }


        if (isPressed(currKeys, KEY_A))
        { // Key A is pressed
            for (int n = 0; n < 5; n++)
            {
                if ( !bulletFired[n] )
                {
                    bulletFired[n] = true;
                    bullet[n].x = 120;
                    bullet[n].y = 134;
                }   
            }
        } 

        FlipBuffers();
    }

    return 0;
}
1

There are 1 answers

1
Stephan van den Heuvel On BEST ANSWER

The problem is here

if (isPressed(currKeys, KEY_A))
    { // Key A is pressed
        for (int n = 0; n < 5; n++)
        {
            if ( !bulletFired[n] )
            {
                bulletFired[n] = true;
                bullet[n].x = 120;
                bullet[n].y = 134;
            }   
        }
    }

When you detect a key press, you fire all available bullets at once.

You want something like:

    if (isPressed(currKeys, KEY_A))
    { // Key A is pressed
        for (int n = 0; n < 5; n++)
        {
            if ( !bulletFired[n] )
            {
                bulletFired[n] = true;
                bullet[n].x = 120;
                bullet[n].y = 134;
                //EXIT THE LOOP
                break;
            }   
        }
    }

To break out of the loop. You also probably want to insert a time delay between firing bullets, or waiting for a full key press, because you will still probably fire the bullets very quickly.