(py)box2d bug?


bzar

A Commando
Joined
Sep 22, 2008
Messages
4,500
Location
Finland
Website
Visit site
Box2d forums seem to be down, and I couldn't find any mention about this anywhere, so I'm posting here.

I'm making a game with python|pygame|pybox2d. The game involves a player jumping on platforms. The platforms can be either dynamic or static. The decision on whether the player can jump is determined by collisions reported by box2d. If the player collides with a subclass of Platform and the collision normal vector is in a predefined range, the object is added to "new platform collisions" set, which is added to "current platform collisions" set when the game world updates. If on the other hand the player stops colliding with a platform, the platform is first searched from the new collisions and then from old collisions. If the platform resides in one of them it is removed from the set (but only one set). This complex procedure is to determine all the platforms with what the player has collided or still collides with in a certain frame. Yes it's quite complex, but taking into account how box2d works, it seems to be the only reliable way.

Now to the point. If a dynamic object (player) collides with a static object (wall), the player is bounced off the wall during the same box2d world update. However, if the other object is also dynamic (a dynamic box for example), both objects are actually affected the next frame!

Let me give an example. Say the player is falling straight down (positive y axis being up) and hits an object on the third frame from T=0. in the following example the leftmost column represents the frame index (T), the middle column is the player's linear velocity if the other object is static, the rightmost column the same as the middle one but with a dynamic object (the actual values are arbituary).

0 (0,-1.0) (0,-1.0)
1 (0,-1.1) (0,-1.1)
2 (0,-1.4) (0,-1.4)
3 (0,0.7) (0,-1.4) # the player hits the floor
4 (0,0.6) (0,0.7)

If I implement jumping by applying an impulse to the player, and the player jumps the moment he hits the floor, he'll jump normally, if the floor is static, but won't jump a pixel if it's dynamic, because the downward motion nullifies the impulse. This can worked around by setting the players linear y velocity to zero before applying the impulse, but thats not too pretty.

Even with this fix there's another problem. If the player is rotating, it should affect which way the player will jump. If the player is moving right in the air and rotating wildly counterclockwise, shouldn't he jump left when he touches ground? Well, he won't if it's a dynamic object, because also the effect of the rotating movement is calculated the next frame. So he jumps right without any regard to the rotating movement until he hits a static object. I could delay handling all collisions by one frame, but then collisions lasting only one frame would never count. This would mean that the player sometimes just wouldn't jump. That's not a good thing for playability.

My current (ugly) solution is to use not one but two sets for the new platform collisions. One for the static platforms and another for the dynamic ones. The static platforms take effect immediately, so you can jump off those one-frame-collisions. The dynamic platform collisions however are delayed by one frame.

Is this a bug in box2d or pybox2d? Is there a standard way to cope with it?
 
Hm, what exactly are you trying to accomplish here?
I've never had any problems with Box2D; the engine follows the Newtonian laws exactly. If you collide two dynamic objects, you will get an elastic collision depending on the masses of the objects. And if you apply an impulse when an object is moving downwards, where the impulse is equal to the force by which the object moves downwards, the object will stand still. If you want to create the unrealistic jumping effect à la Super Mario, you should consider setting the velocity and/or force to your wanted value.

(maybe you need to explain the core of your problem better in order for me to get your point)

Box2D may delay a collision by one frame, since it needs to interpolate the paths of the dynamic objects in order to really find out whether they collided or not. This is of course unnecessary if you have a static object, since it's velocity always will have a magnitude of 0.

(Sorry if I don't use the English technical terminology here, I only know the German, Swedish and Latin names for physical phenomena and the Newtonian physics)
 
dflemstr said:
Hm, what exactly are you trying to accomplish here?
I've never had any problems with Box2D; the engine follows the Newtonian laws exactly. If you collide two dynamic objects, you will get an elastic collision depending on the masses of the objects. And if you apply an impulse when an object is moving downwards, where the impulse is equal to the force by which the object moves downwards, the object will stand still. If you want to create the unrealistic jumping effect à la Super Mario, you should consider setting the velocity and/or force to your wanted value.

(maybe you need to explain the core of your problem better in order for me to get your point)

Box2D may delay a collision by one frame, since it needs to interpolate the paths of the dynamic objects in order to really find out whether they collided or not. This is of course unnecessary if you have a static object, since it's velocity always will have a magnitude of 0.

(Sorry if I don't use the English technical terminology here, I only know the German, Swedish and Latin names for physical phenomena and the Newtonian physics)
The problem is that I need to handle collisions between dynamic and static objects differently because of that one frame delay. Box2d reports the collisions as soon as they happen, but in the case of dynamic objects it actually reacts to them one frame later.

Say I have a ball bouncing on a block. The block is either static or dynamic with nigh infinite inertia. The block also applies an upward impulse to any ball touching it to keep it bouncing (for the example to work correctly, the ball must have restitution < 1). However the ball bouncing on the nigh-infinite inertia dynamic block stops as it hits the block, as the inertia merely counters its downward movement. The ball bouncing on the static block however keeps bouncing, because the ball has already lost its downward momentum by bouncing off the block.

If you counter this by first nullifying the vertical velocity, and if the ball has no rotational momentum, the balls bouncing on dynamic (with nigh infinite inertia) and static blocks work exacly the same. However, if rotation is added, the one on the static block bounces away as it should, while the other keeps bouncing up and down regardless of the rotational momentum.

The point is, that the outcome between these two scenarios (static and infinite-inertia-dynamic) shouldn't differ, but they do. If you react to things right after the update when things collided, it's a world of difference which it was.

I want realistic jumps, but always having to do a different handler if the other object happens to be dynamic is really annoying. Also I have to sometimes delay other things by a frame because of this. The jumping is just a good example.

EDIT: typos (lots of them)
 
Back
Top