Projectiles (Bullets) using OpenGL/Glut

Compiled using Code::Blocks 13.12 in Ubuntu 14:
Build options -> Linker Settings (Other Linker Options):  -lGL -lGLU -lglut
Properties -> Build Targets (Type): GUI Application

The following code changes and additions are based off the code posted in Movement using OpenGL/Glut.

projectiles
Player shooting projectiles.

New defines, structures, and global variables added.

[code language=”c”]
#define SPACEBAR 32
#define MAX_BULLET_ON_SCREEN 8
#define MAX_VELO_BULLET 5

typedef struct {
    int active;
    double  x, y, dx, dy, bullet_phi;
}  Bullet;

static int shoot = 0;
static Bullet bullets[MAX_BULLET_ON_SCREEN];
[/code]


Addition to void keyboard()
The keyboard() function needed a way to handle the spacebar key input from the player to fire projectiles. It then sets the shoot variable to true (1 in this case), which will be used in moveBullet() to start the firing bullet process.

[code language=”c”]
case KEY_SPACEBAR:
shoot = 1;
break;
[/code]


 

Addition to void myTimer()
myTimer() only needed one modification to it and that was to call the moveBullet().

[code language=”c”]
void myTimer (int value) {

    movePlayer();
    moveBullet();
    checkMapBoundries();

    glutPostRedisplay();
    glutTimerFunc(33, myTimer, value);      /* 30 frames per second */

}
[/code]


New function added – moveBullet();
This is the core of the new functionality for firing a projectile (bullet). When the player presses the spacebar, shoot is set to 1 (or true). As myTimer() is calling moveBullet() is it checking to see if shoot is enabled. If shoot is enabled the function is allowed to progress further, where we check our bullets[] array. Checking through the bullets[] array we are to see if there are any inactive bullets that can be set as active. Once a bullet is able to become active it is then give some properties.

The properties the bullet receives are the current players rotation. The rotation is used to rotate our triangle looking bullet to look like it firing in the right direction. Furthermore, the bullet is given a velocity with the dx and dy values. player.phi is used to fire the bullet in the players current rotation. bullets[i].bullet_phi could be used instead of player.phi; however, I thought it was better to use the player.phi just in case the ordering ever got changed.

Once the calculations are done shoot is set back to 0 (false).

[code language=”c”]
/**
 *  Bullets
 */
void moveBullet () {
    int i = 0;

    // Give the bullets velocity if shoot is true.
    if (shoot == 1) {

         for(i = 0; i < MAX_BULLET_ON_SCREEN; i++) {

            if(bullets[i].active == 0) {
                bullets[i].active = 1;
                bullets[i].x = player.x;
                bullets[i].y = player.y;
                bullets[i].bullet_phi = player.phi;
                bullets[i].dx = -MAX_VELO_BULLET * sin(player.phi);
                bullets[i].dy = MAX_VELO_BULLET * cos(player.phi);
                break;
            }
        }

        // Resets shoot key to prevent rapid fire
        shoot = 0;
    }

    /* Advance bullets and eliminating those that have gone past
     * the window boundaries
     */
    for(i = 0; i < MAX_BULLET_ON_SCREEN; i++) {

        if(bullets[i].active == 1) {
            bullets[i].x = bullets[i].x + bullets[i].dx;
            bullets[i].y = bullets[i].y + bullets[i].dy;
        }
        //Bullet Boundries/ Destory bullet outside boundries
        if(bullets[i].active == 1 && (bullets[i].x > win.width || bullets[i].x < 0 || bullets[i].y > win.height || bullets[i].y < 0)) {
            bullets[i].active = 0;
        }
    }
} // end moveBullet()
[/code]


 

Changes to void display()
This function checks to see if the maximum number of bullets are on screen, if the maximum number is not met then the player is able to fire more bullets. When shoot is fire it enables an bullet in the array, this function goes through the array checking which bullets are active and draws the active bullets.

[code language=”c”]

/**
* The display callback handles exposure events and is called whenever the display must be refreshed.
* Values can be passed to the display callback function only by means of global variables.
*/
void display () {
int i = 0;

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen and Depth Buffer
    glLoadIdentity();
    glTranslatef(0.0f,0.0f,-3.0f);

    drawPlayer(&player);

    // Draws the bullets on screen when they are active
    for (i = 0; i < MAX_BULLET_ON_SCREEN; i++) {
        if (bullets[i].active) {
            drawBullet(&bullets[i]);
        }
    }

    glutSwapBuffers();
}

[/code]


Additional function added – drawBullet()
This function is used in the same way the drawPlayer() function is. It is used for drawing the bullets on the screen and the passed in Bullet pointer is used for determining where the bullet should be fired from and it’s angle.

[code language=”c”]
void drawBullet (Bullet *b) {

    glLineWidth(0.5);
    glColor3f(myRandom(0.7,1.0), 0.0f, 0.0f);
    glPushMatrix();
        myTranslate2D(b->x, b->y);
        myRotate2D(b->bullet_phi);
        myScale2D(1.0f, 1.0f);
        glBegin(GL_TRIANGLES);
            glVertex3f( 0.0f ,  2.0f , 0.0f);   // Top
            glVertex3f(-1.0f , -1.0f , 0.0f);   // Bottom Left
            glVertex3f( 1.0f , -1.0f , 0.0f);   // Bottom Right
        glEnd();
    glPopMatrix();
}
[/code]