Thread: help getting SDL collision to work

  1. #1
    Registered User
    Join Date
    Nov 2009
    Posts
    151

    help getting SDL collision to work

    In this game when you shoot the bullet passes right through the enemy, and I was hopping the community here could help me out.

    here is my code:
    Code:
    #include <SDL/SDL.h>
    #include <SDL/SDL_Image.h>
    #include <string>
    #include "class.h"
    
    using namespace std;
    
    SDL_Surface *screen = NULL;
    
    SDL_Rect space;
    
    SDL_Event event;
    
    bool quit = false;
    
    character person;
    villian enemy;
    bullet shoot;
    
    const int GRAVITATIONAL_ACCELARATION = -2;
    const int MAX_FALL_HEIGHT = -12;
    const int FALL_SPEED = 3;
    
    int collision_x(SDL_Rect A, SDL_Rect B){
    int aLeft = A.x;
    int aRight =A.x+ A.w-1;
    int aUp = A.y;
    int aDown = A.y+A.h-1;
    
    int bLeft = B.x;
    int bRight = B.x+B.w-1;
    int bUp = B.y;
    int bDown = B.y+B.h-1;
    
    if(aLeft == bRight && aUp >= bDown){
    return 1; /* collision case */
    }
    if(aRight == bLeft && aUp >= bDown){
        return 2;
    }
    return  0;
    }
    
    int collision_y(SDL_Rect A, SDL_Rect B){
        if(A.h >= B.y){
            return 1;
        }
        if(A.y <= B.h){
            return 2;
        }
        return 0;
    }
    
    void handle_events(){
        if(SDL_PollEvent(&event)){
            if(event.type == SDL_QUIT){
                quit = true;
            }
            if(event.type == SDL_KEYDOWN){
                switch(event.key.keysym.sym){
                    case SDLK_ESCAPE: quit = true; break;
                    case SDLK_RIGHT://
                        person.right = 1;
                    break;
                    case SDLK_LEFT://
                        person.left = -1;
                    break;
                    case SDLK_UP://
                        if(!person.inAir){
                            person.inAir = true;
                        }
                    break;
                    case SDLK_DOWN://
                        person.down = 1;
                    break;
                    default: break;
            }
        }
        if(event.type == SDL_KEYUP){
                switch(event.key.keysym.sym){
                    case SDLK_RIGHT:person.right = 0; break;
                    case SDLK_LEFT:person.left = 0; break;
                    case SDLK_UP: person.up = 0; break;
                    case SDLK_DOWN:person.down = 0; break;
                    case SDLK_SPACE://
                    if(shoot.draw == false){
                        shoot.draw = true;
                        }
                        break;
                    default: break;
                }
        }
        }
    }
    
     void apply_surface(int X, int Y, SDL_Surface *source, SDL_Surface *destination){
        SDL_Rect pos;
        pos.x = X;
        pos.y = Y;
    
        SDL_BlitSurface(source, NULL, screen, &pos);
    }
    
    SDL_Surface *load_image(string filename){
        SDL_Surface *surface = NULL;
        SDL_Surface *optSurface = NULL;
    
        surface = IMG_Load(filename.c_str());
    
        if(surface != NULL){
            optSurface = SDL_DisplayFormat(surface);
            SDL_FreeSurface(surface);
            if(optSurface != NULL){
            SDL_SetColorKey( optSurface, SDL_SRCCOLORKEY, SDL_MapRGB( optSurface->format, 0, 0xFF, 0xFF ) );
            }
        }
        return optSurface;
    }
    
    bool load_files(){
        return true;
    }
    
    void clean_up(){
        SDL_FreeSurface(person.person);
        SDL_FreeSurface(shoot.bullet);
        SDL_FreeSurface(enemy.enemy);
    
        SDL_Quit;
    }
    
    bool Init(){
        if(SDL_Init(SDL_INIT_EVERYTHING) == -1){
            return false;
        }
    
        screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);
    
        if(screen == NULL){
            return 0;
        }
        SDL_WM_SetCaption("Shooter", NULL);
    
        space.x = 640;
        space.y = 480;
        space.w = 0;
        space.h = 0;
    
        return true;
    }
    
    void class_init(){
        //charecter init
        person.inAir = false;
        person.airTime = 0;
    
        person.x = 0;
        person.y = 453;
        person.w = person.x + 19;
        person.h = person.y + 28;
    
        person.coll.x = person.x;
        person.coll.y = person.y;
        person.coll.w = person.w;
        person.coll.h = person.h;
    
        person.left = 0;
        person.right = 0;
        person.up = 0;
        person.down = 0;
    
        person.person = NULL;
    
        //bullet init
        shoot.x = person.x + 19;
        shoot.y = person.y + 13;
        shoot.w = shoot.x + 7;
        shoot.h = shoot.y + 3;
        shoot.timer = 0;
    
        shoot.coll.x = shoot.x;
        shoot.coll.y = shoot.y;
        shoot.coll.w = shoot.w;
        shoot.coll.h = shoot.h;
    
        shoot.draw = false;
    
        shoot.bullet = NULL;
    
        //enemy init
        enemy.x = 619;
        enemy.w = enemy.x + 21;
        enemy.y = 451;
    
        enemy.alive = true;
    
        enemy.coll.x = enemy.x;
        enemy.coll.w = enemy.w;
    }
    
    
    int main(int argc, char *argv[]){
    
        if(Init() == false){
            return 1;
        }
        class_init();
        if(load_files() == false){
            return 1;
        }
    
        person.person = load_image("person.png");
        shoot.bullet = load_image("bullet.png");
        enemy.enemy = load_image("enemy.png");
    
        while(quit == false){
            SDL_FillRect(screen, &screen->clip_rect, SDL_MapRGB(screen->format, 0x237, 0x20, 0x48));
    
            person.w = person.x + 19;
            person.h = person.y + 28;
            person.coll.x = person.x;
            person.coll.y = person.y;
            person.coll.w = person.w;
            person.coll.h = person.h;
    
            if(shoot.draw == false){
            shoot.x = person.x + 19;
            shoot.y = person.y + 11;
            shoot.w = shoot.x + 7;
            shoot.h = shoot.y + 3;
    
            shoot.coll.x = shoot.x;
            shoot.coll.y = shoot.y;
            shoot.coll.w = shoot.w;
            shoot.coll.h = shoot.h;
            }
    
            while(person.inAir){
                person.up += GRAVITATIONAL_ACCELARATION;
                if(person.up <= MAX_FALL_HEIGHT){
                    person.up = FALL_SPEED;
                }
                if(person.y == 453){
                    person.up = 0;
                    person.inAir = false;
                }
            }
    
            handle_events();
            if(collision_x(person.coll, space) != 1){
            person.x += person.left;
            }
            if(collision_x(person.coll, space) != 2){
            person.x += person.right;
            }
            if(collision_y(person.coll, space) != 1){
                person.y += person.down;
            }
            if(collision_y(person.coll, space) != 2){
                person.y += person.up;
            }
    
            apply_surface(person.x, person.y, person.person, screen);
    
            if(collision_x(shoot.coll, enemy.coll) == 2){
                enemy.alive = false;
                class_init();
            }
            if(enemy.alive){
                apply_surface(enemy.x, enemy.y, enemy.enemy, screen);
                enemy.x--;
            }
    
            if(shoot.draw == true){
                apply_surface(shoot.x, shoot.y, shoot.bullet, screen);
                shoot.x += 4;
    
                if(collision_x(shoot.coll, space) == 1){
                enemy.alive = false;
                shoot.draw = false;
            }
            }
    
            SDL_Delay(1000/110);
    
            SDL_Flip(screen);
        }
    
        clean_up();
        return 0;
    }

  2. #2
    Just a pushpin. bernt's Avatar
    Join Date
    May 2009
    Posts
    426
    Honestly (and I'm sorry) I just had a few 'wtf' moments. I'll list them and hopefully it will help your problems.

    Number 1:
    Code:
    if(collision_x(shoot.coll, enemy.coll) == 2){
                enemy.alive = false;
                class_init();
            }
            if(enemy.alive){
                apply_surface(enemy.x, enemy.y, enemy.enemy, screen);
                enemy.x--;
            }
    
            if(shoot.draw == true){
                apply_surface(shoot.x, shoot.y, shoot.bullet, screen);
                shoot.x += 4;
    
                if(collision_x(shoot.coll, space) == 1){
                enemy.alive = false;
                shoot.draw = false;
            }
            }
    Why is one collision_x outside the check for (shoot.draw == true) and the other inside (and after if (enemy.alive) as well...)?

    Number 2:
    You really shouldn't have collision_x and collision_y. It should be collision_rect(SDL_Rect a, SDL_Rect b) or something like that - really it should. If you need to check if you can move left or right then check collisions with a rectangle that is moved. In pseudocode:
    Code:
    int dx=0, dy=0;
    
    if (left is pressed)
        dx=-1;
    if (right is pressed)
        dx=1;
    //same with up, down
    
    move_player(player_x+dx, player_y) //move the player to its new x position
    if (collision_rect(player.rect, other.rect))    //and if there's a collision there
        move_player(player_x-dx, player_y) //move back
    
    move_player(player_x, player_y+dy) //same with y
    if (collision_rect(player.rect, other.rect))
        move_player(player_x, player_y-dy)
    Number 3:
    In collision_x
    Code:
    if(aLeft == bRight && aUp >= bDown){
    return 1; /* collision case */
    }
    if(aRight == bLeft && aUp >= bDown){
        return 2;
    }
    Since when do the sides of the rectangle have to be equal for a collision to happen? This is probably the source of your problems with the bullet collision. Since you set the bullet at the start to
    shoot.x = person.x + 19;
    and
    /*whilst bullet is moving*/
    shoot.x += 4;
    and
    case SDLK_RIGHT:
    person.right = 1;
    break;
    case SDLK_LEFT:
    person.left = -1;
    break;
    There is only a 1 in 4 chance that the bullet will actually register a hit. Given the initial conditions:
    person.x = 0;
    enemy.x = 619;
    enemy.w = enemy.x + 21;

    shoot.x = person.x + 19;
    it seems as though the bullet should register (bullet starts at 19, travels by 4; eventually shoot.x will equal 639 [enemy.w - 1] given those conditions). But in general this is a very bad practice.
    Consider this post signed

  3. #3
    Sweet
    Join Date
    Aug 2002
    Location
    Tucson, Arizona
    Posts
    1,820
    Collision question answered before:

    Doesn't look like the exact same code but the answer(s) still apply.
    collision not taking affect
    Woop?

  4. #4
    Just a pushpin. bernt's Avatar
    Join Date
    May 2009
    Posts
    426
    Collision question answered before:
    Yeah, it's the same guy asking too so I think (well I hope) he knows it was answered.

    EDIT: And he's been
    asking
    for
    a
    while,
    evidently.
    Last edited by bernt; 06-22-2010 at 03:57 PM.
    Consider this post signed

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Hard time having SDL and OpenGL work together
    By indigo0086 in forum Game Programming
    Replies: 5
    Last Post: 07-05-2007, 10:21 AM
  2. Check collision (REAL THREAD)
    By Livijn in forum C++ Programming
    Replies: 34
    Last Post: 05-22-2007, 12:45 AM
  3. SDL and MinGW Studio
    By Vicious in forum Tech Board
    Replies: 0
    Last Post: 07-30-2004, 09:59 PM
  4. bounding box collision detection
    By DavidP in forum Game Programming
    Replies: 7
    Last Post: 07-07-2002, 11:43 PM
  5. Replies: 4
    Last Post: 05-03-2002, 09:40 PM