Attracted circles

Experimenting with attractors

Log in to post a comment.

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


const circles = 40;//min = 1, max = 250, step = 1

//const force = 30;// min = -200, max = 200, step = 1
const attractors = 2;//min = 1, max = 50, step = 1

const resolution = 0.5;//min = 0.01, max = 1, step = 0.01

// help function to compute the distance from a point (i.e., the hypothenuse of a triangle rectangle)
function distance(x, y){
    return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
}

// An attractor is a point which deflects drawing. It has a position and a force.
class Attractor{
    constructor(x = 0, y = 0, force = 0){
            this.x = x;
            this.y = y;
            this.force = force;
            
            if( x == 0 && y == 0 && force == 0){
            this.x = Math.random() * 200 - 100;
            this.y = Math.random() * 200 - 100;
            this.force = Math.random() * 200;
        }
    }
}

// Class that handle tracing of circles, and their behavior regarding attractors.
class Circle{
    constructor(size = 25){
        this.size = size;
        this.centerX = 0;
        this.centerY = 0;
        this.angle = 0;
        this.turtle = new Turtle();
        this.turtle.jump(0, size);
    }
    
    attract(a){
        this.attractors = a;
    }
    
    walk(){
        let radAngle = this.angle * Math.PI / 180;
        
        this.x = Math.sin(radAngle) * this.size;
        this.y = Math.cos(radAngle) * this.size;
        
        if(this.attractors){
            let delta;
            let coef;
            for(let item of this.attractors){
                let deltaX = this.x - item.x;
                let deltaY = this.y - item.y;
                
                delta = distance(deltaX, deltaY);
                coef = Math.pow(item.force/delta, 2);
                
                let moveX = (deltaX / delta) * coef;
                let moveY = (deltaY / delta) * coef;
                
                let dist = distance(moveX, moveY);

//                if(item.force > 0){
                    if(dist > delta){
                        // have to find a way to decrease attraction when move is > delta, instead of topping it.
                        moveX = deltaX;
                        moveY = deltaY;
//                        moveX *= delta / dist;
//                        moveY *= delta / dist;
                    }
//                } else {
/*
                    // same here : have to find a way to limit movement
                    if(distance < item.force / 4){
                        moveX /= 1/dist;
                        moveY /= 1/dist;
                    }
*/
 //                   moveX = -moveX;
 //                   moveY = -moveY;
 //               }
                this.x -= moveX;
                this.y -= moveY;
            }
        }
        if(this.angle == 0) this.turtle.jump(this.x, this.y);
        else this.turtle.goto(this.x, this.y);
        this.angle += resolution;
        
        if(this.angle >= 360) return false;
        return true;
    }
}

// generate random attractors.
const attractorList = [];

for(let i = 0; i < attractors; i++){
    attractorList.push(new Attractor());
}


//attractorList.push(new Attractor(60, 0, 40));
//attractorList.push(new Attractor(-40, 40, -40));

//generate the circles.
const circleList = [];

for (let i = 0; i < circles; i++){
    circleList[i] = new Circle((100 / circles) * (i + 1));
    circleList[i].attract(attractorList);
}


// The walk function will be called until it returns false.
function walk(i) {
    let goOn = true;
    
    for(let item of circleList){
        goOn = item.walk();
    }
    
    return goOn;
}