6
\$\begingroup\$

I'm trying to put together a struct or a method of some sort that will allow me to check the relative position between two objects, and if they're too far apart, apply a force that will draw them closer to eachother. I've read that you can achieve this by creating a 'spring', what that might look like in code?

\$\endgroup\$
4
  • 2
    \$\begingroup\$ what about the first link google suggest when you search "spring physics". it has all the theoretical explanation you need to implement your own or the second one explaining how you should implement it step by step. or you can use farseer to simulate spring for you. \$\endgroup\$
    – Ali1S232
    Commented Oct 14, 2012 at 20:39
  • \$\begingroup\$ Didn't want to use an entire physics engine for one purpose. \$\endgroup\$ Commented Oct 14, 2012 at 20:47
  • \$\begingroup\$ Technically, a spring's motion would work, but wouldn't it be easier to just change the direction and velocity of the entities until they reach some distance that satisfies the condition? If you're dead set on a spring, here's the Wikipedia entry on it. \$\endgroup\$ Commented Oct 14, 2012 at 20:49
  • \$\begingroup\$ Naw, not dead set on a spring, so far all the given answers are great! \$\endgroup\$ Commented Oct 14, 2012 at 22:24

3 Answers 3

6
\$\begingroup\$

None-physical way (not spring physics):

If I simply wanted an object to pull towards another object and stop there I would use this instead:

Define too far apart as a radius r, any object farther than that radius will be attracted to its partner.

R = r*r;

Lets say the attractor is A and the other object is B

  1. Pick a small percentage representing your speed : s = 25%; //adjust s as needed
  2. Divide the percentage by 100 : s /= 100.0 // s = 0.25
  3. Use this method:

A.attract(B)

deltaT = (currentTime - lastFrameTime) / 1000.0;    //time in seconds since last frame
deltaX = A.x - B.x;
deltaY = A.y - B.y;

if(deltaX * deltaX + deltaY * deltaY > R)
{
    B.x += s * deltaX * deltaT;
    B.y += s * deltaY * deltaT;
}
//could use some refinement to make the slowdown more gradual.

This would attract an object to another without 'letting go' once it gets there.


To simulate spring physics in one direction, use this:

`F=-kx`

k is a coefficient and x is the distance between the objects.

F will determine the acceleration speed between object A(attractor) and object B(attracted).

Edit:

Like dreta mentioned, you could use x (distance) to help calculate the new speed:

// dividing by distance to normalize
B.newVel.x = B.oldVel + ((A.x - B.x) / distance) * F

B.newVel.x = B.oldVel + ((A.x - B.x) / distance) * distance * k

Which is basically : (I am taking deltaT, frame time in seconds into account)

B.vel.x += (A.x - B.x) * k * deltaT; //You can divide by mass here
B.vel.y += (A.y - B.y) * k * deltaT; //Or adjust k to take that into account

Otherwise do something like:

To simulate the foce, check for the angle between them:

angle = Math.atan2(A.y - B.y, A.x - B.x);

The new velocity for B will be:

//We do not consider mass (assuming it is 1)
B.newVel.x = Math.cos(angle) * B.oldVel.x + F * delta;  
B.newVel.y = Math.sin(angle) * B.oldVel.y + F * delta;

This is not classic spring behavior as it does not consider the fact that the spring will repel an object if it is too close (closer than the equilibrium point).

If you wish to emulate that, detract a constant e from the distance x and it will push the object away if it is too near. To make the object stop, you will need to weaken the spring, otherwise it will continue to move near and then away after reaching it's attractor.

\$\endgroup\$
15
  • 6
    \$\begingroup\$ is there any reason why people keep using angles to calculate this, isn't it easier to just subtract one position from annother and then just normalize that, multiply by a value (in this case the force) and add that to the old vector, it should be way less expensive than trigonometry \$\endgroup\$
    – dreta
    Commented Oct 14, 2012 at 21:09
  • 1
    \$\begingroup\$ You need to calculate the distance anyway, so it's just a division, besides even if it wasn't, square root is hardware accelerated these days and trigonometry functions aren't \$\endgroup\$
    – dreta
    Commented Oct 14, 2012 at 21:12
  • 1
    \$\begingroup\$ i'm not saying this is a big deal, it's just that there's a less expensive way of doing this (unless we are talking about using look-up tables, like you've mentioned), that's why i'm asking if there's any reason why people use angles or is it just a habit, i'm not trying to be rude \$\endgroup\$
    – dreta
    Commented Oct 14, 2012 at 21:21
  • 1
    \$\begingroup\$ Just a habit. Your comment was constructive. \$\endgroup\$
    – AturSams
    Commented Oct 14, 2012 at 21:21
  • 1
    \$\begingroup\$ I agree with @dreta, The solution would be much clearer using vectors. And You can have a lookup table for sqrt if really needed.Besides you know what they say about early optimisation... \$\endgroup\$
    – Ken
    Commented Oct 14, 2012 at 21:22
5
\$\begingroup\$

What you need to implement is Hookes law. This is an equation which calculates the force created by a spring. The equation is;

F=-kx

where x is the how far a way the spring is from its 'natural' or resting length. i.e if a spring has a resting length of 5 meters and is stretched to 8 meters, x is 3 in this case. k is the spring constant, which controls how 'strong' the spring is. Note there is a minus sign. That is because the force acts in the opposite direction of the direction of stretching (or compression).

Once you know F, you can calculate the acceleration a=F/mass.

you will probably want to include damping in your model, otherwise an will bounce back and forth forever.

Now your equation will be

F=-kx-cv

v is the velocity of the object and c is the amount of damping (bigger values mean the oscillation will stop sooner

\$\endgroup\$
2
\$\begingroup\$

Rather than invoking physics, simpler solution would be to constantly adjust their positions to make sure that they are the required distance apart.

Vector2 disp=b.pos-a.pos; //displacement between both points

float adj=disp.length()-requiredLength; // how far are we from correct seperation

disp.normalize();

a.pos+=disp*0.01f*adj; //move a towards/away from b by 1% of the discrepancy
b.pos-=disp*0.01f*adj; //move b towards/away from a

In this code adjust the 0.01 value to make the objects move quicker or slower.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .