The wanderers VI

Another noise field

Log in to post a comment.

// Forked from "The wanderers V" by troisiemetype
// https://turtletoy.net/turtle/286caa4360

// You can find the Turtle API reference here: https://turtletoy.net/syntax
Canvas.setpenopacity(0.5);

const size = 95;                //min = 10, max = 100, step = 5
const perlinSize = 3;           //min = 1, max = 10, step = 1
const turnRatio = 0.2;          //min = 0.1, max = 5, step = 0.1
const footStep = 0.2;           //min = 0.1, max = 2, step = 0.1
//const drawBoth = 2;             //min = 0, max = 2, step = 1,(no, yes, middle)

// Global code will be evaluated once.
const turtle = new Turtle();

class Perlin{
    constructor(size, gridSize){
        this.size = size;
        this.gridSize = gridSize;
        
        this.grid = [];
        
        // For each grid intersection, compute a random unit vector
        for(let i = 0; i <= gridSize; i++){
            let table = [];
            for(let j = 0; j <= gridSize; j++){
                
                let angle = Math.random() * 2 * Math.PI;
                let x = Math.cos(angle);
                let y = Math.sin(angle);

                table.push([x, y]);
//                console.log([x, y]);
            }
            this.grid.push(table);
        }
//        console.log(this.grid);
    }
    
    get(x, y){
        x = x / 2 + this.size / 2;
        y = y / 2 + this.size / 2;
        if(x < 0) x = 0;
        if(x >= this.size) x = this.size - 0.01;
        if(y < 0) y = 0;
        if(y >= this.size) y = this.size - 0.01;
        
//        console.log(x, y);
        
        let posx = x * this.gridSize / this.size;
        let posy = y * this.gridSize / this.size;
        
//        console.log(posx, posy);
        
        let x1 = Math.floor(posx);
        let x2 = x1 + 1;
        let y1 = Math.floor(posy);
        let y2 = y1 + 1;

        let scal = [];
        
        scal.push()
        
        scal.push(this.scalar(posx, posy, x1, y1));
        scal.push(this.scalar(posx, posy, x2, y1));
        scal.push(this.scalar(posx, posy, x1, y2));
        scal.push(this.scalar(posx, posy, x2, y2));
        
//        console.log(scal);

        // interpolate : linear interpolation for a start
        let int1 = this.interpolate(posx - x1, scal[0], scal[1]);
        let int2 = this.interpolate(posx - x1, scal[2], scal[3]);

//        console.log(int1, int2);
        
        return this.interpolate(posy - y1, int1, int2);
    }
    
    scalar(x, y, vx, vy){
        x -= vx;
        y -= vy;
//        console.log(x, y);
        return x * this.grid[vx][vy][0] + y * this.grid[vx][vy][1];
    }
    
    smooth(v){
        if(v < 0) v = 0;
        if(v > 1) v = 1;
        return v**2 * (3 - 2*v);

    }
    
    interpolate(x, a, b){
        return a + (b - a) * this.smooth(x)
    }
}

let perlin = new Perlin(size, perlinSize);

let startPositions = [];

for(let i = 0; i < 360; i++){
    let theta = Math.PI * i / 180;
    let x = Math.cos(theta);
    let y = Math.sin(theta);
    let ratio = 0;
    if(Math.abs(x) > Math.abs(y)) ratio = size / x;
    else ratio = size / y;
    ratio = Math.abs(ratio);

    x *= ratio;
    y *= ratio;
    startPositions.push([[x, y], i + 180]);
}

let posx = 0;
let posy = 0;

turtle.jump(startPositions[0][0]);
turtle.seth(startPositions[0][1]);

let gen = 0;

let step = 0;

let wait = Date.now();



// The walk function will be called until it returns false.
function walk(i) {
    
    if(Math.abs(posx) > size || Math.abs(posy) > size){
        step++;
        
        if(step >= startPositions.length) return false;

        turtle.jump(startPositions[step][0]);
        turtle.seth(startPositions[step][1]);

        gen++;
    }
    
    let turn = perlin.get(posx, posy)
    
    turtle.right(turn * turnRatio);
    turtle.forward(footStep);
    
//    console.log(turtle.pos(), turtle.heading());
    
    posx = turtle.x();
    posy = turtle.y();

//    while((wait) >= Date.now());
    wait = Date.now();
    

//    console.log(posx, posy);

    return true;
}