This post is a portion of Part 5 in my on going series about 2D Game Development using the Allegro 5 library. These posts are in course order. You can see all of the posts in this course by clicking the “2D Game Development” button at the top of this site.
- 5.0 – Our First Game
- 5.1 – Our First Game: The Player
- 5.2 – Our First Game: Timing and Movement
- 5.3 – Our First Game: The Projectiles
- 5.4 – Our First Game: The Enemies
- 5.5 – Our First Game: Collision Detection
- 5.6 – Our First Game: Game Logic
- 5.7 – Our First Game: Conclusion
In this video we begin looking at our projectile object. Different from the player object, the projectile needs to handle being updated automatically.
Full source can be found here.
Notice that the source code is slightly different from the video? Here is why.
Great tutorial, I just have a quick question. I noticed that when I run my game, if I am moving the ship diagonally, it won’t fire bullets. Is this just because of the simplified game loop, or did I make a mistake?
Ok, edit, to my question. It doesn’t fire when moving Up/left or down/right diagonally. It works with up/right and down/left.
Both work for me. Can we see your code?
When you were unable to shoot while moving diagonally, had you already fired 5 shots? Remember, only 5 shots can exist at a time. When I tried this hitting the space bar quickly, I was unable to shoot at a certain point because there were already 5 live bullets.
Hi Mike,
I’m also having the same problem when I try to shoot some bullets while moving up/left diagonally. That’s the only problem I noticed.
I think some (laptop)keyboards do not allow you to push 3 keys at a time. Try to use an USB keyboard to do it.
It doesn’t seem to be because there are too many bullets on the screen. Here’s my code:
#include
#include
#include “gameIDS.h”
//global
const int WIDTH = 800;
const int HEIGHT = 400;
enum KEYS {UP, DOWN, LEFT, RIGHT, SPACE};
bool keys[5] = {false, false, false, false, false};
const int NUM_BULLETS = 5;
const int NUM_COMETS = 10;
//prototypes
void init_ship(spaceship &ship);
void draw_ship(spaceship &ship);
void move_left(spaceship &ship);
void move_right(spaceship &ship);
void move_up(spaceship &ship);
void move_down(spaceship &ship);
void init_bullet(Bullet bullet[], int size);
void draw_bullet(Bullet bullet[], int size);
void fire_bullet(Bullet bullet[], int size, spaceship &ship);
void update_bullet(Bullet bullet[], int size);
int main(void) {
// primitive variables
bool done = false;
bool redraw = true;
const int FPS = 45;
//object variables
spaceship ship;
Bullet bullets[5];
//allegro variables
ALLEGRO_DISPLAY *display = NULL;
ALLEGRO_EVENT_QUEUE *queue = NULL;
ALLEGRO_TIMER *timer = NULL;
//init functions
if(!al_init()) {
return -1;}
display = al_create_display(WIDTH, HEIGHT);
if(!display) {
return -1;}
queue = al_create_event_queue();
if(!queue) {
return -1;}
timer = al_create_timer(1.0 / FPS);
al_init_primitives_addon();
al_install_keyboard();
init_ship(ship);
init_bullet(bullets, NUM_BULLETS);
al_register_event_source(queue, al_get_keyboard_event_source());
al_register_event_source(queue, al_get_timer_event_source(timer));
al_register_event_source(queue, al_get_display_event_source(display));
al_start_timer(timer);
while(!done) {
ALLEGRO_EVENT ev;
al_wait_for_event(queue, &ev);
if (ev.type == ALLEGRO_EVENT_TIMER) {
redraw = true;
if(keys[UP]) {
move_up(ship);}
if(keys[DOWN]) {
move_down(ship);}
if(keys[LEFT]) {
move_left(ship);}
if(keys[RIGHT]) {
move_right(ship);}
update_bullet(bullets, NUM_BULLETS);
}
else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
done = true;
break;
}
if(ev.type == ALLEGRO_EVENT_KEY_DOWN)
{
switch(ev.keyboard.keycode) {
case ALLEGRO_KEY_ESCAPE:
done = true;
break;
case ALLEGRO_KEY_UP:
keys[UP] = true;
break;
case ALLEGRO_KEY_DOWN:
keys[DOWN] = true;
break;
case ALLEGRO_KEY_LEFT:
keys[LEFT] = true;
break;
case ALLEGRO_KEY_RIGHT:
keys[RIGHT] = true;
break;
case ALLEGRO_KEY_SPACE:
keys[SPACE] = true;
fire_bullet(bullets, NUM_BULLETS, ship);
break;
}
}
else if(ev.type == ALLEGRO_EVENT_KEY_UP)
{
switch(ev.keyboard.keycode) {
case ALLEGRO_KEY_ESCAPE:
done = true;
break;
case ALLEGRO_KEY_UP:
keys[UP] = false;
break;
case ALLEGRO_KEY_DOWN:
keys[DOWN] = false;
break;
case ALLEGRO_KEY_LEFT:
keys[LEFT] = false;
break;
case ALLEGRO_KEY_RIGHT:
keys[RIGHT] = false;
break;
case ALLEGRO_KEY_SPACE:
keys[SPACE] = false;
break;
}
}
if(redraw && al_is_event_queue_empty(queue)) {
redraw = false;
draw_ship(ship);
draw_bullet(bullets, NUM_BULLETS);
al_flip_display();
al_clear_to_color(al_map_rgb(0,0,0));
}
}
al_destroy_timer(timer);
al_destroy_display(display);
al_destroy_event_queue(queue);
return 0;
}
void init_ship(spaceship &ship) {
ship.x = 20;
ship.y = HEIGHT / 2;
ship.ID = PLAYER;
ship.lives = 3;
ship.speed = 7;
ship.boundx = 6;
ship.boundy = 7;
ship.score = 0;
}
void draw_ship(spaceship &ship) {
al_draw_filled_rectangle(ship.x, ship.y – 9, ship.x + 10, ship.y – 7, al_map_rgb(255,255,255));
al_draw_filled_rectangle(ship.x, ship.y + 9, ship.x + 10, ship.y + 7, al_map_rgb(255,255,255));
al_draw_filled_triangle(ship.x – 12, ship.y – 17, ship.x + 12, ship.y, ship.x – 12, ship.y + 17, al_map_rgb(255,255,255));
al_draw_filled_rectangle(ship.x – 12, ship.y – 2, ship.x + 15, ship.y + 2, al_map_rgb(255,0,0));
}
void move_left(spaceship &ship){
ship.x -= ship.speed;
if(ship.x 300) {
ship.x = 300;}
}
void move_up(spaceship &ship){
ship.y -= ship.speed;
if (ship.y HEIGHT) {
ship.y = HEIGHT;}
}
void init_bullet(Bullet bullet[], int size) {
for(int i = 0; i < size; i++) {
bullet[i].ID = BULLET;
bullet[i].speed = 12;
bullet[i].live = false;
}
}
void draw_bullet(Bullet bullet[], int size){
for(int i = 0; i < size; i++) {
if(bullet[i].live) {
al_draw_filled_circle(bullet[i].x, bullet[i].y, 4, al_map_rgb(255,0,0)); }
}
}
void fire_bullet(Bullet bullet[], int size, spaceship &ship){
for(int i = 0; i < size; i++) {
if(!bullet[i].live) {
bullet[i].x = ship.x + 17;
bullet[i].y = ship.y;
bullet[i].live = true;
break; }
}
}
void update_bullet(Bullet bullet[], int size){
for(int i = 0; i WIDTH)
bullet[i].live = false;
}
}
}
by the way, the “update bullet” function actually looks like this. the comment messed it up.
void update_bullet(Bullet bullet[], int size){
for(int i = 0; i WIDTH)
bullet[i].live = false;
}
}
}
What OS are you using?
Copy and paste butchered your code. Could you email it to me (check contacts page) and I can get a better look at it?
I was wondering: Why doesn’t holding the space bar down result in multiple shots being fired. From my understanding of the code it should.
Doesn’t the event ALLEGRO_EVENT_KEY_DOWN fire every tick as long as you press the space bar, and shouldn’t that result in several shots?
If not; what kind of modification would make it possible to fire rapidly only by holding the space bar?
The event only fires off once, when the key is pressed. If you would like continuous state, just store it in an array like I do with the rest of the keys.
I tried typing the code in again from scratch, but I’m still experiencing the same problem when I try to shoot bullets while moving up/left(diagonal). Is there any particular reason that would happen Mike? Is there any particular solution?
Someone had that issue before and we fixed it, but I don’t remember how.
That’s alright. Thanks anyway =)
I modified my code to use mouse input instead.
I also had this problem, I googled around and apparently its a hardware limitation on some keyboards that won’t allow certain combinations of keys to be pressed all at once. I modified the code to use LCTRL instead of space for firing, and everything worked perfectly. Oh, and btw thanks for the great tutorials :).
void init_bullet(Bullet bullet[], int size) {
for(int i = 0; i < size; i++) {
bullet[i].ID = BULLET;//I really dont know where this BULLET variable is declared?
bullet[i].speed = 12;
bullet[i].live = false;
}
Oh, i see, BULLET=1 from the .h file
Jeje I´m having some problems because
I´m coding all with variables in spanish
and a change in the function names :p
México
Sorry for the 3 post, I cant edit 🙁
I have the problem of shoot while moving diagonally too,
only works up/right :O i think its keyboard problem,
like sometimes you cant press more than 3 keys.
hi mike, that is the way how to let the enemies shot directly to your ship, modified bresenhalm algorithm, extremely fast bullet trajectory computing. i can share with you my entire solution, maybe i miss something, it’s old code, send me mail. so you can use it in your tutorials. maybe allegro have better routines, i don’t know. anyway keep up good work.
typedef struct SDeltaGen
{
public:
BOOL fSwap;
int xf;
int yf;
int dx;
int dy;
int d;
int incx;
int incy;
int inc1;
int inc2;
} *LPDELTAGEN;
void DeltaGen( LPDELTAGEN pdg, int* px, int* py )
{
static int* pnT;
if( pdg->fSwap )
{
pnT = px;
px = py;
py = pnT;
}
*px += pdg->incx;
if ( pdg->d d += pdg->inc1;
else
{
*py += pdg->incy;
pdg->d += pdg->inc2;
}
}
BOOL CSprite::DeltaGenInit( LPDELTAGEN pdg, int x0, int y0, int xf, int yf, int* px, int* py )
{
int nT;
pdg->xf = xf;
pdg->yf = yf;
if( x0 == xf && y0 == yf )
return FALSE;
if( xf >= x0 )
pdg->incx = 1;
else
pdg->incx = -1;
if(yf >= y0)
pdg->incy = 1;
else
pdg->incy = -1;
pdg->dx = (xf – x0) * pdg->incx;
pdg->dy = (yf – y0) * pdg->incy;
if( pdg->dy > pdg->dx )
{
nT = pdg->dy;
pdg->dy = pdg->dx;
pdg->dx = nT;
nT = pdg->incx;
pdg->incx = pdg->incy;
pdg->incy = nT;
pdg->fSwap = TRUE;
}
else
pdg->fSwap = FALSE;
pdg->inc1 = pdg->dy <inc2 = (pdg->dy – pdg->dx) <d = pdg->inc1 – pdg->dx;
pdg->xf = xf;
pdg->yf = yf;
*px = x0;
*py = y0;
return TRUE;
}
Hey Mike!
I am following your toturials will all my interesst, and i come to a stage their i wanna try to remake the normal projectile so instead of 1 there will be 3.
One goes straight ahead as yours do and the other two goes bullet.y –; / bullet.y ++; .
But i can’t make it work, and i dunno how to start, would you assist me with some code or some clues atleast.
Greetings a newstarted programmer
How do i make the projectile shoot towards my mouse
Check out the sprite “Gravity Demo” in my series. There is an equation in there called angular velocity. Use that.
I tried to modify the number of bullets that can be shot at a time.
i changed the NUM_BULLETS from 5 to 7.
Then my “Ship” started in a Corner and i only could move it up or down 🙁
and when i close the game an error appears:
“Run-Time Check Failure #2 – Stack around the variable “bullets” was corrupted…
any ideas?
using win7 and VS 2010 express
Problem is solved due to explanations in the next part 😉
Hi, I’m trying to modify the code to shoot based on the direction the ship is facing but am running into a problem. If I face my ship left, I shoot left but then if I change direction the ship is facing, the
bullet changes to that direction.
I’ve tried playing around but had no luck.
Are there any ways you suggest to fix this? I was adding the direction under here. Thanks very much for your help
else if(ev.type == ALLEGRO_EVENT_KEY_DOWN)
{
switch(ev.keyboard.keycode)
{
case ALLEGRO_KEY_ESCAPE:
done = true;
break;
case ALLEGRO_KEY_UP:
keys[UP] = true;
playerFacing = 8;
break;
case ALLEGRO_KEY_DOWN:
keys[DOWN] = true;
playerFacing = 2;
break;
case ALLEGRO_KEY_LEFT:
keys[LEFT] = true;
playerFacing = 4;
break;
case ALLEGRO_KEY_RIGHT:
keys[RIGHT] = true;
playerFacing = 6;
break;
hello, i was wondering if you can help me make it so that the bullet fires non stop when i hold down space, i read one of your other comments about making it an array but im a recently new programmer and i don’t quite get it
would you be able to explain how to do it please, thank you before hand
Howdy, it already is an array. You could make it so that every update cycle, if the space bar is down it just fires (spawns a new bullet)
I hope this helps
thanks for the quick reply, would you be able to explain to me how to make it do that as i dont quite understand …. im really new to programing xD
Hi, I don’t speak english very well and I might not have hear it but i don’t understand why we need live boolean array. Can you explain it to me?
If we have an array of 5 lives does it mean that ther can be only five bullets on the screen at once?