Fork: Invaders
Added some controls to play around and some different generation options.
Log in to post a comment.
// Forked from "Invaders" by ge1doot
// https://turtletoy.net/turtle/46d50beb8a
// --- Print Configuration ---
const paperSize = 0; // min=0 max=1 step=1 (A4, A3)
const penWidthMM = 0.4; // min=0.1 max=2 step=0.05 (Actual width in mm)
// --- Design Controls ---
const gridCount = 12; // min=4 max=32 step=1 (Number of invaders)
const alienScale = 0.85; // min=0.1 max=1 step=0.05 (Invader scale)
const randomness = 0.5; // min=0.1 max=0.9 step=0.05 (Pixel density)
// --- Pixel Style ---
const pixelShape = 1; // min=0 max=1 step=1 (Circle, Square)
const fillEnabled = 1; // min=0 max=1 step=1 (Outline only, Fill/Hatch)
const hatchType = 2; // min=0 max=2 step=1 (Horizontal, Vertical, Diagonal)
const hatchDensity = 1.0; // min=0.5 max=3 step=0.1 (1 = Solid, >1 = More open)
// --- Internal Settings ---
const paperWidthMM = paperSize === 0 ? 210 : 297;
const scaleFactor = 200 / paperWidthMM;
const penSize = penWidthMM * scaleFactor;
Canvas.setpenopacity(1);
// Grid setup
const margin = 10;
const availableSize = 200 - (margin * 2);
const cellSize = availableSize / gridCount;
const pixelSize = (cellSize / 10) * alienScale;
const turtle = new Turtle();
// Helper to draw a Square (with optional hatching)
function drawSquarePixel(t, x, y, size) {
const r = size / 2;
// 1. Draw Outline
t.up();
t.jump(x - r, y - r);
t.down();
t.goto(x + r, y - r);
t.goto(x + r, y + r);
t.goto(x - r, y + r);
t.goto(x - r, y - r);
// 2. Draw Hatching (if enabled)
if (fillEnabled === 1) {
// Calculate step based on pen size and density
const step = penSize * hatchDensity;
if (hatchType === 0) { // Horizontal ZigZag
let currentY = -r + step;
let dir = 1;
t.up();
t.jump(x - r, y + currentY);
t.down();
while (currentY < r) {
t.goto(x + (dir * r), y + currentY);
currentY += step;
if (currentY < r) t.goto(x + (dir * r), y + currentY);
dir *= -1;
}
}
else if (hatchType === 1) { // Vertical ZigZag
let currentX = -r + step;
let dir = 1;
t.up();
t.jump(x + currentX, y - r);
t.down();
while (currentX < r) {
t.goto(x + currentX, y + (dir * r));
currentX += step;
if (currentX < r) t.goto(x + currentX, y + (dir * r));
dir *= -1;
}
}
else if (hatchType === 2) { // Diagonal (45 degrees)
t.up();
// Generate lines at 45 degrees (y = x + offset) and clip them to the square
for(let offset = -2*size; offset <= 2*size; offset += step) {
let x1 = -r, y1 = -r + offset;
let x2 = r, y2 = r + offset;
// Clip Y values to stay within -r and r
if (y1 < -r) { x1 += (-r - y1); y1 = -r; }
if (y1 > r) { x1 -= (y1 - r); y1 = r; }
if (y2 < -r) { x2 += (-r - y2); y2 = -r; }
if (y2 > r) { x2 -= (y2 - r); y2 = r; }
// Draw line if valid
if (x1 < r && x2 > -r && x1 < x2) {
t.up(); t.jump(x + x1, y + y1);
t.down(); t.goto(x + x2, y + y2);
}
}
}
}
}
// Helper to draw a Circle (concentric fill)
function drawCirclePixel(t, radius) {
const step = Math.max(penSize, radius/3);
let currentR = radius;
if (fillEnabled === 1) {
while(currentR > penSize/2) {
t.circle(currentR);
currentR -= step;
}
t.circle(0.1); // Center point
} else {
t.circle(radius);
}
}
// Main Loop
function walk(i) {
const col = i % gridCount;
const row = (i / gridCount) >> 0;
// Calculate cell position
const cellX = -100 + margin + (col * cellSize);
const cellY = -100 + margin + (row * cellSize);
// Center the 8x8 invader within the cell
const centeringOffset = (cellSize - (8 * pixelSize)) / 2;
const startX = cellX + centeringOffset;
const startY = cellY + centeringOffset;
// Generate and draw the 8x8 grid
for (let y = 0; y < 8; y++) {
let bits = [];
// Generate half the row and mirror it for symmetry
for(let b=0; b<4; b++) bits.push(Math.random() < randomness ? "1" : "0");
let fullRow = bits.concat(bits.slice().reverse());
fullRow.forEach((n, x) => {
if (n === "1") {
const px = startX + (x * pixelSize);
const py = startY + (y * pixelSize);
// 0.9 factor creates a small aesthetic gap between pixels
const visualSize = pixelSize * 0.9;
turtle.up();
turtle.goto(px, py);
turtle.down();
if (pixelShape === 0) {
drawCirclePixel(turtle, visualSize / 2);
} else {
drawSquarePixel(turtle, px, py, visualSize);
}
}
});
}
return i < gridCount * gridCount - 1;
}