๐Ÿ“ฆ sbuggay / boids

๐Ÿ“„ boid.js ยท 136 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136const maxSpeed = 4;
const maxForce = 0.05;
const size = 15;
const maxPercieved = 30;

class Boid {
    constructor() {
        this.position = createVector(random(width), random(height));
        this.velocity = p5.Vector.random2D();
        this.acceleration = createVector();
        this.perception = 30;
        this.affected = false;
    }

    align(boids) {
        if (boids.length === 0) return;

        let wish = createVector();

        for (let boid of boids) {
            wish.add(boid.velocity);
        }

        wish.div(boids.length);
        wish.setMag(maxSpeed);
        wish.sub(this.velocity);
        wish.limit(maxForce);
        return wish;
    }

    cohesion(boids) {
        if (boids.length === 0) return;

        let wish = createVector();

        for (let boid of boids) {
            wish.add(boid.position);
        }

        wish.div(boids.length);
        wish.sub(this.position);
        wish.setMag(maxSpeed);
        wish.sub(this.velocity);
        wish.limit(maxForce);

        return wish;
    }

    separation(boids, d) {
        if (boids.length === 0) return;

        let wish = createVector();

        for (let boid of boids) {
            let d = dist(this.position.x, this.position.y, boid.position.x, boid.position.y);
            // if (d < (this.perception / 2)) {
                let diff = p5.Vector.sub(this.position, boid.position);
                diff.div(d ** 2);
                wish.add(diff);
            // }
        }

        wish.div(boids.length);
        wish.setMag(maxSpeed * 1.1);
        wish.sub(this.velocity);
        wish.limit(maxForce);

        return wish;
    }

    update(boids) {

        let count = 0;

        let localBoids = [];

        for (let boid of boids) {
            if (boid === this) continue;
            let d = (this.position.x - boid.position.x) ** 2 + (this.position.y - boid.position.y) ** 2;
            if (d < (this.perception) ** 2) {
                localBoids.push(boid);

            }
            count++;
            if (count >= maxPercieved) break;
        }

        this.acceleration.add(this.align(localBoids));
        this.acceleration.add(this.cohesion(localBoids));
        this.acceleration.add(this.separation(localBoids));

        this.affected = localBoids.length > 0;

        if (window.mouse) {
            if (window.mouse.x <= width && window.mouse.x >= 0 && window.mouse.y <= height && window.mouse.y >= 0) {
                const d = dist(this.position.x, this.position.y, window.mouse.x, window.mouse.y);
                const wish = p5.Vector.sub(createVector(window.mouse.x, window.mouse.y), this.position);
                wish.div(d ** 2);
                wish.mult(10);
                this.acceleration.add(wish);
            }
        }

        this.velocity.add(this.acceleration);
        this.velocity.limit(maxSpeed);
        this.position.add(this.velocity);
        this.acceleration.mult(0);

        if (this.position.x < 0 || this.position.x > width) {
            this.position.x = (this.position.x + width) % width;
        }
        if (this.position.y < 0 || this.position.y > height) {
            this.position.y = (this.position.y + height) % height;
        }
    }

    render() {
        push();
        translate(this.position.x, this.position.y)
        rotate(this.velocity.heading());
        fill(0, 0, 0, 0);
        strokeWeight(1);
        stroke(255);

        if (window.debug === 2) {
            stroke(this.affected ? color(0, 100, 0) : 100);
            circle(0, 0, this.perception * 2);
        }
        else {
            const h = Math.sqrt(size ** 2 - (size / 2) ** 2);
            triangle(h / 2, 0, h / -2, size / 3, h / -2, size / -3);
        }

        pop();
    }
}