Sign in to follow this  

Sample source for the leader follow steering behavior

This topic is 3563 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all, I'm looking for some sample source code for the leader follow steering behavior. I already googled but didn't find anything. The applets on red3d.com don't have source code included. I theoretically know how the behavior works (combination of separation and arrival) but I my implementation doesn't work properly. Hope someone can help :)

Share this post


Link to post
Share on other sites
Ok I think that might be the best solution. I wrote an extra program using SDL to test out the steering stuff, so it's quite easy to post some code.

Here's the relevant code:

Vector2 truncateVector2(const Vector2 &vec,float maxLen) {
/*if (vec.lengthSq()>maxLen) {
return vec.normalizedCopy()*maxLen;
}*/

return vec;
}

class Unit {
private:
Vector2 m_pos;
Vector2 m_vel;
Vector2 m_targetPos;

static const float maxSpeed;
static const float maxForce;
static const float arrivalSlowingDistance;
static const float radius;

public:
Unit(const Vector2 &pos):m_pos(pos),m_targetPos(pos) {}

const Vector2 &getPosition() const { return m_pos; }

void update(float secsPerFrame,const std::vector<Unit> &otherUnits);

void addCommand(const Vector2 &targetPos);
void addForce(const Vector2 &force);
Vector2 computeArrivalSteeringForce(const Vector2 &targetPos) const;
Vector2 computeSeparationSteeringForce(const std::vector<Unit> &otherUnits) const;
};

const float Unit::maxSpeed = 100.0f;
const float Unit::maxForce = 100.0f;
const float Unit::arrivalSlowingDistance = 100.0f;
const float Unit::radius = 40.0f;

void Unit::update(float secsPerFrame,const std::vector<Unit> &otherUnits) {
Vector2 force = computeSeparationSteeringForce(otherUnits)*2.0f;
force += computeArrivalSteeringForce(m_targetPos)*1.0f;

addForce(force);

m_pos += m_vel*secsPerFrame;
}

void Unit::addCommand(const Vector2 &targetPos) {
m_targetPos=targetPos;
}

void Unit::addForce(const Vector2 &force) {
m_vel += truncateVector2(force,maxForce);
m_vel = truncateVector2(m_vel,maxSpeed);
}

Vector2 Unit::computeArrivalSteeringForce(const Vector2 &targetPos) const {
Vector2 target_offset = targetPos - getPosition();
if (target_offset == Vector2::ZERO) {
return Vector2::ZERO;
}
float distance = target_offset.length();

float ramped_speed = maxSpeed * (distance / arrivalSlowingDistance);
float clipped_speed = std::min(ramped_speed, maxSpeed);
Vector2 desired_velocity = (clipped_speed / distance) * target_offset;
return desired_velocity - m_vel;
}

Vector2 Unit::computeSeparationSteeringForce(const std::vector<Unit> &otherUnits) const {
Vector2 desired_velocity;
for (std::vector<Unit>::const_iterator unitIter=otherUnits.begin(); unitIter!=otherUnits.end(); ++unitIter) {
Vector2 diff=getPosition()-unitIter->getPosition();
float lenSq=diff.lengthSq();
if (lenSq<radius*radius) {

//diff.normalize();
//diff *= 1.0f/lenSq;
desired_velocity += diff;//-m_vel;
}
}

return desired_velocity;// - m_vel;
}

std::vector<Unit> g_units;

void move(float secsPerFrame) {
for (std::vector<Unit>::iterator unitIter=g_units.begin(); unitIter!=g_units.end(); ++unitIter) {
unitIter->update(secsPerFrame,g_units);
}
}

void addCommand() {
int x,y;
SDL_GetMouseState(&x,&y);

for (std::vector<Unit>::iterator unitIter=g_units.begin(); unitIter!=g_units.end(); ++unitIter) {
unitIter->addCommand(Vector2(x,y));
}
}





the addCommand function is called each time the mouse is moved and just updates the target position. move is called each frame. Note: the units actually don't follow a leader but just the mouse cursor. But that shouldn't be a problem, right? The problem is that the units are jittering around while moving, the motion is not as smooth as in the applets on steeringbehaviors.de

Hope someone can help :)

(hmm the cpp tag doesn't work?)

Edited by moderator to fix 'source' tags

[Edited by - Timkin on February 17, 2008 8:03:58 PM]

Share this post


Link to post
Share on other sites
(use the 'source' and '/source' tags for code...remove the quotes and replace with square brackets)

I've only taken a quick pass over your code as I'm a bit swamped at the moment... but as I see it the following is a problem


void Unit::addForce(const Vector2 &force) {
m_vel += truncateVector2(force,maxForce);
m_vel = truncateVector2(m_vel,maxSpeed);
}


Simple kinematics tells us that v = u + at and a = F/m. So, your code should be

m_vel += truncateVector2(force,maxForce)*secsPerFrame;

and then truncate it as needed. Of your object does not have unit mass then it should be force/mass in the above equation.

I'll try and find time to look further into your code later today or tonight.

Cheers,

Timkin

Share this post


Link to post
Share on other sites
Thanks very much for your answer!
I tried out your suggestion, however when changing
m_vel += truncateVector2(force,maxForce);

to
m_vel += truncateVector2(force,maxForce)*secsPerFrame;


the units move very slowly because here
m_pos += m_vel*secsPerFrame;


I already multiply with secsPerFrame.

If it helps I can also post the complete code (only uses SDL) to make it easier to test ...

Share this post


Link to post
Share on other sites
That's not an error... it's just the approximation scheme you're using.

Here is my advised scheme (again I'm assuming a unit mass particle)

Inputs:

x(t): position at time t
v(t): velocity at time t
f(t): net force at time t
Δt: time step

Outputs:
x(t+Δt): position at time t+Δt
v(t+Δt): velocity at time t+Δt


x(t+Δt) = x(t) + v(t)Δt + 1/2f(t)Δt2
v(t+Δt) = v(t) + f(t)Δt

This is equivalent to writing
v(t+Δt) = v(t) + f(t)Δt
x(t+Δt) = x(t) + (v(t) + v(t+Δt))Δt/2

which uses a first order approximation scheme


If you find that your particles are moving too slowly, then you need to simply increase the forces applied on them per unit time... or decrease their mass.

Cheers,

Timkin

Share this post


Link to post
Share on other sites
Thanks for your answer. I tried out your solution, but now it doesn't work at all. Perhaps I'm doing something wrong ...

I think the best is to post the complete code. You only need SDL to compile. The unit.bmp is a simple 32x32 circle image.

[url=http://www.file-upload.net/download-676797/steering.zip.html]Here it is![/url]

[Edited by - unsigned short on February 19, 2008 2:58:13 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by unsigned short
Thanks for your answer. I tried out your solution, but now it doesn't work at all. Perhaps I'm doing something wrong ...

I think the best is to post the complete code. You only need SDL to compile. The unit.bmp is a simple 32x32 circle image.

[url=http://www.file-upload.net/download-676797/steering.zip.html]Here it is![/url]


I'm sorry but I don't have time to review your complete code (nor install SDL)... the teaching semester is about to start and I'm flat out. I'll do my best to come back to this when I have some time, but I cannot promise that will be any time soon. Sorry.

I hope you're able to locate your problem soon.

Cheers,

Timkin

Share this post


Link to post
Share on other sites
A few quick questions/points of interest:

1. Have you tested the steering behaviors individually yet? Test the arrival behavior by itself using a single unit to verify that it specifically isn't the problem. Test only the separation behavior with a few units starting in close proximity to make sure that they escape in the expected directions.

2. Your description of the problem is kind of vague.....but it sounded like they are following the leader and separating, but just jittering around as they do it. Have you considered that your weighting of the two steering force vectors isn't balanced properly? Perhaps the separation behavior is overpowering the arrival behavior by too great a margin? Weighting multiple steering behaviors against eachother to achieve a desired result tends to be a process of incremental tweaking.

3. Some jittering is to be expected from certain combinations of steering behaviors. An easy solution to just average a unit's heading over a certain number of previous frames to eliminate some of the unnecessary back-and-forth.

Share this post


Link to post
Share on other sites
1. Yeah I tested them and they worked fine.
2. Yeah thats pretty much the problem. When the units are moving, they are like bumping together repeatedly / jittering around. When they are reaching the target location, they keep jittering and don't come to a standstill. Might be that the steering forces are not balanced properly. I tried out some values but when setting the separation too low, they are crowding together.
3. I read about that approach and it seems pretty reasonable because it smoothens the movement. I also tried to implement it some time ago. I added an array of velocities and calculated the average. But it didn't change anything :(

Share this post


Link to post
Share on other sites

This topic is 3563 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this