Fork of Houses on path 🏠🌳 in christmas style.
Log in to post a comment.
// Forked from "Houses on path 🏠🌳" by markknol
// https://turtletoy.net/turtle/4c92500323
// You can find the Turtle API reference here: https://turtletoy.net/syntax
Canvas.setpenopacity(1);
const PATH_PRECISION = .5
const totalPathPoints = 180;
const totalPathSpiral1 = 0.69;
const totalPathSpiral2 = 0.13;
let houseWidth = 15;
houseWidth /= PATH_PRECISION;
let houseDistance = 25;
houseDistance /= PATH_PRECISION;
let houseHeight = 14;
let houseDepth = 10;
houseDepth /= PATH_PRECISION;
const roof = 25;
// 3d depth
const z = 0.9;
// Global code will be evaluated once.
const turtle = new Turtle();
turtle.pendown();
let path;
let objectId = (Math.random() * 777) | 0;
// The walk function will be called until it returns false.
function walk(i) {
if (i === 0) {
setup();
}
// line of the path
turtle.jump(path[i][0], path[i][1]);
turtle.goto(path[i+1][0], path[i+1][1]);
// houses
if (i > 4 && i % houseDistance === 0 && i + houseWidth+houseDepth < path.length - 1) {
if (Math.random() > 0.5) {
if (Math.random()>0.3) drawTree(i+ 5, houseHeight * 0.75);
if (Math.random()>0.3) drawTree(i+ 5 + houseWidth / 2, houseHeight);
if (Math.random()>0.3) drawTree(i+ 5 + houseWidth, houseHeight * 0.65);
} else if (Math.random() > 0.5) {
drawStar(i + 5, 10 + Math.random() * 15);
drawStar(i + 20, 10 + Math.random() * 15);
drawStar(i + 30, 10 + Math.random() * 15);
} else {
drawHouse(i, i+15);
}
objectId ++;
}
return i < path.length - 2;
}
function drawTree(x, treeHeight) {
for(let i = -1; i < 2; i+= 2) {
moveTo(path, x + 1 * dir);
lineTo(path, x + 1* dir, treeHeight * 0.25);
lineTo(path, x + 7* dir, treeHeight * 0.25);
if (i == -1) lineTo(path, x , treeHeight *2 );
}
}
function drawTree(x, treeHeight) {
moveTo(path, x - 1);
lineTo(path, x - 1, treeHeight * 0.25);
lineTo(path, x - 7, treeHeight * 0.25);
lineTo(path, x , treeHeight *2 );
lineTo(path, x + 7, treeHeight * 0.25);
lineTo(path, x + 1, treeHeight * 0.25);
lineTo(path, x + 1);
}
function drawStar(x,y) {
const s = 5;
const a = 0;
const t = 10;
for (let i=0; i<=t; i++) {
const l = s * (i % 2 ? 1 : .45);
const x1 = x+Math.cos(a + i/(t/2) * Math.PI)*l;
const y1 = y+Math.sin(a+i/(t/2)*Math.PI)*l;
if (i==0) moveTo(path, x1, y1);
else lineTo(path, x1, y1);
}
}
function drawHouse(x1,x2) {
var hasLine = Math.random()>.5;
var doubleLine = Math.random()>.5;
var windowHeight = 3;
// walls
moveTo(path, x1);
lineTo(path, x1, houseHeight);
var roofX = ((x1 + x2) * 0.5) | 0
lineTo(path, roofX, roof);
lineTo(path, x2, houseHeight);
lineTo(path, x2);
// 3d depth
line(path, roofX, roof* z, roofX + houseDepth, roof );
lineTo(path, x2 + houseDepth, houseHeight * z);
line(path, x2, houseHeight * z, x2 + houseDepth, houseHeight);
moveTo(path, x2 + houseDepth, houseHeight * z);
lineTo(path, x2 + houseDepth);
// wall/roof line
if (hasLine) line(path, x1, houseHeight, x2, houseHeight);
if (hasLine && doubleLine) {
line(path, x1, houseHeight-1, x2, houseHeight-1);
// double line
line(path, x2, houseHeight * z-1, x2 + houseDepth, houseHeight-1);
}
// door
var doorWidth = 3;
var doorX = Math.random() > 0.5 ? x1 + 2 : x2 - 2 - doorWidth;
moveTo(path, doorX);
lineTo(path, doorX, 5);
lineTo(path, doorX + doorWidth, 5);
lineTo(path, doorX + doorWidth);
// windows
for(let ii=0;ii<=2;ii++) {
var x = ii * 3;
if (Math.random()> 0.5 && 8+windowHeight < houseHeight) {
moveTo(path, x+x1 + 2, 8);
lineTo(path, x+x1 + 2, 8+windowHeight);
lineTo(path, x+x1 + 4, 8+windowHeight);
lineTo(path, x+x1 + 4, 8);
lineTo(path, x+x1 + 2, 8);
}
}
}
function getPos(path, x, y = 0) {
var idx = (x/PATH_PRECISION)|0;
var t = x - (idx * PATH_PRECISION); // 10.34 - 10 = 0.34
idx *= PATH_PRECISION;
idx = idx|0;
var p1 = path[idx+1];
var p2 = path[idx];
var p3 = path[idx-1];
var a1 = angle(p2, p1);
var a2 = angle(p3, p1);
// TODO: fix this interpolation somehow..
var xx1 = lerp(p2[0], p1[0], t);
var yy1 = lerp(p2[1], p1[1], t);
var a = lerpAngle(a1,a2,t) - Math.PI*0.5;
return [xx1 + Math.cos(a) * y, yy1 + Math.sin(a) * y];
var a = angle(p3, p1) - Math.PI*0.5;
return [
lerp(p1[0], p3[0], t) + Math.cos(a) * x,
lerp(p1[1], p3[1], t) + Math.sin(a) * y
]
}
function moveTo(path, x, y = 0) {
var pos = getPos(path, x, y);
turtle.jump(pos[0], pos[1]);
}
function lineTo(path, x, y = 0) {
var pos = getPos(path, x, y);
turtle.goto(pos[0], pos[1]);
}
function line(path, x1, y1, x2, y2, precision = PATH_PRECISION/2) {
var xa = Math.min(x1,x2);
var xb = Math.max(x1,x2);
for(let x=xa;x<=xb; x+=precision) {
var t=((xb-x)/(xb-xa));
if (x==x1) moveTo(path, x, lerp(y1,y2,t));
else lineTo(path, x, lerp(y1,y2,t));
}
//lineTo(path, xx, y2);
}
function setup(){
path = createPath();
path = normalizePath(path, PATH_PRECISION);
console.log(path);
}
// vec2 functions
const equal2=(a,b)=>.001>dist_sqr2(a,b);
const scale2=(a,b)=>[a[0]*b,a[1]*b];
const add2=(a,b)=>[a[0]+b[0],a[1]+b[1]];
const sub2=(a,b)=>[a[0]-b[0],a[1]-b[1]];
const dot2=(a,b)=>a[0]*b[0]+a[1]*b[1];
const dist_sqr2=(a,b)=>(a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1]);
const dist=(a,b)=>Math.sqrt(dist_sqr2(a,b));
const angle=(a,b)=>Math.atan2(b[1]-a[1], b[0]-a[0]);
const center=(a,b)=>[(a[0]+b[0])/2,(a[1]+b[1])/2];
const lerp=(a,b,t)=>a+(b-a)*t;
const clone=(a)=>[a[0],a[1]];
const clamp01=(t)=>Math.min(1.0,Math.max(0.0,t));
const randomRange=(a,b)=>a+Math.random()*(b-a)
const repeat=(t,l)=>t-Math.floor(t/l)*l;
const lerpAngle=(a,b,t) => {
let val = repeat(b - a, Math.PI*2);
if (val>Math.PI) val -= Math.PI*2;
return a + val * clamp01(t);
}
const createPath = ()=> {
const path = [];
const total = totalPathPoints;
for (let i = 0; i < total; i++) {
let r = i * totalPathSpiral1;
path.push([r * Math.cos(i*totalPathSpiral2) + Math.sin(i), r * Math.sin(i*totalPathSpiral2)+ Math.sin(i)]);
}
return path;
}
const normalizePath = (path, minDist) => {
var newPath = [];
let d = 0.0
let prev = path[0];
newPath.push(clone(prev));
for (let i = 1; i < path.length; i++) {
let curr = clone(path[i]);
d = dist(prev, curr);
var a = angle(prev, curr);
while (d > minDist) {
prev[0] += Math.cos(a) * minDist;
prev[1] += Math.sin(a) * minDist;
newPath.push(clone(prev));
d -= minDist;
}
}
return newPath;
}