xaxaia
xaxaia

Reputation: 21

C Space Invaders enemy movement

I have to write a clone of space invaders game for university in C language using SDL library for graphics.I am very new to C and programming in general so i struggle with it a lot. For now I have one row of enemies and I'm trying to make it move correctly. This are functions for movement of aliens, which check for the collision with right/left wall(which are SDL_Rects near window edges) and if it happens, enemies move one line lower in the opposite direction. The problem is it works okay for all ten enemies except the first one. Each time when collision with left wall occurs the first alien sort of moves away a bit from others instead of moving in one block as I want it to. I noticed that if I change the first for loop in move_aliens function to start from i=11 and i--, the same thing will happen to the enemy in last column. But I still dont know how to fix it. I would appreciate if someone could tell me what I'm doing wrong, give me an idea or sollution :). I uploaded a video of whats happening http://sendvid.com/dt1reizc

void move_down (GameState *game)
{
    int i=0; 
    for(; i < HMALIENS; i++)
        game->alien1[i].y += 25;
}

int collided(int a1, int b1, int a2, int b2, int width1, 
             int height1, int width2, int height2)
 {
     return (!((a1 > (a2+width2)) || (a2 > (a1+width1)) || 
            (b1 > (b2+height2)) || (b2 > (b1+height1))));
 }


void move_aliens(GameState *game)
{
    int i=0;
    for(; i < HMALIENS; i++)
    {
    if (game->alien1[i].dir==LEFT)
       game->alien1[i].x -= 10;
    if (game->alien1[i].dir==RIGHT)
       game->alien1[i].x += 10;

    if (collided(game->alien1[i].x, game->alien1[i].y, 
        game->leftwall.x, game->leftwall.y, 50, 50, 1, 600))
     {
         int i = 0;

         for(; i < HMALIENS; i++)
            game->alien1[i].dir=RIGHT;
         move_down(game);
     }
  }

if(collided(game->alien1[i].x, game->alien1[i].y, game->rightwall.x, 
   game->rightwall.y, 50, 50, 1, 600))
{
    int i = 0;
    for(; i < HMALIENS; i++)
        game->alien1[i].dir=LEFT;

     move_down(game);
 }
}
}

//edit HMALIENS is just a constant (11), the number of living enemies at the start GameState is a structure. LEFT/RIGHT stand for direction of movement (quite obvious) [enum Direction {LEFT, RIGHT};]. I have in my alien1 structure enum Direction dir and in the function which load_game function i set it to RIGHT.

typedef struct
{
    Player player;
    Rightwall rightwall;
    Leftwall leftwall;
    Alien1 alien1[HMALIENS];
    SDL_Texture *bulet;
    SDL_Texture *ship;
    SDL_Texture *Alien1;
    SDL_Renderer *renderer;
 } GameState;

Upvotes: 1

Views: 2327

Answers (3)

milevyo
milevyo

Reputation: 2184

typedef enum{
    LEFT,
    RIGHT
}GAME_DIRECTION;

int dir=LEFT;

#define SPRITE_WIDTH    50
#define SPRITE_HEIGHT   50
#define BOTTOM_LINE     600


void move_down (GameState *game)
{
    int i; 
    for(i=0; i < HMALIENS; i++)
        game->alien1[i].y += 25;

}

void do_slide(GameState *game)
{
    int i; 
    for(i=0; i < HMALIENS; i++)
        game->alien1[i].x += dir?10:-10;

}


int collided(GameState *game)
 {
    int i;

    for(i=0; i < HMALIENS; i++){
        if(
            game->alien1[i].x <= game->leftwall.x                 || 
            game->alien1[i].x >= game->rightwall.x +SPRITE_WIDTH  || 
            game->alien1[i].y >= BOTTOM_LINE - SPRITE_HEIGHT
        )
        return true;
    } 
    return false;
 }


void move_aliens(GameState *game)
{
    if(collided(game)){
        move_down (game);
        dir=!dir;         // update direction; 
    }else{
        do_slide (game);
    }
}

Upvotes: 1

jimhark
jimhark

Reputation: 5046

Maybe something like:

void move_aliens(GameState *game)
{
    int i=0;
    for(; i < HMALIENS; i++)
    {
        if (game->alien1[i].dir==LEFT)
            game->alien1[i].x -= 10;
        if (game->alien1[i].dir==RIGHT)
            game->alien1[i].x += 10;
    }

    if (collided(
        game->alien1[0].x, game->alien1[0].y,
        game->leftwall.x, game->leftwall.y,
        50, 50, 1, 600))
    {
        int i = 0;

        for(; i < HMALIENS; i++)
            game->alien1[i].dir=RIGHT;

         move_down(game);
    }

    if(collided(
        game->alien1[HMALIENS-1].x, game->alien1[HMALIENS-1].y,
        game->rightwall.x, game->rightwall.y,
        50, 50, 1, 600))
    {
        int i = 0;
        for(; i < HMALIENS; i++)
            game->alien1[i].dir=LEFT;

        move_down(game);
    }
}

I have tried to make the minimum changes. But @milevyo's more extensive rewrite looks good as well.

The problem, I think (just from looking), is you has the left collision test inside the loop so when that hits, the movement gets out of sync.

Also it was pretty subtle that the right collision test used i from the previous loop which happens to index the last element (the rightmost alien). I changed that to explicitly use HMALIENS - 1. When you start destroying aliens, you'll have to track the first (leftmost) and last (rightmost) living aliens and use them for you collision tests.

Your indentation and formatting were a little off which makes the code much harder to read. Formatting is important, and will be even more so when your code gets more complicated.

Upvotes: 0

jamieguinan
jamieguinan

Reputation: 1680

Without rewriting your code, the problem is that you have already moved the first alien ([0]) left,

if (game->alien1[i].dir==LEFT)
       game->alien1[i].x -= 10;

and then you are doing the collision test and flagging all of them to move right, but the loop continues with [1..10], while [0] has already moved.

Upvotes: 1

Related Questions