3
\$\begingroup\$

Hey all, I'm making a simple side-scrolling game, and I would appreciate some input!

My collision detection system is a simple bounding box detection, so it's really easy to implement. However my collision resolution is ridiculous! Currently I have a little formula like this:

if (colliding(firstObject,secondObject))  
  firstObject.resolve_collision(yAxisOffset);
if (colliding(firstObject,secondObject))
  firstObject.resolve_collision(xAxisOffset);

where yAxisOffset is only set if the first object's previous y position was outside the second object's collision frame, respectively xAxisOffset as well.

Now this is working great, in general. However there is a single problem. When I have a stack of objects and I push the first object against that stack, the first object get's "stuck," on the stack. What's I think is happening is the object's collision system checks and resolves for collisions based on creation time, so If I check one axis, then the other, the object will "sink" object directly along the checking axis.

This sinking action causes the collision detection routine to think there's a gap between our position and the other object's position, and when I finally check the object that I've already sunk into, my object's position is resolved to it's original position...

All this is great, and I'm sure if I bang my head against a wall long enough i'll come up with a working algorithm, but I'd rather not =). So what in the heck do you think I should do? How could I change my collision resolution system to fix this?

Here's the program (temporary link, not sure how long it'll last) (notes: arrow keys to navigate, click to drop block, x to jump)

I'd appreciate any help you can offer!

\$\endgroup\$
1
  • \$\begingroup\$ Small update, I checked for vertical depth of collision vs horizontal, and only handled one. The collisions still catch, but they automatically release (I'm guessing because of the acceleration due to gravity) \$\endgroup\$ Commented Mar 12, 2011 at 0:08

2 Answers 2

1
\$\begingroup\$

I'm not sure I understand the problem, but looking at your code above you resolve collision by only moving the first object away. What if in certain conditions, it's the second object that needs to move away and not the first?

You might want to try resolving the collision by moving both objects away from each other at the same time by half of the offset, or even better by an amount proportional to their weight or size, this way a big box will only move a little bit while a small box will move a lot.

If you have several objects to resolve (as you mention a stack), you need to find a solution that works for all objects at the same time and not just for 2 at a time.

If you want a very good/accurate solution I recommend you get a good book on physics/collision for games and try something from there. This will probably take some time to implement and some of those system are quite hard to understand. Maybe also overkill for a simple game.

One thing you could probably try now is to iterate through your resolution code a few times every frame between all the object. Every iteration will move each object away a little bit and hopefully find a good solution in very few iterations. Of course you might never find a solution this way and it might become too expensive to iterate many times in a single frame. Might be worth a try though.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks for the response, I'm sorry if my explanation wasn't clear. The second object is supposed to be static, in this case. This is simply for collision with tiles on my map(I had a system which would check the squares directly around you, didn't work well) On the several objects issue, I'm considering simply putting a bounding box around the whole stack, which would work really well. And since this is for the static part of my map there's no reason not to. However the problem lies in my dynamic aspect... (i'll probably just add to the large bb dynamically) Anyways thanks, you sparked ideas \$\endgroup\$ Commented Mar 12, 2011 at 6:07
1
\$\begingroup\$

Figured it out!!!!!

Here's the new method:
first, I add an object that I wish to check collisions, with my add_message_to_collision_queue(); function. I then invoke my handle_collisions() method:

bool player::handle_collisions() {
collisions tcol;

bool did_handle = false;
for (int temp = 0; temp < collideQueue.size(); temp++) {

tcol = get_collision(prevPos.x,y,get_img()->get_width(),get_img()->get_height(),
                     collideQueue[temp]->get_position().x,collideQueue[temp]->get_position().y,
                     collideQueue[temp]->get_img()->get_width(),collideQueue[temp]->get_img()->get_height());

if (prevPos.y >= collideQueue[temp]->get_prev_pos().y + collideQueue[temp]->get_img()->get_height())
  if (tcol.top > 0) {
    add_pos(0,tcol.top);
    set_vel(get_vel().x,collideQueue[temp]->get_vel().y);
    did_handle = true;
  }

if (prevPos.y + get_img()->get_height() <= collideQueue[temp]->get_prev_pos().y)
  if (tcol.bottom > 0) {
    add_pos(0,-tcol.bottom);
    set_vel(get_vel().x,collideQueue[temp]->get_vel().y);
    ableToJump = true;
    did_handle = true;
  }
}

for (int temp = 0; temp < collideQueue.size(); temp++) {
tcol = get_collision(x,y,get_img()->get_width(),get_img()->get_height(),
                     collideQueue[temp]->get_position().x,collideQueue[temp]->get_position().y,
                    collideQueue[temp]->get_img()->get_width(),collideQueue[temp]->get_img()->get_height());


  if (prevPos.x + get_img()->get_width() <= collideQueue[temp]->get_prev_pos().x)
    if (tcol.left > 0) {
      cout << "\nleft";
      add_pos(-tcol.left,0);
      set_vel(collideQueue[temp]->get_vel().x,get_vel().y);
      did_handle = true;
    }
  if (prevPos.x >= collideQueue[temp]->get_prev_pos().x + collideQueue[temp]->get_img()->get_width())
    if (tcol.right > 0) {
      cout << "\nright";
      add_pos(tcol.right,0);
      set_vel(collideQueue[temp]->get_vel().x,get_vel().y);
      did_handle = true;
    }

}


return did_handle;
}

then I clear the queue. pretty easy, and it works perfectly!!

\$\endgroup\$
1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .