Hello Guest, please login or register.
Did you miss your activation email?
Login with username, password and session length.

Pages: [1]   Go Down

Author Topic: [C++] Platformer collision  (Read 2676 times)

0 Members and 1 Guest are viewing this topic.

Xiphirx

wat
[C++] Platformer collision
« on: May 22, 2010, 01:52:45 am »
  • Xiphirx
  • *
  • Reputation: +0/-0
  • Offline Offline
  • Gender: Male
  • Posts: 3007
I've been working on a platformer for a few weeks now, and it is at the point where I implement collision.

I am currently attempting the bounding box method, and I guess, am successfully detecting the collision, but I am not exactly handling it quite well. I have tried to set the players collision to its previous position, but it creates a bouncing effect. I have also tried setting the players position next to the collision point, but it makes the player stuck pretty much, or it makes it jerky...

I want the collision to behave like cave story's if that helps... any ideas?

if it matters, C++ + SDL
Logged
  • For The Swarm
Re: [C++] Platformer collision
« Reply #1 on: May 22, 2010, 04:37:58 am »
  • Doesn't afraid of anything
  • *
  • Reputation: +42/-0
  • Offline Offline
  • Gender: Male
  • Posts: 7002
I've been having this exact problem with my collisions as well, not sure how to fix it...so I request help as well haha
Logged



i love big weenies and i cannot lie

Xiphirx

wat
Re: [C++] Platformer collision
« Reply #2 on: May 22, 2010, 07:13:53 pm »
  • Xiphirx
  • *
  • Reputation: +0/-0
  • Offline Offline
  • Gender: Male
  • Posts: 3007
I've been having this exact problem with my collisions as well, not sure how to fix it...so I request help as well haha

See this? Its a well-known and spread disease :O!

HAPL.
Logged
  • For The Swarm

DefaultAlias

Re: [C++] Platformer collision
« Reply #3 on: May 22, 2010, 08:50:36 pm »
Not sure how much help it would be, but here's a quick link i got from gamedev.net: MetaNet collision tutorial
There's a second part of the tutorial too, but i've yet to read through either of them. I hope they're of some use.

Also, if you haven't, go run through the article section at gamedev.net.

I'm getting to collisions in my engine soon too, so if you find any other cool info let us know about it.
Logged

Xiphirx

wat
Re: [C++] Platformer collision
« Reply #4 on: May 23, 2010, 01:04:54 am »
  • Xiphirx
  • *
  • Reputation: +0/-0
  • Offline Offline
  • Gender: Male
  • Posts: 3007
Not sure how much help it would be, but here's a quick link i got from gamedev.net: MetaNet collision tutorial
There's a second part of the tutorial too, but i've yet to read through either of them. I hope they're of some use.

Also, if you haven't, go run through the article section at gamedev.net.

I'm getting to collisions in my engine soon too, so if you find any other cool info let us know about it.

SAT looks interesting, but sadly I dont know vector math, although I can look at some things to learn it...
Logged
  • For The Swarm

DefaultAlias

Re: [C++] Platformer collision
« Reply #5 on: May 23, 2010, 01:49:21 am »
Yeah. Vectors are not to hard to learn and it's good to know in general if you're interested in game development. But to get any advanced geometric algorithms, you'll want to know what they are.


One of the tricks i messed with a while back was to use a projected vector from the point of intersection and center of the static object. I calculated the distance the colliding object had penetrated the static object, and moved it back that distance along that vector. I only ever tested it with spheres though, not sure if it'd be useful with anything else.
Logged

Xiphirx

wat
Re: [C++] Platformer collision
« Reply #6 on: May 23, 2010, 03:05:36 am »
  • Xiphirx
  • *
  • Reputation: +0/-0
  • Offline Offline
  • Gender: Male
  • Posts: 3007
Ok, here is what I came up with, it doesn't work quite yet :/

Code: [Select]
vec2d Map::checkCollision(SDL_Rect obj)
{
vec2d vector;

vector.dirX = vector.dirY = 0;
vector.mag = 0;

if ( (obj.y/16) >= 0 &&
((obj.y+obj.h)/16) >=0 &&
(obj.x/16) >= 0 &&
((obj.x+obj.w)/16) >=0 &&
(obj.y/16) < data1.numrows() &&
((obj.y+obj.h)/16) < data.numrows() &&
(obj.x/16) < data1.numcols() &&
((obj.x+obj.w)/16) < data.numcols() &&
(
data1[(obj.y/16)][(obj.x/16)] != 0 ||
data1[(obj.y/16)][((obj.x+obj.w)/16)] != 0 ||
data1[((obj.y+obj.h)/16)][(obj.x/16)] != 0 ||
data1[((obj.y+obj.h)/16)][((obj.x+obj.w)/16)] != 0
)
   )
{

SDL_Rect tile;

tile.x = (obj.x/16)*16;
tile.y = (obj.y/16)*16;
tile.w = tile.h = 16;

if (
obj.x > tile.x &&
obj.x < (tile.x+tile.w)
   )
{
vector.dirX = (tile.x+tile.w)-obj.x;
vector.mag = 1;
}

if (
(obj.x+obj.w) > tile.x &&
(obj.x+obj.w) < (tile.x+tile.w)
   )
{
vector.dirX = (obj.x+obj.w) - tile.x;
vector.mag = -1;
}

if (
(obj.y+obj.h) > tile.y &&
(obj.y+obj.h) < (tile.y+tile.h)
   )
{
vector.dirY = (obj.y+obj.h) - tile.y;
vector.mag = -1;
}

if (
obj.y < (tile.y+tile.h) &&
obj.y > tile.y
   )
{
vector.dirY = (tile.y+tile.h) - obj.y;
vector.mag = 1;
}
}
return vector;
}

vec2d is a class made by me
Code: [Select]
#ifndef VEC2D
#define VEC2D

class vec2d
{
public:
int mag;
int dirX, dirY;
};

#endif

Maybe someone can help me sort this out? am I supposed to calculate the center of the boxes or something? looking at my algorithm theoretically, it should work right?
Logged
  • For The Swarm
Re: [C++] Platformer collision
« Reply #7 on: May 23, 2010, 04:07:15 am »
  • Oh.
  • *
  • Reputation: +0/-0
  • Offline Offline
  • Posts: 579
For a simple tile-based platformer?

Moving on the X axis? Take a step on the X axis. In a wall? Break from the loop. Otherwise, loop the check and increment the X position until you reach your destination. I.E., if you're moving at a pace of 5 pixels a frame, do the loop 5 times.

Moving on the Y axis? Take a step on the Y axis. In a wall? Break from the loop. Otherwise, loop the check and increment the X position until you reach your destination. I.E., if you're moving at a pace of 5 pixels a frame, do the loop 5 times.

Moving on both the X and Y axis? Do the first one, then the second one.

Seems to work fine for the most part, although it might have it's flaws in places, it's good for a beginner. Otherwise, I'd do it in trigonometry and represent the world as a series of polygons or various shapes.
Logged
Hm.

Mamoruanime

@Mamoruanime
Re: [C++] Platformer collision
« Reply #8 on: May 23, 2010, 04:14:31 am »
  • ^Not actually me.
  • *
  • Reputation: +9/-0
  • Offline Offline
  • Gender: Male
  • Posts: 9786
Tile based collision is pretty dog simple :x

I don't imagine it's very difficult in C++ either...

This isn't C++, but I don't see how it could be much different-

Code: [Select]
Function CollisionRect:Int(_x1:Int,_y1:Int,_w1:Int,_h1:Int,_x2:Int,_y2:Int,_w2:Int,_h2:Int)

If _y1 >= (_y2 + _h2) Or  (_y1 + _h1) <= _y2
Return False
EndIf

If _x1 >= (_x2 + _w2) Or  (_x1 + _w1) <= _x2
Return False
EndIf

Return True
End Function

I'm sure you can easily convert that <_<

I use that coupled with a Bounding Box class that holds the information for width/height along with x offsets and y offsets. When you want to check (for example) to the right, you simply call the CollisionRect function and add to the direction you're moving + the speed you're moving. If there's distance between, you do a loop that runs through that incrementally until there's no gap. Very easy stuff :p

I think the only times I've had issues with that particular script was due to oversights on my part on my loop return being too soon, or 'obiwan' errors.
« Last Edit: May 23, 2010, 04:16:13 am by Mamoruアニメ »
Logged

Xiphirx

wat
Re: [C++] Platformer collision
« Reply #9 on: May 23, 2010, 08:11:48 pm »
  • Xiphirx
  • *
  • Reputation: +0/-0
  • Offline Offline
  • Gender: Male
  • Posts: 3007
Still going at it... :/'

Here is the function
Code: [Select]
vec2d Map::checkCollision(SDL_Rect obj)
{
vec2d vector;

vector.dirX = vector.dirY = 0;
vector.xMag = 0;
vector.yMag = 0;

if ( (obj.y/16) >= 0 &&
((obj.y+obj.h)/16) >=0 &&
(obj.x/16) >= 0 &&
((obj.x+obj.w)/16) >=0 &&
(obj.y/16) < data1.numrows() &&
((obj.y+obj.h)/16) < data.numrows() &&
(obj.x/16) < data1.numcols() &&
((obj.x+obj.w)/16) < data.numcols()
   )
{
SDL_Rect tile;
tile.x=tile.y=0;
tile.w = tile.h = 16;
int numy, numx;
char dir;
dir = 'N';
numy = obj.y/16;
numx = obj.x/16;
// TOP LEFT = A
// TOP RIGHT = B
// BOTTOM LEFT = C
// BOTTOM RIGHT = D
// NULL = N

if (data1[numy][numx] != 0)
{
tile.x = numx*16;
tile.y = numy*16;
dir = 'A';
}
if (data1[numy][numx+1] != 0)
{
tile.x = (numx+1)*16;
tile.y = numy*16;
dir = 'B';
}
if (data1[numy+1][numx+1] != 0)
{
tile.x = (numx+1)*16;
tile.y = (numy+1)*16;
dir = 'D';
}
if (data1[numy+1][numx] != 0)
{
tile.x = numx*16;
tile.y = (numy+1)*16;
dir = 'C';
}
if (dir == 'N')
{
return vector; //no collision
}

switch (dir)
{
case 'A': // TOP LEFT
vector.dirX = ((numx*16) + tile.w) - obj.x;
vector.dirY = ((numy*16) + tile.h) - obj.y;
vector.xMag = 1;
vector.yMag = 1;
break;
case 'B': // TOP RIGHT
vector.dirX = (obj.x+obj.w) - tile.x;
vector.dirY = ((numy*16) + tile.h) - obj.y;
vector.xMag = -1;
vector.yMag = 1;
break;
case 'C': // BOTTOM LEFT
vector.dirX = ((numx*16) + tile.w) - obj.x;
vector.dirY = (obj.y+obj.h) - tile.y;
vector.xMag = 1;
vector.yMag = -1;
break;
case 'D': // BOTTOM RIGHT
vector.dirX = (obj.x+obj.w) - tile.x;
vector.dirY = (obj.y+obj.h) - tile.y;
vector.xMag = -1;
vector.yMag = -1;
break;
default:
return vector; // no collision
break;
}
}
return vector;
}


and here is handling the result...
Code: [Select]
motion = curMap.checkCollision(boundingBox);
if (motion.xMag != 0 || motion.yMag != 0)
{
switch ( motion.dirX < motion.dirY )
{
case true:
x += motion.dirX * motion.xMag;
xVel=0;
break;
case false:
y += motion.dirY * motion.yMag;
yVel=0;
jumping = false;
break;
default:
break;
}
}

I've read the function over about 4 times now... it should work perfectly right? That means the way I'm handling it is wrong... :'/
Logged
  • For The Swarm

DefaultAlias

Re: [C++] Platformer collision
« Reply #10 on: May 23, 2010, 10:28:17 pm »
Some weird stuff is going on in there man, it's kind of hard to follow.
Could you maybe layout the algorithm you're trying to follow? I'll help you out if i can.
Logged

Xiphirx

wat
Re: [C++] Platformer collision
« Reply #11 on: May 23, 2010, 10:57:16 pm »
  • Xiphirx
  • *
  • Reputation: +0/-0
  • Offline Offline
  • Gender: Male
  • Posts: 3007
Some weird stuff is going on in there man, it's kind of hard to follow.
Could you maybe layout the algorithm you're trying to follow? I'll help you out if i can.

Heh, I'm cleaning it out, and am fixing my math... I am finding a lot of errors in it D;
Logged
  • For The Swarm

Xiphirx

wat
Re: [C++] Platformer collision
« Reply #12 on: May 24, 2010, 12:38:09 am »
  • Xiphirx
  • *
  • Reputation: +0/-0
  • Offline Offline
  • Gender: Male
  • Posts: 3007
Aha! It is done (finally)
Here is the function that detects the collision, and sets a vector accordingly.
Code: [Select]
vec2d Map::checkCollision(SDL_Rect obj)
{
vec2d vector;
vector.dirX = vector.dirY = vector.xMag = vector.yMag = 0;

if (data1.inRange(obj.y/TILE_DIM, obj.x/TILE_DIM)
&& data1[obj.y/TILE_DIM][obj.x/TILE_DIM] != 0)
{ // TOP LEFT
vector.dirX = ( (obj.x/TILE_DIM)*TILE_DIM+TILE_DIM ) - obj.x;
vector.dirY = ( (obj.y/TILE_DIM)*TILE_DIM+TILE_DIM ) - obj.y;
vector.xMag = 1;
vector.yMag = 1;
return vector;
}

if (data1.inRange(obj.y/TILE_DIM, (obj.x+obj.w)/TILE_DIM )
&& data1[obj.y/TILE_DIM][(obj.x+obj.w)/TILE_DIM] != 0)
{ // TOP RIGHT
vector.dirX = (obj.x + obj.w) - ((obj.x+obj.w)/TILE_DIM)*TILE_DIM;
vector.dirY = ( (obj.y/TILE_DIM)*TILE_DIM+TILE_DIM ) - obj.y;
vector.xMag = -1;
vector.yMag = 1;
return vector;
}

if (data1.inRange( ((obj.y+obj.h)/TILE_DIM), obj.x/TILE_DIM)
&& data1[((obj.y+obj.h)/TILE_DIM)][obj.x/TILE_DIM] != 0)
{ // BOTTOM LEFT
vector.dirX = ( (obj.x/TILE_DIM)*TILE_DIM+TILE_DIM ) - obj.x;
vector.dirY = (obj.y+obj.h) - ( (obj.y/TILE_DIM)*TILE_DIM+TILE_DIM );
vector.xMag = 1;
vector.yMag = -1;
return vector;
}

if (data1.inRange( ((obj.y+obj.h)/TILE_DIM), ((obj.x+obj.w)/TILE_DIM))
&& data1[((obj.y+obj.h)/TILE_DIM)][((obj.x+obj.w)/TILE_DIM)] != 0)
{ // BOTTOM RIGHT
vector.dirX = (obj.x + obj.w) - ((obj.x+obj.w)/TILE_DIM)*TILE_DIM;
vector.dirY = (obj.y+obj.h) - ( (obj.y/TILE_DIM)*TILE_DIM+TILE_DIM );
vector.xMag = -1;
vector.yMag = -1;
return vector;
}
return vector;
}

Then, to handle the output (what I have done so far, it is not perfect just yet)
Code: [Select]
motion = curMap.checkCollision(boundingBox);
if (motion.xMag != 0 || motion.yMag != 0)
{
if (abs(motion.dirX) < abs(motion.dirY))
{
x += motion.dirX * motion.xMag;
xVel=0;
}
else
{
y += motion.dirY * motion.yMag;
if (yVel > 0) jumping = false;
yVel=0;
}
}

It has one bug, if there is a block under the player and a block to the left of the player (or right I am assuming) and you move toward the left (or right) block, your player will fall through the block it is on. I know why this happens and I am trying to fix it...

You guys are probably shaking your head saying I overcomplicated it, but I just wanted really solid collision detection, and this is as solid as I can get it D;

Oh, another thing, this detection only works if the player's dimensions are smaller than or equal to (unsure on the equal) the blocks' dimensions.
Logged
  • For The Swarm
Pages: [1]   Go Up

 


Contact Us | Legal | Advertise Here
2013 © ZFGC, All Rights Reserved



Page created in 0.186 seconds with 60 queries.