Box-- Absorbing impulse after collide

Started by
15 comments, last by JohnRaptis 9 years ago

My test bed is two spheres of equal density and size and with restitution set to 0 and for the first one I set velocity towards the second one and modified PModB (not PModA). In that case behaviour was similar to increasing mass of the second sphere.

Try the following. Set the test bed with no modifications at all. Run and check behaviour. Multiply PModA (by 0.1f) and check the behaviour. Then revert to normal, multiply PModB and see what happens. Plus instead of using arrow keys, use SetLinearVelocity, maybe there is something in your movement code.

As for interpenetration. Yes, there is some, it emerges when multiplier is close to 0. And that might be an issue in crowds... I will try to figure out what to do, meanwhile try to make the code work as it is strange that you see no effect.

And one thing for interpenetration. The task you've described is quite ambigous. Imagine a case when both bodies have 0 strength (they dont transfer any weight when they collide) and one body move towards the other one. Intuitively when body in motion hits motionless body, it should stop as it doesnt transfer its mass (strength 0). It cant move motionless body, yet cant pass thru it, so it should stop. But to stop the first body, second body must apply some impulse to it. But it cant, as it has strength of 0. Contradiction. (I hope my explanation is clear). Imagine same bodies (with 0 strength) moving towards each other, how are they supposed to change velocity of each other in this case?

Well, there is an option. They shouldnt change velocities. They will travel towards each other and... And here comes the separation. But separation forces are small and eventually body might penetrate each other and pass thru each other. You might increase separation forces, but that may lead to instabilities in other situations.

Okay, the code is here (b2ContactSolver.cpp): http://codepaste.net/e55knq

In my test case there is no interpenetration now. In the beginning of the code there are two variables _fa, _fb, representing strength of two colliding bodies (0 - no mass transfer, 1 - full mass transfer). And if two bodies with strength 0 collide, their velocity remains unchanged (they dont interpenetrate and dont move). You can find all my adjustments by searching for MODIFICATION word in code (there 3). I also increased maximum separation correction (by 10), in your case you may have to tune it (the less you change it the better).

Advertisement

Here, http://speedy.sh/6sURv/Box2D.rar

b2FixtureDef now has strength property. Try setting strength of main character to 0 (default is 1.0) and see if it works.

Fixed version of b2ContactSolver: http://codepaste.net/k29ah7 (forgot to swap strengthA and strengthB)

Hi Alex,

I wish I had but more upvotes to give. That does the correct modification of the velocity. However, if I'm not mistaken, the strength is not related to the weight at all? I.E. if I set the strength to .1, then it's .1 push-power against everything.

Can you suggest a way I can make that related to the weight of the other object? My first inclination is to intercept the solver's constructor and set the "strength" explicity by just comparing it to the density of the other object and setting it anywhere from 0 to 1.0f depending.

Does that sound right to you?

The system I intend to set up is something like this:

if (strengthA<=weightB || weightB==0) {A cannot move B at all}

else if (strengthA>weightB*10) {A pushes B without any hindrance, sort of like Box2D normal behavior}

else {A pushes B at a linear interpolation depending on it's placement between weightB and weightB*10}

* * *

Edit: I've been fiddling around with the code a bit, trying to make this happen... I'm running into an issue in that during the push, strengthA is related to strengthB... whereas what I'm looking for is for strengthA to be related to weightB.

I made a quickie function:


float32 ResolveStrength(float pushStr, float pushedWeight)
{
	if (pushStr<=pushedWeight) return .00001f;// Should be zero actually!
	if (pushStr>=pushedWeight*10) return 1.0f;

	pushStr-=pushedWeight;
	float aMax=(pushedWeight*10)-pushedWeight;
	return (pushStr)/aMax;
}

And I use that like so in b2ContactSolver's constructor:


vc->strengthA = ResolveStrength(fixtureA->GetStrength(),fixtureB->GetWeight());
vc->strengthB = ResolveStrength(fixtureB->GetStrength(),fixtureA->GetWeight());

(I added a weight component to fixtures, to seperate it from density-- for the purposes of my initial test, everything has a density of 1 so that it's not a factor)

So when I do this, I set up:

CircleA, weight = 1.0, strength=11.0

CircleB, weight = 10.0, strength = 10.0

...and it works exactly as expected, with the pushing circle barely budging CircleB.

BUT! If I decide CircleB is going to be a weak guy, and give it a low strength, then suddenly circle A has more power to move it. So those attributes are still related to eachother, albeit with finer control.

But picture this situation:

A horde of Chasers are set up. Each chaser has weight 10, strength 1. This prevents the chasers from pushing much (including eachother, so they aren't just batting eachother out of the way constantly) but meanwhile the player character has to have at least strength 11 to push back at all.

There's probably an on-the-fly modification I could do to inv_mass to make this all come together--but for simplicity, is it possible to just divorce out the relationship between strengthA and strengthB when deciding how much the players seperate?

You could avoid physical hacks by making each of your "chasers" push the character, in case they are in contact, only if the projection of the velocity of the character along the direction of the chaser velocity is smaller than a certain threshold, i.e. the character is being pushed in the opposite direction by someone else or resisting effectively. If the character is seconding chaser movement, or even running away, there's no reason to break contact by pushing him/her in the wrong direction.

Omae Wa Mou Shindeiru

However, if I'm not mistaken, the strength is not related to the weight at all? I.E. if I set the strength to .1, then it's .1 push-power against everything. Can you suggest a way I can make that related to the weight of the other object? My first inclination is to intercept the solver's constructor and set the "strength" explicity by just comparing it to the density of the other object and setting it anywhere from 0 to 1.0f depending.

It is possible, but I'd recommend to keep modifications as simple as possible as these modifications are unphysical and may lead to unexpected results. Before going further If I were you I'd analyze the behaviour I want to achive, write down all the cases (player pushed by enemy, enemy pushed by player, player pushed by alot of enemies) and all desired outcomes and try to analyze to find regularities (and inconsistencies). And then I'd think how I can implement these regularities and resolve inconsistencies. In the end it is possible you'll not need to modify the engine at all.

CircleA, weight = 1.0, strength=11.0

CircleB, weight = 10.0, strength = 10.0

...and it works exactly as expected, with the pushing circle barely budging CircleB.

BUT! If I decide CircleB is going to be a weak guy, and give it a low strength, then suddenly circle A has more power to move it. So those attributes are still related to eachother, albeit with finer control

Here what's happening. In former case when A hits B, A starts pushing B with strength 11. At the same time, B actually acts on A by stopping it. The rate of those two processes (pushing/stopping) are influenced by two variables: strength (they are almost equal) and weight. B has bigger weight, so the stopping process occurs faster then pushing. A stops faster, then B accelerates. But when Bs strength is small, stopping and acceleration rates are almost equal.

I've made another changes to b2ContactSolver: http://codepaste.net/2iag4d

It now takes into account who is pushing who.

p.s.: it only uses density and strength

Ah thank you, with the latest changes I'm able to see what's happening and I can work with it!

A final update... it appears this problem cannot be solved simulaneously... or the solution is more than a quick velocity mod can handle. I started another thread, showing all the conditions that work, and the one condition where it fails: http://www.gamedev.net/topic/668296-collisionunembeddingpushing-and-a-seemingly-impossible-case/

If you're interested in following up, click over there... this has become somewhat of a quest to me now, and I'm actually writing a small, shallow simulator because I'm now interested in the mechanics philosophically rather than just practically.

This topic is closed to new replies.

Advertisement