-
Notifications
You must be signed in to change notification settings - Fork 0
/
Boids.html
186 lines (150 loc) · 5.67 KB
/
Boids.html
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
<!DOCTYPE html>
<html>
<head>
<title>Boids</title>
</head>
<body>
<p align="center">
<canvas id="mycanvas"></canvas>
</p>
</body>
<script src="https://cdn.jsdelivr.net/processing.js/1.4.8/processing.min.js"></script>
<script>
var sketchProc = function(processingInstance) {
with (processingInstance) {
var width=1200; // canvas width
var height=800; // canvas height
size(width,height);
frameRate(30);
var nodeCount = 150; // how many simulation nodes
var nodeSize = 10; // length of single node
var nodeWidth = 5; // width of single node
var perceivedDist = 50; // how far can a single node see
var seperationDist = 40; // how close before node starts moving away from others
var alignmentDist = 50; // how far it will calculate local alginment
var seperationWeight = 0.4; // 0.4
var cohesionWeight = 0.3; // 0.3
var alignmentWeight = 0.3; // 0.3
var delta = 0.25;
var nodes = [];
// create nodes
for(var i=0;i<nodeCount;i++) {
// random unit vector
var oX = random(-1,1);
var oY = sqrt(1 - (oX*oX))*((round(random(1))%2===0)?1:-1);
// add node to list
nodes.push(
{
// position
'x': random(0,width),
'y': random(0,height),
// oritenation
'oX': oX,
'oY': oY,
// speed
'v': random(0.5, 1)
}
);
}
var getRules = function(nodeIndex, nodes) {
// cohesion variables
var cohesionX = 0;
var cohesionY = 0;
// avoidance variables
var seperationX = 0;
var seperationY = 0;
// alignment variables
var alignmentX = 0;
var alignmentY = 0;
// go through all nodes
for(var i=0;i<nodes.length;i++) {
// if there is a node witin range
if(nodeIndex !== i) {
// distance to node
var d = dist(nodes[i].x,nodes[i].y, nodes[nodeIndex].x, nodes[nodeIndex].y);
// if within perceived distance
if(d <= perceivedDist) {
// variables to find average
cohesionX+=nodes[i].x - nodes[nodeIndex].x;
cohesionY+=nodes[i].y - nodes[nodeIndex].y;
}
// if too close to another node
if(d <= seperationDist) {
// give more weight to closer nodes
seperationX += ((seperationDist-d)/d)*(nodes[i].x - nodes[nodeIndex].x)*-1;
seperationY += ((seperationDist-d)/d)*(nodes[i].y - nodes[nodeIndex].y)*-1;
}
// get total alignment
if(d <= alignmentDist) {
alignmentX += nodes[i].oX;
alignmentY += nodes[i].oY;
}
}
}
// cohesion data
var cohesionMagnitude = sqrt((cohesionX*cohesionX) + (cohesionY*cohesionY));
var unitCohesionX = (cohesionMagnitude > 0) ? cohesionX/cohesionMagnitude : 0;
var unitCohesionY = (cohesionMagnitude > 0) ? cohesionY/cohesionMagnitude : 0;
// seperation data
var seperationMagnitude = sqrt((seperationX*seperationX) + (seperationY*seperationY));
var unitSeperationX = (seperationMagnitude > 0) ? seperationX/seperationMagnitude : 0;
var unitSeperationY = (seperationMagnitude > 0) ? seperationY/seperationMagnitude : 0;
// alignment data
var alignmentMagnitude = sqrt((alignmentX*alignmentX) + (alignmentY*alignmentY));
var unitAlignmentX = (alignmentMagnitude > 0) ? alignmentX/alignmentMagnitude : 0;
var unitAlignmentY = (alignmentMagnitude > 0) ? alignmentY/alignmentMagnitude : 0;
return {
'unitSeperationX': unitSeperationX,
'unitSeperationY': unitSeperationY,
'unitCohesionX': unitCohesionX,
'unitCohesionY': unitCohesionY,
'unitAlignmentX': unitAlignmentX,
'unitAlignmentY': unitAlignmentY
};
};
draw = function() {
// draw blank canvas
background(255,255,255);
// make copy of array for boid changes
var nodesCopy = nodes;
// go through all nodes
for(var i=0;i<nodes.length;i++) {
// draw nodes
triangle(nodes[i].x - nodeWidth*nodes[i].oY, nodes[i].y + nodeWidth*nodes[i].oX, nodes[i].x + nodeWidth*nodes[i].oY, nodes[i].y - nodeWidth*nodes[i].oX, nodes[i].x + nodeSize*nodes[i].oX*2, nodes[i].y + nodeSize*nodes[i].oY*2);
// location of perceived center of mass
var data = getRules(i, nodes);
// show current direction unit vector
stroke(0, 0, 0);
line(nodes[i].x, nodes[i].y, nodes[i].x + nodeSize*nodes[i].oX*2, nodes[i].y + nodeSize*nodes[i].oY*2);
// calulcate new orientation vector
var newDirectionX = nodes[i].oX + ((data.unitCohesionX*cohesionWeight + data.unitSeperationX*seperationWeight + data.unitAlignmentX*alignmentWeight)*delta);
var newDirectionY = nodes[i].oY + ((data.unitCohesionY*cohesionWeight + data.unitSeperationY*seperationWeight + data.unitAlignmentY*alignmentWeight)*delta);
var newMagnitude = sqrt((newDirectionX*newDirectionX) + (newDirectionY*newDirectionY));
// update orientation with new unit orientation vector
nodesCopy[i].oX = newDirectionX/newMagnitude;
nodesCopy[i].oY = newDirectionY/newMagnitude;
// update position
nodesCopy[i].x += nodes[i].oX*nodes[i].v;
nodesCopy[i].y += nodes[i].oY*nodes[i].v;
// make sure node stays in the canvas
if(nodesCopy[i].x < 0) {
nodes[i].x+=width;
}
if(nodesCopy[i].x > width) {
nodes[i].x-=width;
}
if(nodesCopy[i].y < 0) {
nodes[i].y+=height;
}
if(nodesCopy[i].y > height) {
nodes[i].y-=height;
}
}
// update all nodes with changes
nodes = nodesCopy;
};
}};
var canvas = document.getElementById("mycanvas");
var processingInstance = new Processing(canvas, sketchProc);
</script>
</html>