SDL rect collision detection

Started by
4 comments, last by password 18 years ago
I have a question about rectangle collision detection in SDL, it made sense until it did make me confused. I've created a program from a tutorial that shows a simple example of collision detection and a rectangle that can be moved. I had a problem that the rectangle that you can move, stopped before it hit the rectangle, let's call it wall instead. The rectangle leaves a little space between the wall and the rectangle sometimes. I was experimenting with it for a while to fix it, but the only thing I found out was that if I gave the width and height of the wall to a denary like (10 or 20) it leaved no space at all. For example, when I set the width to 65 it leaves the biggest space possible but if I change it to 60 or 70 the space will disappear. If I change the value to 62 or 68, the space is still there but much smaller, it's like the closer the value is to a denary the less the space between the rectangles become. Is this some kind of known bug or just the bad part of rectangle collision detection? I don't understand why the rectangle mysteriously becomes bigger and leaves un invisible space that the rectangle collides with, while it doesn't change shape when the value is what I mentioned before. I'm tired right now, if necessary, I will post the code too tomorrow..
Advertisement
Well, what are you doing after it hits the wall? If you're not moving the rectangle, it will leave whatever room it had previously between it and the wall. So say it starts 100 pixels from the wall and you move it by 10 pixels each cycle. If the block is 20 pixels wide, it will hit after 8 cycles of movement and end up right next to it. If it's 25 pixels wide, it will move seven times and be 5 pixels from the wall and not be able to move further.

If you move the rectangle to the closest to the wall after a hit, I don't know what the problem is.
That's because in my tutorial when there's a collision I don't put the rect next to the wall, I undo the movement.

just do a
if( rect moved right and touched wall )
put rect on left side of wall
else if( rect moved up and touched wall )
put rect on bottom side of wall
else if( rect moved left and touched wall )
put rect on right side of wall

etc etc

Learn to make games with my SDL 2 Tutorials

Quote:Original post by Lazy Foo
That's because in my tutorial when there's a collision I don't put the rect next to the wall, I undo the movement.

just do a
if( rect moved right and touched wall )
put rect on left side of wall
else if( rect moved up and touched wall )
put rect on bottom side of wall
else if( rect moved left and touched wall )
put rect on right side of wall

etc etc


Yeah, it goes to the opposite side instead, with the same speed, I understood that. But shouldn't the collision work that way no matter what value the wall has anyways? Instead of putting it beside the wall, undo the movement should do it.
Make it so that the rectangle gets put up next to the wall. Or else you could reduce the speed of movement to 1 pixel, but that's probably not practical.

The reason why undoing the movement won't make them right next to eachother is logical. If its moving 10pixels, and it crashes with a wall, then you move it back 10 pixels. This means that the only time when it would end up being in contact with the wall is when it was in contact the previous frame. The only time when it is in contact the previous frame is when the walls position is a multiple of its speed(assuming that the rectangle starts at a multiple of its speed, too).

And FYI, next time you don't need to tell us that you're using SDL, since it really isn't relevant to the problem.
Well, I thought it was because this kind of behaviour in general is kind of strange in my option, so I pointed out what api I used just in case. People tends to be mad if you don't add all the details in the thread also.

I can add that i'm using many walls, i've added three walls, it looks like this in the game loop:

SDL_FillRect(screen, &wall, SDL_MapRGB(screen->format, 0x77, 0x77, 0x77));
SDL_FillRect(screen, &wall2, SDL_MapRGB(screen->format, 0x77, 0x77, 0x77));
SDL_FillRect(screen, &wall3, SDL_MapRGB(screen->format, 0x77, 0x77, 0x77));

Outside the gameloop:

wall.x = 520;
wall.y = 40;
wall.w = 70;
wall.h = 400;

wall2.x = 0;
wall2.y = 40;
wall2.w = 590;
wall2.h = 10;

wall3.x = 0;
wall3.y = 440;
wall3.w = 590;
wall3.h = 10;

And I also created the global rect objects in the top of the program. I don't know if this is a good way to code but the if statement become something like this now and seems a little too, what should I say, hard to read:

if ((box.y<0) || (box.y + SQUARE_HEIGHT > SCREEN_HEIGHT) || (check_collision(box, wall) || (check_collision(box, wall2) || (check_collision(box, wall3)))) {
box.y-=yVel;
}

If I want to add multiple walls, is that a good way to do it?

Lazy foo, would be glad if you could explain the pseudocode you added, like where I should add it.

Quote:Original post by troutofdoom
Well, what are you doing after it hits the wall? If you're not moving the rectangle, it will leave whatever room it had previously between it and the wall. So say it starts 100 pixels from the wall and you move it by 10 pixels each cycle. If the block is 20 pixels wide, it will hit after 8 cycles of movement and end up right next to it. If it's 25 pixels wide, it will move seven times and be 5 pixels from the wall and not be able to move further.

If you move the rectangle to the closest to the wall after a hit, I don't know what the problem is.


I understand what you mean now it sounds logical, in other words the rectangle moves 10 pixels when you're moving it and if the wall is 22 the two remaining pixels will leave a space. That clears up some misunderstanding atleast.

Edit:
Changing the xVel and yVel to 1 is a proof of that it works that way. I can always have it that way and change the max frames to a high value, but I also want to learn how to make it stop instead of undoing.

I can't find a way to do it. I guess I most change this classfunction to make it work.

void Square::show() {
box.x += xVel;

if ((box.x<0) || (box.x + SQUARE_WIDTH > SCREEN_WIDTH) || (check_collision(box, wall) || (check_collision(box, wall2) || (check_collision(box, wall3))))) {
box.x-=xVel;
}

box.y += yVel;

if ((box.y<0) || (box.y + SQUARE_HEIGHT > SCREEN_HEIGHT) || (check_collision(box, wall) || (check_collision(box, wall2) || (check_collision(box, wall3))))) {
box.y-=yVel;
}

apply_surface(box.x, box.y, square, screen);
}

[Edited by - password on April 16, 2006 7:14:36 AM]

This topic is closed to new replies.

Advertisement