/* built with Studio Sketchpad:
* https://sketchpad.cc
*
* observe the evolution of this sketch:
* https://studio.sketchpad.cc/sp/pad/view/ro.e82yjajYoj0/rev.223
*
* authors:
* Dave Vickery
* license (unless otherwise specified):
* creative commons attribution-share alike 3.0 license.
* https://creativecommons.org/licenses/by-sa/3.0/
*/
// This sketch builds on a prior work, "Gammy Horse Race Simulator", created by Dave Vickery & [unnamed author]
// http://studio.sketchpad.cc/sp/pad/view/ro.9ImkoHfwqLGdq/rev.3058
// Walker objects move at random but are biased towards the target
// Click anywhere on the screen to set the target. First horse to reach the target is declared the winner.
final float MAXSTEPSIZE = 10;
final int TICKLENGTH = 10;
final int TRAILLENGTH = 30;
final int GOALSIZE = 30;
final int HORSECOUNT = 5;
Walker[] entities;
int prevMillis = 0;
PVector target;
int winner = -1;
boolean racing = false;
PImage bg;
void setup() {
size(500, 300);
background(255);
target = new PVector(30, 30);
bg = createImage(width, height, RGB);
bg.loadPixels();
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
float bright = map(noise((float)x/15, (float)y/15), 0, 1, 150, 200);
bg.pixels[x+y*width] = color(0, bright, 0);
}
}
bg.updatePixels();
entities = new Walker[HORSECOUNT];
for (int i = 0; i < entities.length; i++) {
entities[i] = new Walker(""+(i+1), target);
entities[i].setGoal(target);
}
//generator = new Random();
noStroke();
fill(0);
}
void draw() {
if (millis() > prevMillis + TICKLENGTH) {
image(bg, 0, 0);
for (int i = 0; i < entities.length; i++) {
entities[i].step();
entities[i].display();
if (winner == -1 && entities[i].reachedGoal()) {
winner = i;
}
}
prevMillis = millis();
}
noFill();
stroke(255, 0, 0);
strokeWeight(2);
ellipse(target.x, target.y, GOALSIZE, GOALSIZE);
strokeWeight(1);
if (racing && winner > -1) {
fill(0);
text("Winner is number " + entities[winner].name + "!", 10, 20);
}
}
class Walker {
PVector[] points;
PVector goal = new PVector(0, 0);
String name;
color col;
Walker(String newName) {
this(newName, new PVector((int)random(width), (int)random(height)), color(random(255), random(255), random(255)));
}
Walker(String newName, PVector start) {
this(newName, start, color(random(255), random(255), random(255)));
}
Walker(String newName, PVector start, int startCol) {
points = new PVector[TRAILLENGTH];
for (int i = 0; i < points.length; i++) {
points[i] = new PVector();
points[i].set(start);
}
col = startCol;
name = newName;
}
void display() {
for (int i = 0; i < points.length; i++) {
float alpha = map(i, 0, points.length, 255, 0);
fill(col, alpha);
stroke(col, alpha);
if (i > 0) {
line(points[i].x, points[i].y, points[i - 1].x, points[i - 1].y);
}
ellipse(points[i].x, points[i].y, 4, 4);
}
}
void step() {
PVector goalBias = new PVector(0, 0);
if (goal.x < points[0].x) {
goalBias.x = -0.5;
} else {
goalBias.x = 0.5;
}
if (goal.y < points[0].y) {
goalBias.y = -0.5;
} else {
goalBias.y = 0.5;
}
for (int i = points.length - 1; i > 0; i--) {
points[i].set(points[i - 1]);
}
float randX;
do {
randX = random(-1 + goalBias.x, 1 + goalBias.x);
} while (random(1) < sq(randX));
float randY;
do {
randY = random(-1 + goalBias.y, 1 + goalBias.y);
} while (random(1) < sq(randY));
points[0].x = points[1].x + (int)(randX * MAXSTEPSIZE);
points[0].y = points[1].y + (int)(randY * MAXSTEPSIZE);
fill(0);
text(name, points[0].x, points[0].y);
}
void setGoal(PVector newGoal) {
goal.set(newGoal);
}
boolean reachedGoal() {
if (abs(points[0].x - goal.x) < (GOALSIZE / 2)
&& abs(points[0].y - goal.y) < (GOALSIZE / 2)) {
return true;
} else {
return false;
}
}
}
void mousePressed() {
target.x = mouseX;
target.y = mouseY;
for (int i = 0; i < entities.length; i++) {
entities[i].setGoal(target);
}
winner = -1;
racing = true;
}