make objects push away from each other

Hi there. I want to make some kind of shockwave that pushes objects away from one particular object emitting the shockwave. This works fine by using Rigidbody.AddExplosion(). however, it doesn’t behave the way I want yet. The problem is, that the one object applying a force to another object should move a bit away from that object. I attached an illustration of it:

alt text

Imagine you’re kicking a barrel, you apply a force to the barrel, the barrel falls over and since you’re standing on the ground, you’re still standing.

Now imagine, you’re in zero-gravity, a space-station or something, there’s a barrel floating in front of you. when you kick it, the barrel moves away from you, but since you’re also not attached to anything, you move a bit away from the barrel (assuming that your mass is higher than the barrel’s)

Do you ahve an idea how to accomplish in the unity physics engine? :slight_smile:

I think your heavy rigidbody idea is the best: since you’re already applying AddExplosionForce to each hit rigidbody, add an extra line of code to apply AddExplosionForce to the exploding object as well: use the original explosion force multiplied by hit object mass * adjust factor, the hit object’s position as the explosion center, and the original explosion radius - this will cheaply produce a very convincent reaction force.

This is an adaptation of the AddExplosionForce example:

var radius = 5.0;
var power = 10.0;
var reaction = 0.1; // adjust reaction factor

function Start () {
    // Applies an explosion force to all nearby rigidbodies
    var explosionPos : Vector3 = transform.position;
    var colliders : Collider[] = Physics.OverlapSphere (explosionPos, radius);
    for (var hit : Collider in colliders) {
        if (hit && hit.rigidbody){
            // apply explosion force to the hit object:
            hit.rigidbody.AddExplosionForce(power, explosionPos, radius, 3.0);
            // apply reaction force proportional to the hit object's mass:
            rigidbody.AddExplosionForce(reaction * power * hit.rigidbody.mass, hit.transform.position, radius)
        }
    }
}

EDITED: When the static object is long like a wall, you can find the reaction force origin using some geometry (case 1 in the drawing below): do a Linecast from the explosion to the object’s center, project the vector hit point - explosion onto the surface normal to find the reaction vector, then add it to the explosion pos: this returns the reaction origin in the wall plane. But what if the explosion is beyond the wall (case 2)? To detect this, you can do a short raycast to the reaction origin plus a little distance (0.5m, for instance) - if wall hit, use the calculated reaction origin; if not, explosion is beyond the wall, thus use the wall center as reaction origin. All this geometry may seem complicated, but is cheap: only when a static object is found you must use one linecast and one raycast, both short and inexpensive.

alt text

Since the treatment for static and movable objects must be different, you must know who’s who. The easiest way is to remove rigidbodies from the static objects: if the object hit has a rigidbody, AddExplosionForce to it (and the reaction force to the exploding object too, if you want); if no rigidbody, the object is static, thus just calculate the reaction origin and apply the reaction force.

This code considers static all objects without a rigidbody, and calculates the reaction origin like said above:

var pos : Vector3 = transform.position;
var colliders : Collider[] = Physics.OverlapSphere (pos, fieldRadius);
for (var hit : Collider in colliders) {
    if (hit){
        if (hit.rigidbody){ // movable object:
            hit.rigidbody.AddExplosionForce(...); // apply force to object hit
            // apply reaction force to exploding object as well, if you want
        } 
        else { // no rigidbody means static object:
            var pReact = hit.transform.position;
            var hitP: RaycastHit;
            Physics.Linecast(pos, pReact, hitP); // find the surface normal and hit point
            // calculate vector from explosion to wall surface
            var vReact = Vector3.Project(hitP.point - pos, hitP.normal);
            // check if not beyond wall end:
            if (Physics.Raycast(pos, vReact, vReact.magnitude + 0.5)){
                pReact = pos + vReact; // ok: reaction origin is here
            }        
            rigidbody.AddExplosionForce(fieldForce, pReact, fieldRadius, 0);
        }
    }
}

NOTE: If you need more control on which objects are static (and thus produce reaction) tag them as “Static” and check this in the else branch - this may be useful if you don’t want reaction from the ground, for instance.

Thanks a lot. I updated it to take the mass ratio into account:

var pos : Vector3 = transform.position;
var colliders : Collider[] = Physics.OverlapSphere (pos, fieldRadius);
for (var hit : Collider in colliders) {
    if (hit && hit.rigidbody){
    	var myMass=rigidbody.mass;
    	var hitMass=hit.rigidbody.mass;
        // apply explosion force to the hit object:
        hit.rigidbody.AddExplosionForce(fieldForce*(myMass/hitMass), pos, fieldRadius, 0.0);
        // apply reaction force proportional to the hit object's mass:
        rigidbody.AddExplosionForce(fieldForce*(hitMass/myMass), hit.transform.position, fieldRadius,0.0);
    }
}

however, i encountered another problem. This solution works fine for spherical objects of the same size, but here’s an illustration of a problem I have that makes the thing a bit more complicated :confused:

alt text