2
\$\begingroup\$

I'm implementing magnet like behavior in unity3d.
the red object have a script that add force to it toward a blue object.
to do that i use this code:

void FixedUpdate()
{
    float distance = Vector2.Distance(blue.transform.position, transform.position);
    speed = MAX_DISTANCE - distance;
    body2d.AddForce((blue.transform.position - transform.position).normalized * speed);
}  

MAX_DISTANCE is maximum distance that red and blue object can have.

with this code i got this behavior :

image

but i don't want red object gets this far after reaching blue object i want red object to decrease it's speed and after maybe some shaking around blue object and eventually stop on blue object, how can i implement this?

UPDATE
red and blue objects can't collide with each other they just know their location.

\$\endgroup\$
0
\$\begingroup\$

You really shouldn't redefine physics, you already have Physics2D. What you need is a PointEffector2D on the blue object and a Rigidbody2D on the red object. Your red object also needs to have its drag and angularDrag set to something other than zero for a realistic effect. You can skip the angularDrag and leave it at zero but you might need it later on.

Since the object will get to a point where the distance is almost zero, you'll have (almost) infinite force at that point. In the following gif, the "blue" object has a PointEffector2D with the force -30 and a CircleCollider2D for the effector to use. The "red" ball on the outside has a Rigidbody2D with a mass of 1 and a drag of 0.25.

enter image description here

Here are the details of the objects (as I already had them at hand, I'm just putting them here for future reference). Be aware that you might or might not need a Collider2D on the "red" object, I'm not entirely sure.

enter image description here

So, when the object gets near enough to the point you want it to be (and when it's slow enough to stop), remove its Rigidbody2D, or just disable it, and set its position. You can also increase the drag your object has to a point where it'll stand still. This way you're ensuring that the object won't wobble. For example:

if(distanceBetweenObjects <= 0.1 && redObject.velocity < 1) {
redObject.Rigidbody2D.enabled = false;
redObject.transform.position = blueObject.transform.position;
}

You'll have to tweak the values and maybe the code but this is close enough.

| improve this answer | |
\$\endgroup\$
4
\$\begingroup\$

I think what you're looking for is "damping." This is where you drain a little energy out of the system with each update step so that it settles into an equilibrium, rather than oscillating/vibrating forever.

You can do this by multiplying the velocity each frame by a value close to but less than one (the lower the value, the more sharply your object decelerates), or equivalently, by applying a force or acceleration that's a small negative multiple of the velocity.

| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

In real world physics, the formula for magnetic force is roughly some constant divided by the square of the distance.
This means that the force starts low, but quickly starts to increases when the distance reaches 1. It becomes infinite when the distance is zero.
If you implement your formula this way, there will be no going back and forth, and it will be more realistic.

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ "If you implement your formula this way, there will be no going back and forth" — this inverse square behaviour is the same as the gravity that pulls planets around their orbits, and they cycle all the time! So it's not the inverse square itself that prevents the oscillation, but friction or damping (including energy absorbed in a physical collision) \$\endgroup\$ – DMGregory Sep 29 '19 at 19:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.