Jump to content
  • Advertisement
Sign in to follow this  
Canvas

Vector collision detection only on one instance?

This topic is 2279 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey guys, ive been working on some basic code for a simple game engine, it seems to be going really well, I have some collision detection and it works 100% correctly, but I have a vector of game entities, and i have written a for loop to go look through them and check for collision, but it only seems to check on the last entity

Here is the code for my 4 wall entities


eEntity wall1;
eEntity wall2;
eEntity wall3;
eEntity wall4;
wall1.setPosition(10,10);
wall2.setPosition(40,10);
wall3.setPosition(70,10);
wall4.setPosition(70,40);
std::vector<eEntity> walls;
walls.push_back(wall1);
walls.push_back(wall2);
walls.push_back(wall3);
walls.push_back(wall4);


Here is the code for my while statement,


while (quit == false)
{
fps.start();
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
quit = true;
}
//Check collisions
//Handle Inputs
gamePlayer.handleInput(event);
}
//Update
//Check Collision
for(int i=0;i<walls.size();i++)
{
gamePlayer.takeRectCollision(walls.at(i).rtnCollision());
}
gamePlayer.update();
//Clear screen
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
//Draw
SDL_BlitSurface(gamePlayer.draw(),NULL,screen,&gamePlayer.rtnPos());
for(int i=0;i<walls.size();i++)
{
SDL_BlitSurface(walls.at(i).draw(),NULL,screen,&walls.at(i).rtnPos());
}
if (SDL_Flip(screen) == -1)
{
return 1;
}
if( fps.rtnTicks() < 1000 / framerate )
{
SDL_Delay( ( 1000 / framerate ) - fps.rtnTicks() );
}
}


As i said my code compiles with my headers and code, but the collision detection is only checked on the last element in the vector

but also my draw for loop works, and draws all 4 walls.
:(

Anyone have a idea on my error?

Share this post


Link to post
Share on other sites
Advertisement
I cannot help you if you don't show up the code of takeRectCollision, rtnnCollision and update, all methods of gamePlayer.

Share this post


Link to post
Share on other sites
Ok let me get the code :)

Code for takeRectCollision

void eEntity::takeRectCollision(SDL_Rect &rectTake)
{
collisionTemp = rectTake;
}


Return collision

SDL_Rect eEntity::rtnCollision()
{
SDL_Rect temp;
temp.x = pos.x;
temp.y = pos.y;
temp.w = width;
temp.h = height;
return temp;
}


Update

void eEntity::update()
{
pos.x += xVel;
if(collision.rectTorectCollision(pos.x,pos.y,width,height,collisionTemp.x,collisionTemp.y,collisionTemp.w,collisionTemp.h))
{
pos.x -= xVel;
}
pos.y += yVel;
if(collision.rectTorectCollision(pos.x,pos.y,width,height,collisionTemp.x,collisionTemp.y,collisionTemp.w,collisionTemp.h))
{
pos.y -= yVel;
}
}


Thats most of the methods from eEntity, also the gamePlayer is a Entity

Share this post


Link to post
Share on other sites
In your for loop you go through and call takeRectCollision for each wall...
Each time you call that the collisionTemp is replaced; however, you only check against that collisionTemp object during the update method, which is only called after you called takeRectCollision all 4 times.

In essence you are only checking for one collision (in update method) against the last SDL_Rect to which collisionTemp was set. What you need to do is check for a collision against every collisionTemp that you set.

Does that make sense?

Share this post


Link to post
Share on other sites
it does indeed, so i need to call the update after each collision :(, there most be a better way, any idea?

Share this post


Link to post
Share on other sites
I don't see why you wouldn't call update each time, but another way would be to store the temps in an array, one set for each actual collision, and process them all at once during update.

Share this post


Link to post
Share on other sites
For each object that i want to check for collision i could make a Vector in the player object, this vector will hold SDL_Rect's and then use them in the collision detection in the player, that sound ok?

Share this post


Link to post
Share on other sites
Yeup, something like that. You clear the vector each frame, add only the data for walls that actually collide with the player, then parse these in the update method.

Share this post


Link to post
Share on other sites
Ok so lets go for this, i make a vector of SDL_Rects, in the update in the player object, it will go through each one, but there is a problem, if it was to collide with the first block but lets say it was hitting the 4th block with this still function correctly?

I just did some code and it kinda works...abit but acts weird
This is the code in main

for(int i=0;i<walls.size();i++)
{
gamePlayer.takeRectCollision(walls.at(i).rtnCollision());
}


This just takes in a SDL_Rect and adds it to a vector
Here is the code for takeRectCollision

void eEntity::takeRectCollision(SDL_Rect &rectTake)
{
rects.push_back(rectTake);
}


And here is the code for the update

void eEntity::update()
{
for(int i = 0;i<rects.size();i++)
{
if(collision.rectTorectCollision(pos.x,pos.y,width,height,rects.at(i).x,rects.at(i).y,rects.at(i).w,rects.at(i).h))
{
pos.x -= xVel;
}
if(collision.rectTorectCollision(pos.x,pos.y,width,height,rects.at(i).x,rects.at(i).y,rects.at(i).w,rects.at(i).h))
{
pos.y -= yVel;
}
}
pos.x += xVel;
pos.y += yVel;
}


But the collision doesnt seem to go very well sad.png

What happens now is my player box gets stuck inside the other boxs, and then just messing up

its ok, i just update the update code and here it is

void eEntity::update()
{
pos.x += xVel;
for(int i = 0;i<rects.size();i++)
{
if(collision.rectTorectCollision(pos.x,pos.y,width,height,rects.at(i).x,rects.at(i).y,rects.at(i).w,rects.at(i).h))
{
pos.x -= xVel;
}
}
pos.y += yVel;
for(int i = 0;i<rects.size();i++)
{
if(collision.rectTorectCollision(pos.x,pos.y,width,height,rects.at(i).x,rects.at(i).y,rects.at(i).w,rects.at(i).h))
{
pos.y -= yVel;
}
}
}


it works fine now, cheers guys

Share this post


Link to post
Share on other sites
If you're making an "engine" then you need to be extremely flexible. You shouldn't just be checking the player against some objects, but rather all collidible objects against each other, and provide some kind of mask to the user of the Engine to define if he wants one object to collide with another.

So, for example, you have a game with many enemies shooting bullets at a player, and there's walls and there are items the player can pick up. Well, you want the player to collide with the wall, enemies, enemy's bullets, and the items, but not his own bullets. You want the enemies to collide with other enemies, the player, the player's bullets and the wall, but not with enemy's bullets nor items.

Each of these objects should inherit from a general Physical Object (that has physical dimensions, positioning in the world, and movement attributes. You provide a method for the user to determine what can collide with what (bit-masks are a common method as well as layers), and then place each physical object into it's own types vector, and then compare each object in those vectors to the vector of objects that they collide with.

Example.

enum {
FIRST_COLLIDE_TYPE = 1,
PLAYER_COLLIDE_TYPE = FIRST_COLLIDE_TYPE ,
ENEMY_COLLIDE_TYPE,
PLAYER_BULLET_COLLIDE_TYPE,
ENEMY_BULLET_COLLIDE_TYPE,
MAX_COLLIDE_TYPE
};

pulic ICollisionHandler
{
virtual ~ICollisionHandler () {};
virtual HandleCollision(TPhysicalObject &ObjectCollidiedWith);
};

class TPhysicalObject : public ICollisionHandler
{
public:
double x,y , width, height;
double xVelocty, yVelocity;
unsigned int collideType;
unsigned int collideMask;

// gets called when this object hits another one
HandleCollision(TPhysicalObject &ObjectCollidiedWith);
};

// assume there is a class for Player, Enemy, PlayerBullet and EnemyBullet
// defined like this class TPlayer : public PhysicalObject

// In Player constructor, you set the bitmask to all the objects you can collide with
TPlayer::TPlayer()
{
...
collideMask = (1 << ENEMY_COLLIDE_TYPE) |
(1 << ENEMY_BULLET_COLLIDE_TYPE);
}
// same in other constructors

// in your engine header, you could have:
std::map CollisionMap<unsigned int, std::vector<TPhysicalObject&> >;

// and in the /ccp file
void MyEngine::AddCollisionObject(TPhysicalObject &object)
{
// add to proper , make it a map
CollisionMap[object.collideType].push_back(object);
}

// later, when checking for collisions, you'd do this
void MyEngine::Update()
{
// loop through every CollisionMap, and check collisions with other maps
// in the objects collision mask
for (itMap = CollisionMap.begin(); itMap != CollisionMap.end(); itMap++) {
for (itObject = itMap->begin(); itObject != itMap->end(); itObject++) {
for (int i = itObject->collideType+1 ; i < MAX_COLLIDE_TYPE; it++) {
if (itObject->collideMask & (1 << i)) {
// loop through every object in CollisionMap vector and check for Collides
// if they collide, tell each of them they collided with the other
if (Collides(*itObject, *itCheckObject) {
itObject->HandleCollision(*itCheckObject);
itCheckObject->HandleCollision(*itObject);
}
}
}
}
}
}


OK, I spent WAY too much time on that, but that's an idea of how I'd do it.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!