This week in Creators we did a very fun project – we learned how to simulate creatures with a kind of basic artificial intelligence and their own hopes, dreams and aspirations! We made an app where a bunch of creatures desired to spell the word “Creators” and were also scared of the mouse.
Click on the image below to play with our completed animation.

All the code is on the creators github as usual! Pretty cool eh? How did we get it working?
The evolution of Consciousness
At the start we chatted about an interesting channel on youtube called Kurzgesagt which contains short videos on all sorts of interesting topics. A recent video I watched discussed the notion of consciousness and how it might have evolved and it inspired the project. Though a lot is speculation about this topic, the video made a reasonable argument that consciousness evolved as a survival tool to allow simple creatures to seek energy (food) and flee from creatures that wanted to eat them. Watch the video, it’s very good!
Though we aren’t quite at the stage where we are ready to code up conscious beings – it was interesting to think about how we might add needs and desires to a character, so that’s what we looked at!
Reynold’s Steering Behaviours for Autonomous Characters
Having decided that we wanted some creatures that moved to the beat of their own drum, we next needed to figure out how to implement it. There are LOTS of pretty complicated strategies for simulating intelligence, but we looked at a brilliant research paper published in 1999 by a playstation programmer called Craig Reynolds called Steering Behaviours for Autonomous characters – read the full paper here. In this paper, Reynolds describes a simple but fantastic way to model “autonomous” characters using forces.

An “Autonomous” character is one that controls or powers itself – i.e. there is no remote control here! There is a lot in Reynolds paper but the basic idea is to think of some “behaviours” that a creature might exhibit – these could be:
- Flee: perhaps the creature might want to escape from someone?
- Seek: perhaps the creature might want to get somewhere really quickly?
- Arrive: perhaps a creature might want to get somewhere and stay there (i.e. slow down to “arrive” there.
- Be close to other creatures: perhaps a creature might want to be close to creatures like them
- etc – basically anything you can think of nearly!
In Reynold’s paper, creatures generally have a limited vision, and can have more than one behaviour happening at once – i.e. I really want to get food, but want to avoid the predator in the way.
The simple but powerful that Reynolds came up with is the idea of using forces to describe these behaviours and letting newton sort it out. To model a Reynolds behaviour, you:
- Determine your DESIRED velocity for this behaviour – this is a force describing how badly you want to escape the predator, or pursue the target, or avoid the obstacle, etc
- You STEERING force vector is worked out as:
steering = desired – velocity
With this simple looking formula, and behaviour rules you combine, you can create some great behaviours that can seem to have realistic looking intelligence behind them.
The Code
Because Reynolds uses force, we had an object which could be a good starting point developed way back in Week 8 – our fun with forces model was a perfect starting point since we already had a “Mover” object that had an applyForce function to allow you to add a force to it.
Our movers “seek” home and “flee” the mouse
All we needed to do was to add some “personality” to our Mover so that it decided itself where it wanted to move to. These are called “behaviours” in Reynolds brilliant paper. We decided that our first Mover would have a “timid, homebird” personality and it would have two desires: to get home (some location that is dear to it!), and to stay away from the mouse. We decided that when it is “afraid” of the mouse we should add something visual to let us know it was afraid – we coloured it red.
The first and easiest code to add was the code to make the Mover want to go home:
goHome(){
// i want to go home
let desired = p5.Vector.sub(this.home, this.position);
desired = desired.limit(this.maxSpeed);
let steering = p5.Vector.sub(desired, this.velocity);
this.applyForce(steering);
}
This is a good example of the process – first we create a Vector that describes where we want to go (home – location), next we limit it to the maximum speed of the Mover. Next we use the magic formula of Steering = Desired – Velocity to find what the steering force should be. (This looked okay for us, but in Reynold’s paper he recommended a maximum steering force so it doesn’t steer too quickly – good idea but we didn’t bother with it!). We called this “goHome” but Reynolds calls this the “Seek” behaviour.
flee(){
// i am scared of the mouse
let mousePosition = createVector(mouseX, mouseY);
let desired = p5.Vector.sub(this.position, mousePosition);
let dist = desired.mag();
if(dist < 100){
desired = desired.limit(this.maxSpeed);
let steering = p5.Vector.sub(desired, this.velocity);
this.applyForce(steering.mult(10));
this.isAfraid=true;
} else {
this.isAfraid = false;
}
}
The next steering behaviour was fear of the mouse. We added this as per the above “flee” method. We imagined that our little creatures can see the mouse when it’s 100 pixels away, and if it is, then it’s afraid and a very strong “flee” force is present. In the show method we decided to show the fear by turning it red (we should have drawn e.g. a scared face or something).
Finally, we add a function which calls the behaviours in turn:
applyBehaviours(){
this.flee();
this.goHome();
}
In each draw loop instance, we call the applyBehaviours, just like we call the “move” method and the “show” one.
That’s it! That’s all it took to give our creatures the desired behaviours!
Drawing a message:
The code to draw a message came from a hidden feature of the font class in p5 – the ability to get points from text with textToPoints. This allowed us to get a bunch of points to set as home which spelled a message. Depending on your computer, it could run a little slow so you might want to just add every 2nd points (takes a while to paint on my phone, but looks quite good on my laptop!).
function preload(){
font = loadFont("fonts/AvenirNextLTW01-Medium.ttf");
}
function setup() {
createCanvas(innerWidth, innerHeight);
textFont(font);
points = font.textToPoints("Creators", 100, height/2, 300);
for(let i=0; i< points.length; i++){
let startPosition=createVector(points[i].x, points[i].y);
movers.push(new Mover(random(10,30), startPosition));
}
}