├── style.css ├── README.md ├── index.html ├── LICENSE └── sketch.js /style.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | canvas { 6 | display: block; 7 | } 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flocos 2 | 3 | #############///////////////////////////################## 4 | 5 | Link do canal no youtube do Professor Rafael https://www.youtube.com/@rasinformatica 6 | #############///////////////////////////################## 7 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Rafael Assis Santos 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /sketch.js: -------------------------------------------------------------------------------- 1 | let flock; 2 | 3 | function setup() { 4 | createCanvas(1550, 800); 5 | createP(""); 6 | 7 | flock = new Flock(); 8 | // Add an initial set of boids into the system 9 | for (let i = 0; i < 100; i++) { 10 | let b = new Boid(width / 2,height / 2); 11 | flock.addBoid(b); 12 | } 13 | } 14 | 15 | function draw() { 16 | background("green"); 17 | flock.run(100); 18 | } 19 | 20 | // Add a new boid into the System 21 | function mouseDragged() { 22 | flock.addBoid(new Boid(mouseX, mouseY)); 23 | } 24 | 25 | // The Nature of Code 26 | // Daniel Shiffman 27 | // http://natureofcode.com 28 | 29 | // Flock object 30 | // Does very little, simply manages the array of all the boids 31 | 32 | function Flock() { 33 | // An array for all the boids 34 | this.boids = []; // Initialize the array 35 | } 36 | 37 | Flock.prototype.run = function() { 38 | for (let i = 0; i < this.boids.length; i++) { 39 | this.boids[i].run(this.boids); // Passing the entire list of boids to each boid individually 40 | } 41 | } 42 | 43 | Flock.prototype.addBoid = function(b) { 44 | this.boids.push(b); 45 | } 46 | 47 | // The Nature of Code 48 | // Daniel Shiffman 49 | // http://natureofcode.com 50 | 51 | // Boid class 52 | // Methods for Separation, Cohesion, Alignment added 53 | 54 | function Boid(x, y) { 55 | this.acceleration = createVector(0, 0); 56 | this.velocity = createVector(random(-1, 1), random(-1, 1)); 57 | this.position = createVector(x, y); 58 | this.r = 3.0; 59 | this.maxspeed = 3; // Maximum speed 60 | this.maxforce = 0.05; // Maximum steering force 61 | } 62 | 63 | Boid.prototype.run = function(boids) { 64 | this.flock(boids); 65 | this.update(); 66 | this.borders(); 67 | this.render(); 68 | } 69 | 70 | Boid.prototype.applyForce = function(force) { 71 | // We could add mass here if we want A = F / M 72 | this.acceleration.add(force); 73 | } 74 | 75 | // We accumulate a new acceleration each time based on three rules 76 | Boid.prototype.flock = function(boids) { 77 | let sep = this.separate(boids); // Separation 78 | let ali = this.align(boids); // Alignment 79 | let coh = this.cohesion(boids); // Cohesion 80 | // Arbitrarily weight these forces 81 | sep.mult(1.5); 82 | ali.mult(1.0); 83 | coh.mult(1.0); 84 | // Add the force vectors to acceleration 85 | this.applyForce(sep); 86 | this.applyForce(ali); 87 | this.applyForce(coh); 88 | } 89 | 90 | // Method to update location 91 | Boid.prototype.update = function() { 92 | // Update velocity 93 | this.velocity.add(this.acceleration); 94 | // Limit speed 95 | this.velocity.limit(this.maxspeed); 96 | this.position.add(this.velocity); 97 | // Reset accelertion to 0 each cycle 98 | this.acceleration.mult(0); 99 | } 100 | 101 | // A method that calculates and applies a steering force towards a target 102 | // STEER = DESIRED MINUS VELOCITY 103 | Boid.prototype.seek = function(target) { 104 | let desired = p5.Vector.sub(target,this.position); // A vector pointing from the location to the target 105 | // Normalize desired and scale to maximum speed 106 | desired.normalize(); 107 | desired.mult(this.maxspeed); 108 | // Steering = Desired minus Velocity 109 | let steer = p5.Vector.sub(desired,this.velocity); 110 | steer.limit(this.maxforce); // Limit to maximum steering force 111 | return steer; 112 | } 113 | 114 | Boid.prototype.render = function() { 115 | // Draw a triangle rotated in the direction of velocity 116 | let theta = this.velocity.heading() + radians(90); 117 | fill(127); 118 | stroke(200); 119 | push(); 120 | translate(this.position.x, this.position.y); 121 | rotate(theta); 122 | beginShape(); 123 | vertex(0, -this.r * 2); 124 | vertex(-this.r, this.r * 2); 125 | vertex(this.r, this.r * 2); 126 | endShape(CLOSE); 127 | pop(); 128 | } 129 | 130 | // Wraparound 131 | Boid.prototype.borders = function() { 132 | if (this.position.x < -this.r) this.position.x = width + this.r; 133 | if (this.position.y < -this.r) this.position.y = height + this.r; 134 | if (this.position.x > width + this.r) this.position.x = -this.r; 135 | if (this.position.y > height + this.r) this.position.y = -this.r; 136 | } 137 | 138 | // Separation 139 | // Method checks for nearby boids and steers away 140 | Boid.prototype.separate = function(boids) { 141 | let desiredseparation = 25.0; 142 | let steer = createVector(0, 0); 143 | let count = 0; 144 | // For every boid in the system, check if it's too close 145 | for (let i = 0; i < boids.length; i++) { 146 | let d = p5.Vector.dist(this.position,boids[i].position); 147 | // If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself) 148 | if ((d > 0) && (d < desiredseparation)) { 149 | // Calculate vector pointing away from neighbor 150 | let diff = p5.Vector.sub(this.position, boids[i].position); 151 | diff.normalize(); 152 | diff.div(d); // Weight by distance 153 | steer.add(diff); 154 | count++; // Keep track of how many 155 | } 156 | } 157 | // Average -- divide by how many 158 | if (count > 0) { 159 | steer.div(count); 160 | } 161 | 162 | // As long as the vector is greater than 0 163 | if (steer.mag() > 0) { 164 | // Implement Reynolds: Steering = Desired - Velocity 165 | steer.normalize(); 166 | steer.mult(this.maxspeed); 167 | steer.sub(this.velocity); 168 | steer.limit(this.maxforce); 169 | } 170 | return steer; 171 | } 172 | 173 | // Alignment 174 | // For every nearby boid in the system, calculate the average velocity 175 | Boid.prototype.align = function(boids) { 176 | let neighbordist = 50; 177 | let sum = createVector(0,0); 178 | let count = 0; 179 | for (let i = 0; i < boids.length; i++) { 180 | let d = p5.Vector.dist(this.position,boids[i].position); 181 | if ((d > 0) && (d < neighbordist)) { 182 | sum.add(boids[i].velocity); 183 | count++; 184 | } 185 | } 186 | if (count > 0) { 187 | sum.div(count); 188 | sum.normalize(); 189 | sum.mult(this.maxspeed); 190 | let steer = p5.Vector.sub(sum, this.velocity); 191 | steer.limit(this.maxforce); 192 | return steer; 193 | } else { 194 | return createVector(0, 0); 195 | } 196 | } 197 | 198 | // Cohesion 199 | // For the average location (i.e. center) of all nearby boids, calculate steering vector towards that location 200 | Boid.prototype.cohesion = function(boids) { 201 | let neighbordist = 50; 202 | let sum = createVector(0, 0); // Start with empty vector to accumulate all locations 203 | let count = 0; 204 | for (let i = 0; i < boids.length; i++) { 205 | let d = p5.Vector.dist(this.position,boids[i].position); 206 | if ((d > 0) && (d < neighbordist)) { 207 | sum.add(boids[i].position); // Add location 208 | count++; 209 | } 210 | } 211 | if (count > 0) { 212 | sum.div(count); 213 | return this.seek(sum); // Steer towards the location 214 | } else { 215 | return createVector(0, 0); 216 | } 217 | } --------------------------------------------------------------------------------