- Home /
How can I get 2 rigidbody2d objects to "share" physics?
In short, I want to make it so that if object A gets knocked back by an explosion, wind, bounces off a bouncy surface, smacked by a hammer, etc. the same forces will be applied to object B and vice versa. I have found that this ultimately creates an infinite feedback loop and I have to take actions to fight it. I have attempted a few method to do this but I run into an issue with each one. Below I have listed what I have tried and the issues:
Method 1
//remove previously recorded velocities
rB2B.velocity -= transferVel;
masterRB2B.velocity -= sentVel;
//record new changes in velocity
transferVel = masterRB2B.velocity;
sentVel = rB2B.velocity;
//add new changes in velocity
masterRB2B.velocity += sentVel;
rB2B.velocity += transferVel;
This method works by adding the velocity, not force, from one object to the other and removing the previous update before adding again.
Issue:
This works but it doesn't account for changes in velocity between updates, like friction, and causes the object to start moving in the reverse direction, unless greater force is continued to be applied. Furthermore, it causes this currently unknown glitch where one object falls slowly while the other one is standing on the ground. I've been able to disable it by ignoring negative Y velocity during transfer but I feel like that will cause issues in the future.
Method 2
masterRB2B.velocity = rB2B.velocity;
Object A's velocity will always equal object B's.
Issue
It does causes physics to sort of copy over but now object A is sort of immune to all physics apply to it except through the transfer. Furthermore, the communication is now one way.
Method 3
No Code
I make Object A a child of Object B.
Issue
This literally does nothing
Method 4
No Code
I join the 2 objects via a joint.
Issue
This is okay but, if Object A hits a wall Object B can't continue to move in the same direction as Object A is facing the wall. Additionally, if either object is in the air and the other in on the ground, the object remains stuck in the air. I would want it to fall but have the force of the fall still be transferred over.
Method 5
No Code
Write my code so that any time I apply force to object A, like when jumping, it, also, applies the same force to object B.
Issue
This is great in theory but it ignores all collision based physics and I have to remember this with EVERY addforce command I write.
Method 6
NoCode
I write my own physics engine that accounts for a true velocity and a player input velocity.
Issue
This could work but is far too labor intensive for the scope of this project.
Answer by Jack-Idealits · Aug 23, 2020 at 08:48 AM
If I understand your idea correctly, while the objects copy each other’s physics, this must not loop infinitely if they are subjected to the same force (otherwise, if they are both pushed towards the same direction by the same explosion, the shared physics would make it look as if the explosion were twice as strong).
Perhaps you could try the following:
Monitor the total force experienced by each object, using F=ma. Each time one object receives a significant acceleration (you can adjust this threshold to filter out small perturbations), the force is calculated and added to the other object. However, if both objects have very similar accelerations (similar amount and similar direction) at the same time, assume they are subject to the same force and don’t mirror the force.
I apologize if I did not fully understand what you suggested but you were able to help me figure out the answer. Code is copied below but, in short, I made a value that stores the previous shared force(actually velocity) and, if either object's velocity deviates from that value, it checks which objects did that, makes that value the new shared force, and passes it over to the other object. If both objects deviate from the normal, it just gets the average. I did try to update force instead of velocity but the physics immediately became very glitchy. I still have the one glitch where object A is on the ground which causes object B to float in the air but I decided to call this a feature.
code
if (sharedForced.x + sharedForceBuffer < masterRB2B.velocity.x || sharedForced.x - sharedForceBuffer > masterRB2B.velocity.x ||
sharedForced.y + sharedForceBuffer < masterRB2B.velocity.y || sharedForced.y - sharedForceBuffer > masterRB2B.velocity.y)
{
if (sharedForced.x + sharedForceBuffer < rB2B.velocity.x || sharedForced.x - sharedForceBuffer > rB2B.velocity.x ||
sharedForced.y + sharedForceBuffer < rB2B.velocity.y || sharedForced.y - sharedForceBuffer > rB2B.velocity.y)
{
sharedForced = (rB2B.velocity + masterRB2B.velocity) / 2f;
masterRB2B.velocity = sharedForced;
rB2B.velocity = sharedForced;
} else
{
sharedForced = masterRB2B.velocity;
rB2B.velocity = sharedForced;
}
} else if (sharedForced.x + sharedForceBuffer < rB2B.velocity.x || sharedForced.x - sharedForceBuffer > rB2B.velocity.x ||
sharedForced.y + sharedForceBuffer < rB2B.velocity.y || sharedForced.y - sharedForceBuffer > rB2B.velocity.y)
{
sharedForced = rB2B.velocity;
masterRB2B.velocity = sharedForced;
}
That glitch occurs because the two objects always try to have the same velocity. The floating object wants to fall, but the grounded object is kept stationary by the ground beneath, thus constantly nullifying the velocity of the other object, keeping it floating. I believe a similar thing would happen when the two objects are both pushed by a uniform wind; when one gets stuck after bumping into a wall, the other one also stops, as if it hits an invisible barrier.
This is why I initially recommended working with force and acceleration instead of velocity: since being stationary means an acceleration of zero, the grounded object would add a force of zero to the other object, which would not prevent it from falling.
I don’t expect there to be any glitches as long as there is a good buffering measure (like the one you currently have in your code) that filters out small perturbations and spasmodic movements. Still, I can’t be 100% sure as I haven’t coded a shared physics feature like this. I guess you could experiment with both methods and use the one that works best. Good luck!
I agree that it would be better to use force over velocity but I can't find a way to just get and set force. I can add force but I can't set it to a hard value. I tired to calculate force using mass and acceleration, which was calculated using velocity and Time, and then I set it by reversing the process and manually setting velocity but, the second velocity becomes anything other than 0, the objects begin to violently oscillate along the direction of the movement with increasing speed and distance of oscillation. Below was my code attempt
acceleration = (rB2B.velocity - lastVelocity) / Time.fixedDeltaTime;
lastVelocity = rB2B.velocity;
masterAcceleration = (masterRB2B.velocity - masterLastVelocity) / Time.fixedDeltaTime;
masterLastVelocity = masterRB2B.velocity;
Vector2 masterForce = masterRB2B.mass * masterAcceleration;
Vector2 force = rB2B.mass * acceleration;
if (sharedForced.x + sharedForceBuffer < masterForce.x || sharedForced.x - sharedForceBuffer > masterForce.x ||
sharedForced.y + sharedForceBuffer < masterForce.y || sharedForced.y - sharedForceBuffer > masterForce.y)
{
if (sharedForced.x + sharedForceBuffer < force.x || sharedForced.x - sharedForceBuffer > force.x ||
sharedForced.y + sharedForceBuffer < force.y || sharedForced.y - sharedForceBuffer > force.y)
{
sharedForced = (force + masterForce) / 2f;
masterRB2B.velocity = ((sharedForced / masterRB2B.mass) * Time.fixedDeltaTime) + masterLastVelocity;
rB2B.velocity = ((sharedForced / rB2B.mass) * Time.fixedDeltaTime) + lastVelocity;
} else
{
sharedForced = masterForce;
rB2B.velocity = ((sharedForced / rB2B.mass) * Time.fixedDeltaTime) + lastVelocity;
}
} else if (sharedForced.x + sharedForceBuffer < force.x || sharedForced.x - sharedForceBuffer > force.x ||
sharedForced.y + sharedForceBuffer < force.y || sharedForced.y - sharedForceBuffer > force.y)
{
sharedForced = force;
masterRB2B.velocity = ((sharedForced / masterRB2B.mass) * Time.fixedDeltaTime) + masterLastVelocity;
}
As part of the buffering measure, you could calculate the acceleration over longer intervals. a = dv/dt; currently your dv and dt are both the change over one frame update, and you could increase it to, say, 5 frames instead. The method is still called once per frame, but each time it is called, it calculates the acceleration over a much longer duration, which should help filter out the spasms.
Your answer
Follow this Question
Related Questions
Maintaining the trajectory of a ball when manipulating its velocity in a Breakout/Arkanoid clone 1 Answer
Convert Force into Velocity for 2D Player Jump 0 Answers
Velocity not updating object position 1 Answer
How to not get velocity by the other objects?,How to not get force by other gameobjects? 0 Answers
How to get the speed of an object? 3 Answers