James
James

Reputation: 77

Detecting collision with sprites made of multiple pixel widths and heights

Context: Developing a small game on a microprocessor displayed on an LCD screen.

I'm trying to fix this collision detection function, what it does is it detects collision between a wall sprite (1 x 25 pixels) and a player sprite (3x3 pixels). It returns 1 or 0, if 1 the player sprite's dx/dy changes so it stops moving. So essentially the wall sprite is treated as a real wall.

int wall_collision(Sprite *w_sprite)
{

    if (((w_sprite->x >= wall_sprite.x) && ((w_sprite->x - wall_sprite.x) < 3)) && ((w_sprite->y >= wall_sprite.y) && ((w_sprite->y - wall_sprite.y) < 3)))
        return 1;

    if (((w_sprite->x <= wall_sprite.x) && ((w_sprite->x - wall_sprite.x) > -3)) && ((w_sprite->y >= wall_sprite.y) && ((w_sprite->y - wall_sprite.y) < 3)))
        return 1;

    if (((w_sprite->x >= wall_sprite.x) && ((w_sprite->x - wall_sprite.x) < 3)) && ((w_sprite->y <= wall_sprite.y) && ((w_sprite->y - wall_sprite.y) > -3)))
        return 1;

    if (((w_sprite->x <= wall_sprite.x) && ((w_sprite->x - wall_sprite.x) > -3)) && ((w_sprite->y <= wall_sprite.y) && ((w_sprite->y - wall_sprite.y) > -3)))
        return 1;

    return 0;
}

My main issue is specifying the exact number the sprite should be equal/greater than/lesser than to, so as you can see in the example, it's 3 or -3. When I take numbers out, it returns 1 and stops the sprite regardless of where is, because the sprite is technically still on the same x or y axis as the wall, but it's not proximity wise, touching the wall. What are the correct size parameters for this?

Case problem: My sprite should only stop when it's directly touching the wall, currently it either passes through the wall, or stops when not even close to the wall.

Upvotes: 1

Views: 227

Answers (2)

C Goldsworthy
C Goldsworthy

Reputation: 344

First of all, you're code seems a little complex - below is canonical (or so I believe) method of detecting collisions. With this function, instead of having to check each collision manually, we can detect any collision between colliders A and B. Keep in mind, the collider struct used in this would have to contain information on the top, bottom, left and right co-ordinates on each collider. You can then store all colliders in an array and then index through them to check for collisions. The function:

int collisionFunction(collider * A, collider * B){

    //Check to see if the colliders are "lined up" on the X-axis 
    if( (A->right > B->left ) && (B->right > A->left) ){

        //Check to see if the colliders are also "lined up" on the Y-axis
        if( (A->top < B->bottom) && (B->top < A->bottom) ){
            return 1; // COLLISION DETECTED
        }
    }

    return 0;//NO COLLISION DETECTED      
}

Explanation of the function/algorithm: First of all, we check to see if A and B are "lined up" on the x axis. By "lined up", I mean to say that two colliders could be colliding based off their position on the X-axis. Then, we check to see if each collider is lined up on the Y-axis. If both conditions are met, then the colliders are colliding. It can be a little hard to grasp this at first so I suggest you trace this by drawing out shapes on paper (some colliding, others not) and see whether the algorithm says they're colliding or not. This algorithm will work for coordinate systems where the origin (i.e. (0,0) ) is in the top left corner of the screen, which is the convention for 2D graphics.

Keep in mind that your player would go through the wall partially when using this algorithm - this is very common in 2D games. But, given the number of pixels you're using, this could obviously be a problem. Therefore, you should take that into account when implementing this algorithm.

Upvotes: 1

Orka
Orka

Reputation: 1105

How about this?

int wall_collision(Sprite *w_sprite)
{
  if(w_sprite->left >= wall_sprite->right) return 0;
  if(w_sprite->right <= wall_sprite->left) return 0;
  if(w_sprite->top >= wall_sprite->bottom) return 0;
  if(w_sprite->bottom <= wall_sprite->top) return 0;
  return 1;
}

Left/Right/Top/Bottom could be values or functions, or just replace them with the actual values. The "left" and "top" would be the same as the x/y value of the sprite or wall. The "right" and "bottom" would be the x/y + the width/height in pixels of the sprite or wall, respectively.

Take a look at this link for a more in-depth tutorial on simple collision detection: http://lazyfoo.net/SDL_tutorials/lesson17/index.php

EDIT: The example code assumes a coordinate system where x increases as you go right, and y increases as you go down.

Upvotes: 0

Related Questions