Draws abstract shapes using a list of turtles where each turtle moves towards another turtle in the list.
Log in to post a comment.
// You can find the Turtle API reference here: https://turtletoy.net/syntax
// Line color
Canvas.setpenopacity(-0.25);
// Canvas is 200x200
const canvas_size = 200;
// Number of turtles
const turtles = 200; // min=1, max=500, step=1
// Offset between turtle and follower
const follower_offset = 3; // min=1, max=10, step=1
// When initially positioning turtles, the length increment on each point in the spiral
const spiral_length_increment = 5; // min=0, max=100, step=1
// When initially positioning turtles, the degree increment on each point in the spiral
const spiral_degree_increment = 15; // min=1, max=360, step=1
// Number of generations to draw
const generations = 400; // min=1, max=1000, step=5
// Number of generations to skip before putting the pen down
const skip_generations = 40; // min=0, max=1000, step=5
// Step length when moving towards next turtle
const step_length = 18; // min=1, max=100, step=1
// How much to change the step length on each generation
const step_increment = -1; // min=-10, max=10, step=1
// Create and position the turtles
const turtle_list = new Array(turtles);
for (i=0; i<turtles; i++) {
const turtle = new Turtle();
let position = pointAt(0, 0, radians(spiral_degree_increment * i), (spiral_length_increment * i));
turtle.penup();
turtle.goto(position[0], position[1]);
turtle_list[i] = turtle;
}
// Connect each turtle to the target turtle it is following
for (i=0; i<turtles; i++) {
let target_index = i+follower_offset;
if (target_index >= turtles) {
target_index -= turtles;
}
turtle_list[i].target = turtle_list[target_index];
}
let generation_index = 0;
let phase = 0;
let turtle_index = 0;
let current_step_length = step_length;
// The walk function will be called until it returns false.
function walk(i) {
const turtle = turtle_list[turtle_index];
if (phase == 0) {
turtle.angle = angle_to(turtle.x(), turtle.y(), turtle.target.x(), turtle.target.y());
} else if (phase == 1) {
let position = pointAt(turtle.x(), turtle.y(), turtle.angle, current_step_length);
if (generation_index >= skip_generations) {
turtle.pendown();
}
turtle.goto(position[0], position[1]);
}
if (turtle_index >= (turtles - 1)) {
turtle_index = 0;
phase++;
} else {
turtle_index++;
}
if (phase > 1) {
phase = 0;
generation_index++;
current_step_length += step_increment;
if (current_step_length < 1) {
current_step_length = 1;
}
}
return generation_index < generations;
}
function radians(angle) {
return angle * (Math.PI / 180);
}
function pointAt(x, y, radians, distance) {
let new_x = x + (distance * Math.cos(radians));
let new_y = y + (distance * Math.sin(radians));
let clipped_x = new_x % (canvas_size / 2);
let clipped_y = new_y % (canvas_size / 2);
return [clipped_x, clipped_y];
}
function angle_to(x1, y1, x2, y2) {
atan_radians = Math.atan2(y2 - y1, x2 - x1);
if (atan_radians >= 0) {
return atan_radians;
} else {
return Math.PI * 2 + atan_radians;
}
}