├── 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 | }
--------------------------------------------------------------------------------