# Space invaders clone not moving properly

I'm trying to make a basic space invaders clone in allegro 5, I've got my game set up, basic events and such, here is the code:

#include <allegro5/allegro.h>
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_primitives.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_ttf.h>
#include "Entity.h"

// GLOBALS ==========================================
const int width = 500;
const int height = 500;
const int imgsize = 3;
bool key[5] = {false, false, false, false, false};
bool running = true;
bool draw = true;

// FUNCTIONS ========================================
void initSpaceship(Spaceship &ship);
void moveSpaceshipRight(Spaceship &ship);
void moveSpaceshipLeft(Spaceship &ship);
void initBullet(Bullet &bullet);
void fireBullet();
void doCollision();
void drawText();

enum key_t { UP, DOWN, LEFT, RIGHT, SPACE };
enum source_t { INVADER, DEFENDER };

int main(void)
{
if(!al_init())
{ return -1; }

Spaceship ship;
Bullet bullet;

al_install_keyboard();

ALLEGRO_DISPLAY *display = al_create_display(width, height);
ALLEGRO_EVENT_QUEUE *event_queue = al_create_event_queue();
ALLEGRO_TIMER *timer = al_create_timer(1.0 / 60);
ALLEGRO_BITMAP *images[imgsize];
ALLEGRO_FONT *font1 = al_load_font("arial.ttf", 20, 0);

al_register_event_source(event_queue, al_get_keyboard_event_source());
al_register_event_source(event_queue, al_get_display_event_source(display));
al_register_event_source(event_queue, al_get_timer_event_source(timer));

al_convert_mask_to_alpha(images[0], al_map_rgb(0, 0, 0));
al_convert_mask_to_alpha(images[1], al_map_rgb(0, 0, 0));
al_convert_mask_to_alpha(images[2], al_map_rgb(0, 0, 0));

initSpaceship(ship);
initBullet(bullet);

al_start_timer(timer);
while(running)
{
ALLEGRO_EVENT ev;
al_wait_for_event(event_queue, &ev);

if(ev.type == ALLEGRO_EVENT_TIMER)
{
draw = true;
if(key[RIGHT] == true)
moveSpaceshipRight(ship);

if(key[LEFT] == true)
moveSpaceshipLeft(ship);
}

else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
running = false;

else if(ev.type == ALLEGRO_EVENT_KEY_DOWN)
{
switch(ev.keyboard.keycode)
{
case ALLEGRO_KEY_ESCAPE:
running = false;
break;

case ALLEGRO_KEY_LEFT:
key[LEFT] = true;
break;

case ALLEGRO_KEY_RIGHT:
key[RIGHT] = true;
break;

case ALLEGRO_KEY_SPACE:
key[SPACE] = true;
break;
}
}

else if(ev.type == ALLEGRO_KEY_UP)
{
switch(ev.keyboard.keycode)
{
case ALLEGRO_KEY_LEFT:
key[LEFT] = false;
break;

case ALLEGRO_KEY_RIGHT:
key[RIGHT] = false;
break;

case ALLEGRO_KEY_SPACE:
key[SPACE] = false;
break;
}
}

if(draw && al_is_event_queue_empty(event_queue))
{
draw = false;

al_draw_bitmap(images[0], ship.pos_x, ship.pos_y, 0);
al_flip_display();
al_clear_to_color(al_map_rgb(0, 0, 0));
}
}

al_destroy_font(font1);
al_destroy_event_queue(event_queue);
al_destroy_timer(timer);
for(int i = 0; i < imgsize; i++)
al_destroy_bitmap(images[i]);
al_destroy_display(display);
}

// FUNCTION LOGIC ======================================
void initSpaceship(Spaceship &ship)
{
ship.lives = 3;
ship.speed = 2;
ship.pos_x = width / 2;
ship.pos_y = height - 20;
}

{
}

void initBullet(Bullet &bullet)
{
bullet.speed = 10;
}

void moveSpaceshipRight(Spaceship &ship)
{
ship.pos_x += ship.speed;
if(ship.pos_x >= width)
ship.pos_x = width-30;
}

void moveSpaceshipLeft(Spaceship &ship)
{
ship.pos_x -= ship.speed;
if(ship.pos_x <= 0)
ship.pos_x = 0+30;
}


However it's not behaving the way I want it to behave, in fact the behavior for the ship movement is un-normal. Basically I specified that the ship only moves when the right/left key is down, however the ship is moving constantly to the direction of the key pressed, it never stops although it should only move while my key is down. Even more weird behavior, when I press the opposite key the ship completely stops no matter what else I press.

What's wrong with the code? Why does the ship move constantly even after I specified it only moves when a key is down?

• I don't know allegro but your event logic is pretty bad to me. You should only care of when a key is pressed and then check if this key is the right or left arrow and apply the proper movement to your ship. I guess you are using this weird approach because the "al_wait_for_event(event_queue, &ev)" call is a blocking one and you want to avoid that the player have to spam his keys to move. Can't you use non-blocking event check? – nathan Sep 6 '12 at 9:01
• Although the code could be arranged a little nicer, what it is doing is conceptually sound. By maintaining the state of the keys (updated via events when they change) each frame can be processed based on the state of the key for that frame and the duration of the frame, providing for the smoothest possible movement. Even though it is using a timed event, it would be good for the code to track the actual frame time to account for small variations and/or long frames. Processing a movement based only off of key events is going to be unreliable, because it will depend on the kry repeat rate. – Jason Morales Sep 6 '12 at 10:57
• I think you guys did not understand what I did there. I'm using a timer to limit my game FPS to 60, and each frame I run certain events, the idea is the user doesn't have to spam his keys, instead he just has to hold them down, that's exactly what my code does, except I missed a silly syntax problem and I was thinking I made a huge mistake somewhere, avoiding the obvious. Voting down this question seems unfair to me, and my code works exactly as intended, in fact I made it from an example off allegro 5 tutorials. The events which happen are timed, and I specify that in ALLEGRO_EVENT_TIMER. – Bugster Sep 6 '12 at 16:21

Based on your description it appears key[LEFT] = false; and key[RIGHT] = false; are never reached. The if-condition for that piece of code reads if(ev.type == ALLEGRO_KEY_UP), however the key down handling code's condition looks like this: if(ev.type == ALLEGRO_EVENT_KEY_DOWN).
Without knowing any Allegro, I suggest you use ALLEGRO_EVENT_KEY_UP in the key up handling code's condition.