Introduction to Steering Behavior for Autonomous Agents in P5.js

Arnauld AlexArnauld Alex
9 min read

TL;DR ๐Ÿ“

Steering behaviors are algorithms that control the movement of autonomous agents, making them navigate environments, avoid obstacles, and interact with other agents in a lifelike manner. Key behaviors include seek (moving towards a target), flee (moving away from a target), wander (introducing randomness), and evasion and pursuit (predicting future positions for dynamic interactions). These behaviors are essential in simulations, games, and robotics for creating intelligent and responsive agents.

Steering Behaviors for Moving Agents

What are steering behaviors?

Steering behaviors are algorithms used to control the movement of autonomous agents in a realistic and dynamic manner. These behaviors allow agents to navigate their environment, avoid obstacles, and interact with other agents. Steering behaviors are essential in simulations, games, and robotics, where lifelike movement and decision-making are crucial. They combine simple rules to produce complex and adaptive behaviors, making agents appear intelligent and responsive.

GIF - Autonomous agents

Seek and flee behaviors

Seek and flee are fundamental steering behaviors that dictate how an agent moves in relation to a target.

  • Seek: This behavior causes an agent to move towards a target. It is useful for scenarios where an agent needs to reach a specific location.

  • Flee: This behavior makes an agent move away from a target. It is often used in situations where an agent needs to avoid danger or escape from a threat.

Both behaviors are based on calculating the desired velocity and adjusting the agent's current velocity to achieve the desired movement.

Seek: Moving towards a target

The seek behavior involves guiding the agent towards a target by calculating a steering force. The key steps are:

  • Determine the direction: Calculate the vector from the agent's position to the target's position. Desired velocity direction.

  • Adjust to maximum speed: Scale this direction vector to the agent's maximum speed.

  • Calculate the steering force: Adjust the agent's current velocity to move towards the desired direction, limiting the force to the agent's maximum allowable force.

Here's how the seek behavior can be implemented in code :

/* Main Class */
function draw() {
    // ...
    let steering = seeker.seek(target.position);
    seeker.applyForce(steering);
    // ... 
}

/* Agent Class */
// return the force, seeking is just steering to a target
seek(seekTargetPosition) {
    return this.steer(seekTargetPosition);
}

// return the steering force toward a target
steer(targetPosition) {
    // Determine the direction to target
    let steering = p5.Vector.sub(targetPosition, this.position);
    // Adjust to maximum speed
    steering.setMag(this.maxSpeed);
    // Calculate the steering force (desired - velocity)
    steering.sub(this.velocity);
    // Limit the magnitude of the steering force
    steering.limit(this.maxForce);

    // For steering function I prefer returning the force than applying
    // it, to have more control later.
    return steering;
}

applyForce(force) {
    this.acceleration.add(force);
}

update() {
    this.velocity.add(this.acceleration);
    this.velocity.limit(this.maxSpeed);
    this.position.add(this.velocity);
    this.acceleration.mult(0);
}

Here you can see the direction in red dashed line, velocity in green and steering vector in blue. The seeker agent is set to have a lower force than the red agent. Making it harder to turn.

Find the code here : Seek Algo ๐Ÿ”—

Flee: Moving away from a target

The flee behavior is the opposite of seek. That's all ๐Ÿ™Œ

Here's how the flee looks like in code, based on previous seek demonstration base :

/* Main Class */  
function draw() {
    // ...
    // Check a distance condition to apply flee force, otherwise it will flee
    // forever from the target
    if (runner.position.dist(target.position) < FLEE_DISTANCE) {
        let steering = runner.flee(target.position);
        runner.applyForce(steering);
    }
    // ...
}

/* Agent Class */
flee(fleeTargetPosition) {
    // .mult(-1) is to have the inverse of seek force
    return this.seek(fleeTargetPosition).mult(-1);
}

You can see that the runner is fleeing from the target when inside the perimeter.

Find the code here : Flee Algo ๐Ÿ”—

Wander behavior

Wander behavior introduces randomness into an agent's movement, making it appear more natural and less predictable. This behavior is useful for creating lifelike and exploratory movement patterns. You might have noticed it from the last two examples (the target). There are numerous wandering algorithms available, and here is the first one I used :

/* Agent Class */
constructor(x, y) {
    // ... 
    this.xoff = 0;
}

wanderXOff() {
    let angle = noise(this.xoff) * TWO_PI * 2;
    let steer = p5.Vector.fromAngle(angle);
    steer.setMag(this.maxForce);
    this.applyForce(steer);
    this.xoff += 0.01;
}

For another project I'll present to you in a future post, I used this one :

/* Agent Class */
constructor(x, y) {
    // ... 
    this.randomDirectionFactor = 0.5;
}

wanderAnts() {
    if (random() < this.randomDirectionFactor) {
        let angle = random(TWO_PI);
        let steer = p5.Vector.fromAngle(angle);
        steer.setMag(this.maxForce);
        this.applyForce(steer);
    }
}

/* Main class */
function draw() {
    background(2, 6, 23);

    wanderer_xoff.wanderXOff();
    // ...
    wanderer_smoother.wanderAnts();
    // ...
}

As you can see, both behave differently. One is smooth (wanderXOff - red) while the other one looks like an ant ๐Ÿœ (wanderAnts - salmon).

Find both examples here : Wander Algos ๐Ÿ”—

All in one examples

And here you are ๐Ÿ™Œ Congratulations ! You have acquired the fundamental knowledge to create autonomous agents. Now it's up to you to explore and imagine scenarios or simulations for your agents.

Stay tuned for my Ants project that I'll showcase in a future post ๐Ÿ“…

It can be planes, animals, cars...

Find the code here : All in one ๐Ÿ”—

For instance, in the next example, all red agents have the same velocity vector, avoid each other when very close, and avoid the blue agent when close enough. After a few seconds, the whole system seems natural and organic, yet it follows very simple rules.

function draw() {
    // ...
    agents.forEach(agent => {
        // Flee the wanderer
        let globalFleeForce = agent.fleeWithDistance(wanderer.position, 80);
        agent.applyForce(globalFleeForce);

        // Flee close agents
        agents.forEach(a => {
            if (a !== agent) {
                let localFleeForce = agent.fleeWithDistance(a.position, 20);
                agent.applyForce(localFleeForce);
            }
        });

        agent.warp();
        agent.update();
        agent.draw();
    });
}

Find the code here : Swarm ๐Ÿ”—

Evasion and Pursuit

Definition

In the previous sections, the demonstrated code for flee and seek are simple forms of direct evasion and pursuit, as the targets are moving. Typically, seek and flee behaviors are used for non-moving targets, while pursuit and evasion are for moving targets. This distinction highlights the dynamic nature of pursuit and evasion, where agents must continuously adjust their paths based on the predicted future positions of their moving targets.

  • Evasion and pursuit are complementary steering behaviors for autonomous agents. Evasion enables an agent to avoid being intercepted or caught by a pursuer. It focuses on escape and avoidance.

  • Pursuit involves an agent actively following and attempting to intercept a target. It emphasizes chasing and interception.

Use case

Evasion and pursuit behaviors are widely used to create dynamic and realistic interactions between agents. Evasion is crucial in video games for challenging enemy AI that avoids the player or other threats, in robotics for collision avoidance and safe navigation, and in simulations for modeling realistic interactions in scenarios such as crowd dynamics and animal behavior studies. Pursuit is commonly implemented in video games to create engaging chases, in security applications for surveillance systems to track and intercept intruders, and in simulations for modeling predator-prey dynamics, where predators chase and attempt to capture their prey. Evasion focuses on escape and avoidance, while pursuit emphasizes chasing and interception, both contributing to the realism and responsiveness of autonomous agents.

Prediction

Prediction is essential in steering behaviors, especially with moving targets. In evasion, an agent anticipates a pursuer's future position by considering its current velocity and position, using a prediction factor (e.g., 10 frames). This helps the evader plan its escape more effectively.

Similarly, in pursuit, an agent predicts the target's future position to intercept it efficiently. This predictive approach makes movements appear more intelligent and lifelike, enhancing realism and responsiveness in dynamic environments where both the pursuer and target are constantly moving.

class Agent {
    // ... (other methods)

    computePredictedPosition(target) {
          let targetPosition = target.position;
          let targetVelocity = target.velocity;
          // Multiply the target's velocity by the prediction factor (e.g., 10 frames)
          let futureVelocity = p5.Vector.mult(targetVelocity, 10);
          // Add the future velocity to the target's current position to get the predicted position
          let predictedPosition= p5.Vector.add(targetPosition, futureVelocity);
          return predictedPosition;
    }

    // ... (other methods)
}

Pursuit

The pursue method in the Agent class helps an agent chase a moving target. It predicts where the target will be using computePredictedPosition and then steers towards that spot with steer, that we previously saw. This makes the pursuit smarter and more effective.

class Agent {
    // ...

    pursue(target) {
          let prediction = this.computePredictedPosition(target);
          return this.steer(prediction); // Simple, isn't it ? 
    }

    // ...
}

Evasion

The evade method in the Agent class helps an agent escape from a pursuer. It essentially reverses the logic of the pursue method by multiplying the steering force by -1, making the agent move away from the predicted position of the target.

class Agent {
    // ...

    evade(target) {
          return this.pursue.mult(-1);
    }

    // ...
}

Conclusion

Recap of key concepts

Steering behaviors are algorithms that control the movement of autonomous agents, making them navigate environments, avoid obstacles, and interact with other agents in a lifelike manner. Key behaviors include:

  1. Seek and Flee:

    • Seek: Moves an agent towards a target by calculating a steering force.

    • Flee: Moves an agent away from a target, inverse of seek force.

  2. Wander: Introduces randomness into an agent's movement, creating natural and exploratory patterns.

  3. Evasion and Pursuit:

    • Pursuit: Involves an agent actively chasing a moving target by predicting its future position.

    • Evasion: Helps an agent avoid being intercepted by predicting the pursuer's future position. Inverse of pursuit force.

These behaviors are essential in simulations, games, and robotics for creating intelligent and responsive agents.

Applications of vector-based steering and evasion in P5.js

Vector-based steering and evasion behaviors have numerous applications in various fields. In video games, these behaviors enhance the realism and responsiveness of non-player characters (NPCs), making them appear more intelligent and lifelike. In robotics, vector-based steering is crucial for path planning, obstacle avoidance, and navigation, enabling robots to move efficiently and safely in dynamic environments. In simulations, these behaviors are used to model the movement of entities in virtual environments, such as crowd simulations, traffic flow, and animal behavior studies. By leveraging the power of vectors and steering behaviors, you can create more engaging and interactive experiences in their projects.

Future learning resources and next steps

To further enhance your understanding and skills in vector-based steering and evasion behaviors, consider exploring the following resources:

  • "Steering Behaviors For Autonomous Characters" by Craig W. Reynolds

  • "Artificial Intelligence for Games" by Ian Millington and John Funge

  • "Programming Game AI by Example" by Mat Buckland

  • "The Nature of Code" book and online tutorials by Daniel Shiffman

By exploring these resources, you can deepen your knowledge of vector-based steering behaviors and apply these concepts to create more sophisticated and dynamic autonomous agents in your projects.


Thank you for reading my blog ! If you enjoyed this post and want to stay connected, feel free to connect with me on LinkedIn. I love networking with fellow developers, exchanging ideas, and discussing exciting projects.

Connect with me on LinkedIn ๐Ÿ”—

Looking forward to connecting with you ! ๐Ÿš€

0
Subscribe to my newsletter

Read articles from Arnauld Alex directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Arnauld Alex
Arnauld Alex

I am a dedicated AI game programmer, former software engineer in aeronautics domain. With a strong passion for AI, game programming, and full-stack development. I thrive on learning new technologies and continuously improving my skills. As a supportive and collaborative person, I believe in adding value to every project and team I work with. Connect with me on LinkedIn