Sample source for the leader follow steering behavior

Started by
12 comments, last by unsigned short 16 years, 1 month ago
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 :)
Advertisement
The author refers to the OpenSteer project that contains implementations for all the described behaviours.
OpenSteer doesn't contain any source for the leader follow steering behavior. This is also mentioned in the library's documentation.
If you're happy to post your implementation (jut the relevant parts) we can take a look at it and try and work out why it isn't working.
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]
(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
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 ...
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 stepOutputs:   x(t+Δt): position at time t+Δt   v(t+Δt): velocity at time t+Δtx(t+Δt) = x(t) + v(t)Δt + 1/2f(t)Δt2v(t+Δt) = v(t) + f(t)ΔtThis is equivalent to writingv(t+Δt) = v(t) + f(t)Δtx(t+Δt) = x(t) + (v(t) + v(t+Δt))Δt/2which 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
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.

Here it is!

[Edited by - unsigned short on February 19, 2008 2:58:13 AM]
Hm no ideas? Btw how does the url tag work?^^

This topic is closed to new replies.

Advertisement