Page 1 of 2

Half working collision engine

Posted: Sun Mar 14, 2010 5:35 pm
by Bullet Pulse
So I originally intended on making a so-called "Particle Engine", but that quickly turned into something else.
Ok. So I'm trying to make images automatically push each other away upon colliding.

If you have any knowledge about collision, please take a look at my code here.
and give me some advice on what I could do to fix it/make it better; I'd greatly appreciate it!

Code: Select all

#include "SDL/SDL.h"
#include "imageManager.h"
#include "image.h"

ImageManager::ImageManager()
{
    i = 1;
}

void ImageManager::WriteImage(SDL_Surface *dstSurf)
{
    for( int i = 0; i < images.size(); i++)
    SDL_BlitSurface( images[i]->imageSurf , &images[i]->imageRect, dstSurf,
       &images[i]->imageDst  );
}

void ImageManager::NewImage( const char *file, Sint16 x, Sint16 y, Uint16 w, Uint16 h )
{
    images.push_back( new Image(file, x, y, w, h) );
}


void ImageManager::GetInput( SDL_Event *event)
{
        if( event->type == SDL_KEYDOWN )
        {
            key = SDL_GetKeyState( NULL );
                CheckUp();
        }
}

bool ImageManager::IsCollision(SDL_Rect *r1, SDL_Rect *r2)
{
    if (r1->x < r2->x + r2->w &&
        r1->x + r1->w > r2->x &&
        r1->y < r2->y + r2->h &&
        r1->y + r1->h > r2->y)
        {
            return true;
        }
    return false;
}

void ImageManager::CheckUp()
{
                    if( key[SDLK_DOWN] )
                    {
                            if (images[0]->imageDst.y < 480 - images[0]->imageDst.h)
                            if ( images[i]->imageDst.y < 480 - images[i]->imageDst.h)
                            {
                                    images[0]->imageDst.y++;
                                        for( int j = 0; j < images.size(); j++)
                                        {
                                            for( int k = 0; k < images.size(); k++)
                                            {
                                                if (k == j)
                                                    continue;
                                                else if ( IsCollision(&images[j]->imageDst, &images[k]->imageDst) )
                                                {
                                                    while( IsCollision(&images[j]->imageDst, &images[k]->imageDst) )
                                                    images[k]->imageDst.y++;
                                                }
                                            }
                                        }
                            }
                            else if (  images[0]->imageDst.y  + images[0]->imageDst.h <  images[i]->imageDst.y 
                                            ||  images[0]->imageDst.x  >  images[i]->imageDst.x + images[i]->imageDst.w
                                            || images[0]->imageDst.y  >  images[i]->imageDst.y + images[i]->imageDst.h      
                                            ||  images[0]->imageDst.x  + images[0]->imageDst.w <  images[i]->imageDst.x)

                                                             images[0]->imageDst.y++;
                    }


                    else if( key[SDLK_UP] )
                    {
                            if (images[0]->imageDst.y > 0)
                            if ( images[i]->imageDst.y > 0)
                            {
                                    images[0]->imageDst.y--;
                                    for( int j = 0; j < images.size(); j++)
                                        {
                                            for( int k = 0; k < images.size(); k++)
                                            {
                                                if (k == j)
                                                    continue;
                                                else if ( IsCollision(&images[j]->imageDst, &images[k]->imageDst) )
                                                {
                                                    while( IsCollision(&images[j]->imageDst, &images[k]->imageDst) )
                                                    images[k]->imageDst.y--;

                                                }
                                            }
                                        }
                            }
                            else if (  images[0]->imageDst.y  + images[0]->imageDst.h <  images[i]->imageDst.y 
                                            ||  images[0]->imageDst.x  >  images[i]->imageDst.x + images[i]->imageDst.w
                                            || images[0]->imageDst.y  >  images[i]->imageDst.y + images[i]->imageDst.h      
                                            ||  images[0]->imageDst.x  + images[0]->imageDst.w <  images[i]->imageDst.x)
                            
                                                      images[0]->imageDst.y--;
                    }

                    else if( key[SDLK_LEFT] )
                    {
                            if (images[0]->imageDst.x > 0)
                            if ( images[i]->imageDst.x > 0)
                            {
                                    images[0]->imageDst.x--;
                                    for( int j = 0; j < images.size(); j++)
                                        {
                                            for( int k = 0; k < images.size(); k++)
                                            {
                                                if (k == j)
                                                    continue;
                                                else if ( IsCollision(&images[j]->imageDst, &images[k]->imageDst) )
                                                {
                                                    while( IsCollision(&images[j]->imageDst, &images[k]->imageDst) )
                                                                 images[k]->imageDst.x--;
                                                }
                                            }
                                        }
                            }
                            else if (  images[0]->imageDst.y  + images[0]->imageDst.h <  images[i]->imageDst.y 
                                            ||  images[0]->imageDst.x  >  images[i]->imageDst.x + images[i]->imageDst.w
                                            || images[0]->imageDst.y  >  images[i]->imageDst.y + images[i]->imageDst.h      
                                            ||  images[0]->imageDst.x  + images[0]->imageDst.w <  images[i]->imageDst.x)
                            
                                                          images[0]->imageDst.x--;
                    }

                    else if( key[SDLK_RIGHT] )
                    {
                            if (images[0]->imageDst.x < 640 - images[0]->imageDst.w )
                            if ( images[i]->imageDst.x < 640 - images[i]->imageDst.w)
                            {
                                    images[0]->imageDst.x++;
                                    for( int j = 0; j < images.size(); j++)
                                        {
                                            for( int k = 0; k < images.size(); k++)
                                            {
                                                if (k == j)
                                                    continue;
                                                else if ( IsCollision(&images[j]->imageDst, &images[k]->imageDst) )
                                                {
                                                    while( IsCollision(&images[j]->imageDst, &images[k]->imageDst) )
                                                               images[k]->imageDst.x++;
                                                }
                                            }
                                        }
                            }
                            else if (  images[0]->imageDst.y  + images[0]->imageDst.h <  images[i]->imageDst.y 
                                            ||  images[0]->imageDst.x  >  images[i]->imageDst.x + images[i]->imageDst.w
                                            || images[0]->imageDst.y  >  images[i]->imageDst.y + images[i]->imageDst.h      
                                            ||  images[0]->imageDst.x  + images[0]->imageDst.w <  images[i]->imageDst.x)
                            
                                                           images[0]->imageDst.x++;
                            


                    }
}

Re: SDL Collision Demo

Posted: Mon Mar 15, 2010 7:14 pm
by eatcomics
pretty sweet

Re: Half working collision engine

Posted: Mon Mar 15, 2010 8:24 pm
by Bullet Pulse
If you know anything about writing collision code, please look at the first post in this topic.

Re: Half working collision engine

Posted: Tue Mar 16, 2010 7:15 pm
by eatcomics
Bullet Pulse wrote:If you know anything about writing collision code, please look at the first post in this topic.
quite frankly, my collision in SDL was crap...

Edit: didn't this topic say something else before I posted....

Re: Half working collision engine

Posted: Tue Mar 16, 2010 7:21 pm
by Bakkon
It looks like you're just stepping outwards until there's no longer a collision and that's pretty wasteful on resources. You'd want to find the magnitude of the penetration and then shift both entities over by half of that depending on their collision direction.
eatcomics wrote:pretty sweet
"Hey, my car has a flat tire. Mind lending a hand?" "Pretty sweet."

Re: Half working collision engine

Posted: Tue Mar 16, 2010 7:22 pm
by Bullet Pulse
eatcomics wrote:
Bullet Pulse wrote:If you know anything about writing collision code, please look at the first post in this topic.
quite frankly, my collision in SDL was crap...

Edit: didn't this topic say something else before I posted....
Yes. However I decided to post the specific code for the collision rather than the whole project ;) .


Should I just learn how to use the separating axis theorem?

Re: Half working collision engine

Posted: Tue Mar 16, 2010 9:22 pm
by eatcomics
Bullet Pulse wrote:
eatcomics wrote:
Bullet Pulse wrote:If you know anything about writing collision code, please look at the first post in this topic.
quite frankly, my collision in SDL was crap...

Edit: didn't this topic say something else before I posted....
Yes. However I decided to post the specific code for the collision rather than the whole project ;) .


Should I just learn how to use the separating axis theorem?
I would imagine this is what you uses:
http://lazyfoo.net/SDL_tutorials/lesson17/index.php
but if not there it is, otherwise google could be of some help, or you could try the separating axis theorem, that might be fun too.

as to the tire thing, I didn't know it wasn't working at the time... So I said sweet, because getting collision in is cool, and I planned on trying it out later....

Edit: I just realized none of this made any sense... what was I doing to have such horrible grammar

Re: Half working collision engine

Posted: Wed Mar 17, 2010 5:18 am
by Bullet Pulse
Well yea the basic collision in that tutorial is pretty simple.
What I'm working on is a way to for a box to push another box away from it,
when it's pushes into it, and for the box that's being pushed to push more boxes away from it,
so it becomes like a stack of boxes being moved.

Re: Half working collision engine

Posted: Wed Mar 17, 2010 6:47 pm
by eatcomics
Bullet Pulse wrote:Well yea the basic collision in that tutorial is pretty simple.
What I'm working on is a way to for a box to push another box away from it,
when it's pushes into it, and for the box that's being pushed to push more boxes away from it,
so it becomes like a stack of boxes being moved.
Well I would imagine most collision detection systems would work fine for this, as long as you're checking the velocity and orientation of boxes against each other.

The separating axis theorem would probably be best if you want your boxes to be rotated differently. But if your boxes are all facing the same way then any regular collision should do...
If you post what code you have, I can probably help you out

Re: Half working collision engine

Posted: Wed Mar 17, 2010 6:58 pm
by Bullet Pulse
eatcomics wrote: Well I would imagine most collision detection systems would work fine for this, as long as you're checking the velocity and orientation of boxes against each other.

The separating axis theorem would probably be best if you want your boxes to be rotated differently. But if your boxes are all facing the same way then any regular collision should do...
If you post what code you have, I can probably help you out
The code is posted above :)

Re: Half working collision engine

Posted: Wed Mar 17, 2010 7:00 pm
by eatcomics
Bullet Pulse wrote:
eatcomics wrote: Well I would imagine most collision detection systems would work fine for this, as long as you're checking the velocity and orientation of boxes against each other.

The separating axis theorem would probably be best if you want your boxes to be rotated differently. But if your boxes are all facing the same way then any regular collision should do...
If you post what code you have, I can probably help you out
The code is posted above :)
Yeah, that and I already figured you got it from lazyfoo, so I didn't need it, I'm just gonna play with a little collision demo myself then get back to ya :D

Edit: by that I mean I'm making a collision demo :lol:

Re: Half working collision engine

Posted: Wed Mar 17, 2010 7:02 pm
by Bullet Pulse
eatcomics wrote: Yeah, that and I already figured you got it from lazyfoo, so I didn't need it, I'm just gonna play with a little collision demo myself then get back to ya :D
Edit: by that I mean I'm making a collision demo :lol:
Nope, I actually didn't. His code is probably much better lol. Can't wait to see it.
Here's my updated code with more efficient collision detection, but still some tiny problems.
I'm going to read up on collision tomorrow, write the code for the other two vertexes, and hopefully I'll figure out then.

Code: Select all

#include "SDL/SDL.h"
#include "imageManager.h"
#include "image.h"

ImageManager::ImageManager()
{
    offset = 0;
}

void ImageManager::WriteImage(SDL_Surface *dstSurf)
{
    for( int i = 0; i < images.size(); i++)
    SDL_BlitSurface( images[i]->imageSurf , &images[i]->imageRect, dstSurf,
       &images[i]->imageDst  );
}

void ImageManager::SaveLocation(Image image)
{
    //images.push_back( new Image("data/spectrum.bmp", image.x, image.y, image.w, image.h) );
}

void ImageManager::NewImage( const char *file, Sint16 x, Sint16 y, Uint16 w, Uint16 h )
{
    images.push_back( new Image(file, x, y, w, h) );
}

void ImageManager::GetInput( SDL_Event *event)
{
        if( event->type == SDL_KEYDOWN )
        {
            key = SDL_GetKeyState( NULL );
                CheckUp();
        }
}

bool ImageManager::IsCollision(SDL_Rect *r1, SDL_Rect *r2)
{
    if (r1->x < r2->x + r2->w &&
        r1->x + r1->w > r2->x &&
        r1->y < r2->y + r2->h &&
        r1->y + r1->h > r2->y)
        {
            return true;
        }
    return false;
}

void ImageManager::CheckUp()
{
                    if( key[SDLK_DOWN] )
                    {
                            if (images[0]->imageDst.y < 480 - images[0]->imageDst.h)
                            {
                                    images[0]->imageDst.y++;
                            }
                    }

                    else if( key[SDLK_UP] )
                    {
                            if (images[0]->imageDst.y > 0)
                            {
                                    images[0]->imageDst.y--;
                            }
                    }

                    else if( key[SDLK_LEFT] )
                    {
                            if (images[0]->imageDst.x > 0)
                            {
                                    images[0]->imageDst.x--;
                            }
                    }

                    else if( key[SDLK_RIGHT] )
                    {
                            if (images[0]->imageDst.x < 640 - images[0]->imageDst.w )
                            {
                                    images[0]->imageDst.x++;
                            }
                    }
                    Collide();
}

void ImageManager::Collide()
{
    for( int j = 0; j < images.size(); j++)
    {
        for( int k = 0; k < images.size(); k++)
        {
            if (k == j)
                continue;
            else if ( IsCollision(&images[j]->imageDst, &images[k]->imageDst) )  
            {
                if( images[j]->imageDst.y < images[k]->imageDst.y + images[k]->imageDst.h && images[j]->imageDst.y > images[k]->imageDst.y ) 
                {
                    offset = images[j]->imageDst.y + images[j]->imageDst.h - images[k]->imageDst.y;
                    images[j]->imageDst.y += offset * .05;
                    images[k]->imageDst.y -= offset * .05;
                }

                else if( images[j]->imageDst.w < images[k]->imageDst.x + images[k]->imageDst.w && images[j]->imageDst.x > images[k]->imageDst.x )
                {
                    offset = images[j]->imageDst.x + images[j]->imageDst.w - images[k]->imageDst.x;
                    images[j]->imageDst.x += offset * .05;
                    images[k]->imageDst.x -= offset * .05;
                }
            }
        }
    }
}

Re: Half working collision engine

Posted: Thu Mar 18, 2010 4:11 pm
by eatcomics
Sorry I didn't get it done yesterday, I was having SDL issus (IDK what it is about me and configuring projects) but I'll finish it up real quick, then clean it up and put some comments

Re: Half working collision engine

Posted: Thu Mar 18, 2010 5:22 pm
by Bullet Pulse
Ok. So here I have my new and improved collision demo.
There seems to be a small problem, because the stacks of boxes only move quickly when you are going in the up direction, otherwise they slow down a bit.
Also, they don't seem to want to stack up when going left or right.
However, it does work pretty good besides those things.

http://www.box.net/shared/oh60nakz28

Re: Half working collision engine

Posted: Thu Mar 18, 2010 7:29 pm
by eatcomics
Mine are the same, almost. You see, my boxes collision checking isn't the best. When a collision is detected, the box currently being checked gets the x and y velocities of the box that they are touching, the problem is with multiple blocks the velocities don't change to zero, because there is a collision, even though they aren't moving. I know this because I've noticed that if you get a cluster of boxes, and touch them, they rocket in a certain direction... Why they stay still when their velocities aren't zero is beyond me... Here is my code

(this is uncleaned, all in one file, horrible to look at, and may cause cancer...)

Code: Select all

#include <SDL.h>
#include <SDL_image.h>
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
#define SCREEN_BPP 32

SDL_Event event;
SDL_Surface *box = NULL;   //a box's surface
SDL_Surface *screen = NULL; //screen surface
bool done = false;

//The player's box
class PBox
{
    public: //I'm too lazy to make accessors and what not... 
		int x, y;
		int xVel, yVel;
		PBox();
		~PBox();
		void getInput();
} player;

//other boxes
class Box
{
    public:
		int x, y;
		int xVel, yVel;
		Box();
		~Box();
		void CheckCollision(int boxx, int boxy, int boxxvel, int boxyvel);
};

bool initVideo();

void drawBox(char *bmp, SDL_Surface *screen, int x, int y);

int main(int argc, char *argv[])
{
    if (!initVideo())
	{
		return 1;
	}

	Box box[8];
    
	int i = 0;
	int j = 0;
	int inc = 0; //increment x and y
	for (i = 0; i < 8; i++)
	{
	    inc += 50;
		box[i].x = inc;
		box[i].y = inc;
	}

	while (!done)
	{
		SDL_FillRect(screen, &screen->clip_rect, SDL_MapRGB(screen->format, 0x00, 0x00, 0x00));
		player.getInput();

		for (i = 0; i < 8; i++)
		{
			for (j = 0; j < 7; j++)
			{
				box[i].CheckCollision(box[j].x, box[j].y, box[j].xVel, box[j].yVel);
			}
		}

		for (i = 0; i < 8; i++)
		{
			box[i].CheckCollision(player.x, player.y, player.xVel, player.yVel);
		}

		drawBox("box.bmp", screen, player.x, player.y);
		for (i = 0; i < 8; i++)
		{
			drawBox("box.bmp", screen, box[i].x, box[i].y);
		}
		SDL_Flip(screen);
	}

	SDL_Quit();
	
	return 0;
}

bool initVideo()
{
	if (SDL_Init(SDL_INIT_EVERYTHING) == -1)
	{
		//I should really output some stuff about the fail, but I'm lazy
		return false;
	}

	screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE);

	if (screen == NULL)
	{
		return false;
	}

	SDL_WM_SetCaption("Collision", NULL);

	return true;
}

void drawBox(char *bmp, SDL_Surface *screen, int x, int y)
{
	SDL_Surface *image;
	SDL_Rect destination;

	image = SDL_LoadBMP(bmp);
	
	destination.x = x;
	destination.y = y;
	destination.w = image->w;
	destination.h = image->h;
	SDL_BlitSurface(image, NULL, screen, &destination);
    SDL_UpdateRects(screen, 1, &destination);
	SDL_FreeSurface(image);
}

PBox::PBox()
{
	x = 0;
	y = 0;
	xVel = 0;
	yVel = 0;
}

PBox::~PBox()
{
}

void PBox::getInput()
{
	while (SDL_PollEvent(&event))
	{
		if (event.type == SDL_KEYDOWN)
		{
			switch (event.key.keysym.sym)
			{
			    case SDLK_DOWN: yVel += 2; break;
				case SDLK_UP: yVel -= 2; break;
				case SDLK_RIGHT: xVel += 2; break;
				case SDLK_LEFT: xVel -= 2; break;
			}
		}
		if (event.type == SDL_KEYUP)
		{
			switch (event.key.keysym.sym)
			{
				case SDLK_DOWN: yVel -= 2; break;
				case SDLK_UP: yVel += 2; break;
				case SDLK_RIGHT: xVel -= 2; break;
				case SDLK_LEFT: xVel += 2; break;
			}
		}
		if (event.type == SDL_QUIT)
		{
			done = true;
		}
	}
	x += xVel;
	y += yVel;
}

Box::Box()
{
	xVel = 0;
	yVel = 0;
}

Box::~Box()
{
}

void Box::CheckCollision(int boxx, int boxy, int boxxvel, int boxyvel)
{
	if (boxx + 32 > x && boxx < x + 32)
	{
		if (boxy + 32 > y && boxy < y + 32)
		{
			xVel += boxxvel;
			yVel += boxyvel;
		}
	}
	else
	{
		xVel = 0;
		yVel = 0;
	}
	x += xVel;
	y += yVel;
}
EW

it would probably be better to test the side that is being collided by, and then make the square move while its still colliding, instead of just transferring velocities, but this is what came to my mind.

Edit: seems to me that that's exactly what you did, although it looks really jumpy, and things bounce backwards on collide so they are bouncing back when they collided, making them not move forward that fast