Trouble with object Collisions

Started by
3 comments, last by Taco2003 17 years, 7 months ago
I'm really having trouble with detecting collisions between my objects. Basically I load my objects in from a file which contains, there locations on my map. That works fine, they are drawn in the correct spots. The problem is when I got to determine if the objects collide I can't seem to get them to work Right now my code looks like this: int Echo_Engine_2D_Map::Sprite_collision_fall() { OBJECTS_OBSTACLES *temp_ptr; OBJECTS_OBSTACLES *temp_ptr_2; int i; temp_ptr = obj_ob_head; temp_ptr_2 = temp_ptr; for(i = 0; i <= num_objects; i++) { //THIS WORKS FINE //check to see if object collides with a block tile on the map while(tiles[Map_Array[(temp_ptr->map_pos_y+64)/64][(temp_ptr->map_pos_x)/64][0]].obstacle == 1) { temp_ptr->map_pos_y -=8; ( THIS IS MY PROBLEM // check object to object Sprite_collision_down(temp_ptr,temp_ptr_2); temp_ptr->map_pos_y +=temp_ptr->v_y; temp_ptr = temp_ptr->next_object; } return TRUE; } bool Sprite_collision_down(OBJECTS_OBSTACLES *ptr1,OBJECTS_OBSTACLES *ptr2) { if(ptr1->map_pos_y+64 <= ptr2->map_pos_y) { dx7.Display_Text("Yes!",384,256); return false; } if(ptr1->map_pos_y >= ptr2->map_pos_y+64) { dx7.Display_Text("Yes!",384,256); return false; } if(ptr1->map_pos_x+64 <= ptr2->map_pos_x) { dx7.Display_Text("Yes!",384,256); return false; } if(ptr1->map_pos_x >= ptr2->map_pos_x+64) { dx7.Display_Text("Yes!",384,256); return false; } dx7.Display_Text("No!",384,256); return true; } When I run the code both the Yes/No are displayed on the screen, I don't know where I'm going wrong Any help on where I'm going wrong would be greatly appreciated [Edited by - Taco2003 on September 18, 2006 6:32:44 PM]
Advertisement
I assume you are trying to see if two rectangles intersect in that last function. I can't really take yours to bits at the moment but it looks all wrong to be honest.

The way I'd do this would be first of all have a function that tests to see if a single point is within a rectangle:

// assumes struct Rect { x,y,w,h };bool IsIn(int X,int Y,Rect R){    return(X>=R.x && X<R.x+R.w && Y>=R.y && Y<R.y+R.h);}


You can then build on this to create a function that tests if one rectangle intersects another:

bool IsIn(Rect A,Rect B){    if(IsIn(A.x,A.y,B)) return true;    if(IsIn(A.x+A.w-1,A.y,B)) return true;    if(IsIn(A.x,A.y+A.h-1,B)) return true;    if(IsIn(A.x+A.w-1,A.y+A.h-1,B)) return true;    return true;}


Then to test two rectangles for intersection, you can just do:

bool Intersect(Rect A,Rect B){    return IsIn(A,B) || IsIn(B,A);}


Once you have removed rectangle checking logic from your sprite code like that, you can then just base the sprite checking code on the Intersect function above.

A slightly nicer approach is to have a Rect class that supports these operations:

class Rect{public:    Rect(int x=0,int y=0,int w=0,int h=0) : X(x),Y(y),W(w),H(h) { }    bool Contains(int x,int y);    bool Contains(Rect R);    int X,Y,W,H;};bool Rect::Contains(int x,int y){    return(x>=X && x<X+W && y>=Y && y<Y+H);}bool Rect::IsIn(Rect R){    if(Contains(R.X,R.Y)) return true;    if(Contains(R.X+R.W-1,R.Y)) return true;    if(Contains(R.X,R.Y+R.H-1)) return true;    if(Contains(R.X+R.W-1,R.Y+R.H-1)) return true;    return false;}bool Intersect(Rect A,Rect B){    return A.Contains(B) || B.Contains(A);}


You can then either have your sprite class contain a Rect structure defining its location and size, or alternatively:

class Sprite{private:    int X,Y,Width,Height;public:    Sprite(){ }    Rect GetRect() const { return Rect(X,Y,Width,Height); }};bool SpritesIntersect(Sprite A,Sprite B){    return Intersect(A.GetRect(),B.GetRect());}


HTH Paul
I understand what you are saying, but will that way work the same for way I have my objects set up?

I create my objects using a typedef struct

eg.

typedef struct obj_str {	int pos_x; // the x position on the map	int pos_y; // the y position on the map	int map_pos_x;	int map_pos_y;	int destroy;	int push;	int v_y;	int block;	obj_str *next_object;} OBJECTS_OBSTACLES;


then during Initialization I read the objects in from a text file

int Echo_Engine_2D_Map::Read_Object_File(char *filename){  FILE *fileinfo;  OBJECTS_OBSTACLES *obj_ptr;  fileinfo = fopen(filename, "r");	for(int i = 0; i <=num_objects; i++)	{			if((obj_ptr = newObject()) == NULL)			{				dx7.Report_Error("could Not create new object");				return FALSE;			}						fscanf(fileinfo,"%d",&obj_ptr->pos_x); // read in the tiles location in bitmap (x direction)			fscanf(fileinfo,"%d",&obj_ptr->pos_y); // read in the tiles location in bitmap (y direction)			fscanf(fileinfo,"%d",&obj_ptr->map_pos_x);// read in the tiles location on the map (x direction)			fscanf(fileinfo,"%d",&obj_ptr->map_pos_y);// read in the tiles location on the map(y direction)			fscanf(fileinfo,"%d",&obj_ptr->destroy);// read in the tile push value			fscanf(fileinfo,"%d",&obj_ptr->push);//ead in the tile push value			fscanf(fileinfo,"%d",&obj_ptr->v_y);//ead in the tile push value			fscanf(fileinfo,"%d\n",&obj_ptr->block);// read in the tiles block value				}				fclose(fileinfo);	return TRUE;} 


I think I'm really getting fooled up in looping through my objects on each update, or does this have any effect on it?

Well first up, you are needlessly mixing C and C++. In C++ there is no difference between the following:

typedef struct object_s{    int x,y;} object;struct x{    int x,y;};class x{public:    int x,y;};


The first one is pointless as it is a throwback to pure C, where it was needed in order to avoid doing "struct object" everywhere you wanted to just do "object".

The second point to bear in mind here is that in C++ there is no difference between a struct and a class except that at struct has public (by default) access and inheritance whereas a class has private.

The implication of this is that a struct can have member functions, constructors and destructors just like a class. It can even have private and protected sections, you just have to explicitly declare them in the same way you have to explicitly declare a public section in a class.

So yes, the approach I suggest would work perfectly well with your approach. You should really consider dumping the typedef stuff though since it serves no purpose in C++ except to provide backwards-compatibility with legacy C code. This is completely equivalent to your declaration (I've added a GetRect() member):

struct OBJECTS_OBSTACLES {	int pos_x; // the x position on the map	int pos_y; // the y position on the map	int map_pos_x;	int map_pos_y;	int destroy;	int push;	int v_y;	int block;	OBJECTS_OBSTACLES *next_object;        Rect GetRect(){ return Rect(pos_x,pos_y,64,64); }};


I also have to suggest that you consider using the C++ file stream objects as well as they are a lot more concise and typesafe.

bool LoadObjects(const std::string &Path){    std::ifstream is(Path.c_str()); if(!is.is_open()) return false;    for(int i=0;i<num_objects;++i)        {        OBJECT_OBSTACLES *O=newObject();// I assume your newObject() function stores the object as well as creating it        is >> O->pos_x >> O->pos_y >> O->map_pos_x; // etc        }    return true;}


Even better would be to create an extractor function for your object:

// this would sit with your class definintion and get updated as the class changesstd::ifstream &operator>>(std::ifstream &is,OBJECT_OBSTACLES &O){    is >> O.pos_x >> O.pos_y >> O.map_pos_x; // etc    return is;}// this can sit elsewhere and is now independent of the details of the object classbool LoadObjects(const std::string &Path){    std::ifstream is(Path.c_str()); if(!is.is_open()) return false;    for(int i=0;i<num_objects;++i)        {        OBJECT_OBSTACLES *O=newObject();        is >> *O;        }    return true;}


This seperates out the loading of a single object from the mechanics of loading a variety of objects.
so I can just create a Rect
ie

Rect E;Rect F;E=temp_ptr->GetRect();E=temp_ptr_2->GetRect();

and test them using the Intersect(routine)?

Intersect(E,F);


Is there more too it because looking at your examples, and I'm just wondering were does the IsIn function get called?

This topic is closed to new replies.

Advertisement