2
\$\begingroup\$

I'm currently studying steering behaviors. Have recently learned about Seek.

I have a question about this.

Seek is supposed to turn the agent slowly in the direction of it's target, and then move in that direction.

However, I don't understand how Seek turns the agent around slowly. It seems to me like it should make the agent change direction immediately.

This is the code for a Seek function:

Vector Seek(Point target){

    Vector toTarget = new Vector(target - agent.getPosition());
    Vector desiredVelocity = toTarget.normalize() * agent.getMaxVelocity();

    return desiredVelocity.subtract(agent.getVelocity());

}

And then here is the update() function of the agent.

void update(){

    Vector force = seek(target);
    Vector acceleration = force.divideBy(mass); // mass = 1.
    velocity = velocity.add(acceleration);
    position = position.add(velocity);

}

Anybody mind explaining to me where the gradual change of velocity takes place? Thanks

\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

That function gives you a direction scaled such that it indeed performs an instantaneous velocity fix, if added to your velocity. You can think of this as the "steer direction". You can scale this direction by whatever factor you like. Maybe something like this to get started:

const dt = (1.0 / 60.0);
object.velocity += dt * object.Seek( targetPosition );

A scaling factor of 1 would provide an instant change, and lesser than 1 would apply a partial change.

If you want your steering behavior to preserve constant velocity, you'd probably want to just rotate your velocity vector towards the target, instead of adding/subtracting vectors.

In your example code acceleration is used as the seek vector, and scaled by a factor related to mass. The larger the mass of agent the greater the divisor of the steer vector. This is like scaling in the range of 0 to 1 with inverted mass:

velocity += direction * (1.0 / mass);

You can see from above that if your mass is 1, then an instant fix will occur.

However, steering with the rate of change dependent on mass might be silly for most games. Usually you just want to directly tune the scaling factor by hand as a designer, within a range of 0 to 1 (or negative, or higher than 1 if you want):

velocity += direction * scalingFactor;
\$\endgroup\$
8
  • \$\begingroup\$ Thanks for answering. I made my question more specific, I've added the update() function of the agent. Please look at it and tell me if anywhere inside it happens a 'gradual' change in the velocity of the agent. \$\endgroup\$
    – Aviv Cohn
    Apr 13, 2014 at 21:16
  • \$\begingroup\$ @Prog Oh yes, so you can see that the "steering vector" is suddenly treated as input for force. You can use force to directly compute an acceleration vector. The larger your mass the slower the steer, this is where a gradual steer occurs. If mass is 1, then the force should apply an instantaneous fix. Please note that the code you're learning from is, in my opinion, pretty silly. Usually you'll want to have a tweakable parameter in the range of 0 to 1, to represent slow (near 0) or instant (near 1) changes. This is why I suggested you apply a unit-less scaling to the "steer vector". \$\endgroup\$
    – RandyGaul
    Apr 13, 2014 at 21:20
  • \$\begingroup\$ Let me see if I understand what you mean. Instead of writing Vector acceleration = force.divideBy(mass), I should write Vector acceleration = force.divideBy(someArbitraryFraction). I set someArbitraryFraction to whatever value fits my needs. If I want the agent to quickly turn around to face it's target, someArbitraryFraction would be small. If I want the agent to slowly turn around, someArbitraryFraction would be a big number. Is this correct? \$\endgroup\$
    – Aviv Cohn
    Apr 13, 2014 at 21:50
  • 1
    \$\begingroup\$ @Prog Yeah this is right! Usually you do multiplication instead since it is faster to multiply than to divide. Also, if you multiply your range of numbers is 0 to 1 for the scaling factor. If you are dividing your range is from 0 to infinity instead. The infinity part is not very intuitive to tweak. \$\endgroup\$
    – RandyGaul
    Apr 13, 2014 at 21:53
  • \$\begingroup\$ Apart from that specific change, is everything else I wrote 'correct' and standard-Seek-implementation? (Both in the update() function and the seek() function). \$\endgroup\$
    – Aviv Cohn
    Apr 13, 2014 at 21:55
1
\$\begingroup\$

This function appear strange because it does not actually compute force, it compute the delta in velocity (the change in velocity) which is needed in order for the agent to turn and pursue the target. It has nothing to do with force and mass and yet those are artificially squeezed in there for no reason.

If you want gradual change, compute the desired change (like you already do) and make partial changes each frame. This could be done in several ways, one is to cap the acceleration like you do with the velocity. The other is to compute the desired change and then multiply it by some fraction.

The change is gradual only when acceleration is bound or partial (e.g. 10% of the needed acceleration). Whenever acceleration is used to change velocity and velocity is not changed instantly to a new value, you get the desired gradual smoothness. In this case there does not appear to any gradual change. It appears that the change is instant. This is because the acceleration is not capped or multiplied by some fraction e.g. 0.05.

If you wish to make change smooth and gradual, simply multiply the acceleration by some fraction such as deltaTime (frame time) and perhaps cap it with some maximal value. Otherwise you are just setting the new velocity to the desired velocity for pursuit.

You can use:

acceleration = acceleration.normalize() * agent.getMaxAcceleration();
velocity = velocity.add(acceleration);

@RandyGaul was the first to answer correctly

\$\endgroup\$
4
  • \$\begingroup\$ Yeah you're right. A mass of 1 would apply no down-scaling and apply an instant fix. I said the same thing in my answer I think. \$\endgroup\$
    – RandyGaul
    Apr 13, 2014 at 21:26
  • \$\begingroup\$ Yeah, I guess I started typing before I read. :/ \$\endgroup\$
    – AturSams
    Apr 13, 2014 at 21:30
  • \$\begingroup\$ No problem I don't mind :P \$\endgroup\$
    – RandyGaul
    Apr 13, 2014 at 21:31
  • \$\begingroup\$ It's funny I read enough to upvote and then begun to type. :p \$\endgroup\$
    – AturSams
    Apr 13, 2014 at 21:34

You must log in to answer this question.

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