here is an example (processing, not p5)
- he’s following the points stored in targets
- variable easing dictates how tight the curves are
- activeSteering() is the interesting part
- maybe it’d look cooler when he’d turn on the screen borders instead of crossing them
Chrisir
// Walker towards targets
Branch branch;
PVector[] targets = new PVector[15];
int indexTarget=0;
//easing for the angle
float easing = 0.23; // 0.061288;
int timer;
void setup() {
size(990, 800);
background(0);
branch = new Branch(width / 2, height / 2);
// fill targets randomly
for (int i2=0; i2<targets.length; i2++) {
targets[i2] = new PVector (random(width), random(height));
}
timer = millis();
}// func
void draw() {
// background(0);
// readKeys();
branch.update();
// show target
showTargets();
// after timer is up
if (millis()-timer>1000) {
// active steering
activeSteering();
}//if timer
//
}//func
//-----------------------------------------------------------------------------------------------------
void showTargets() {
// show current target
// fill(255, 0, 0);
// noStroke();
// ellipse (targets[indexTarget].x, targets[indexTarget].y, 17, 17);
// show ALL targets
int i3=0;
strokeWeight(1);
for (PVector pv : targets) {
stroke(111);
// different shades of red
fill( map(i3, 0, targets.length, 40, 255), 0, 0);
// show current target in BLUE
if (i3==indexTarget)
fill(0, 0, 255); //BLUE
ellipse (pv.x, pv.y,
17, 17);
i3++;
}
}//func
void activeSteering() {
// active steering
// core idea
float targetAngle=getAngle();
// showLine(targetAngle); // only for debug
if (targetAngle>branch.a)
branch.turn(1 * easing);
else if (targetAngle<branch.a)
branch.turn(-1 * easing);
else if (targetAngle==branch.a) {
// ignore
// branch.a = 0;
}
// when we reach a target we go to next target
if (dist(targets[indexTarget].x, targets[indexTarget].y, branch.x, branch.y)<2) {
indexTarget++;
// easing+=.103; // change it
println("ellipse: "
+indexTarget
+" with easing: "
+easing);
timer = millis(); // timer
// make a random deviation
if (random(100) > 50)
branch.turn(random(4));
else
branch.turn(-random(4));
// end of array?
if (indexTarget>=targets.length)
indexTarget=0; //reset
}//if
}//func
void readKeys() {
/*
if (keyPressed) {
if (keyCode == LEFT) {
branch.turn(1);
} else if (keyCode == RIGHT) {
branch.turn(-1);
} else if (keyCode == UP) {
branch.changeSpeed(1);
} else if (keyCode == DOWN) {
branch.changeSpeed(-1);
}
}
*/
}// func
void showLine(float a) {
// only for debug
pushMatrix();
translate(branch.x, branch.y);
rotate(a);
translate(28, 0);
fill(0, 0, 255);
rect(-30, -5, 60, 10);
popMatrix();
}
float getAngle() {
// core idea
float a = atan2(
targets[indexTarget].y-branch.y,
targets[indexTarget].x-branch.x);
//----------------------------------------
if (a<0) {
a=map(a, -PI, 0,
PI, TWO_PI);
}
return a;
}
//==========================================================================
class Branch {
float x, y; // pos
float px, py; // prev pos
float s, // speed
a, // angle
d; // damping?
Branch(float _x, float _y) {
this.x = _x;
this.y = _y;
this.px = _x;
this.py = _y;
this.s = 1;
this.a = TWO_PI-PI/2; // PI;
this.d = 0.05;
}
void update() {
this.move();
this.checkEdges();
this.show();
}
void move() {
this.px = this.x;
this.py = this.y;
this.x = this.px + cos(this.a) * this.s;
this.y = this.py + sin(this.a) * this.s;
}
void checkEdges() {
if (this.x > width) {
this.x = 0;
this.px = this.x;
} else if (this.x < 0) {
this.x = width;
this.px = this.x;
}
if (this.y > height) {
this.y = 0;
this.py = this.y;
} else if (this.y < 0) {
this.y = height;
this.py = this.y;
}
}
void turn(float _t) {
this.a += _t * this.d;
}
void changeSpeed(float _s) {
this.s =
constrain(this.s + (_s * this.d), 0, 3);
}
void show() {
// stroke(255);
stroke(0, 255, 0);
strokeWeight(3);
line(this.px, this.py,
this.x, this.y);
}
}//class
//