source: main/trunk/model-sites-dev/von-sparql/js/paper/examples/Node.js/Tadpoles.pjs@ 28914

Last change on this file since 28914 was 28914, checked in by ak19, 10 years ago

Supporting javascript libraries and bespoke code written by Steffan to support the von-sparql user interface

File size: 8.2 KB
Line 
1paper.setup(new Canvas(1024, 768));
2
3// Adapted from Flocking Processing example by Daniel Schiffman:
4// http://processing.org/learning/topics/flocking.html
5
6project.currentStyle = {
7 strokeColor: 'white',
8 strokeWidth: 2,
9 strokeCap: 'round'
10};
11
12new Path.Rectangle(view.bounds).fillColor = 'black';
13
14var head = new Path.Ellipse([0, 0], [13, 8]);
15head.fillColor = 'white';
16head.strokeColor = null;
17var headSymbol = new Symbol(head);
18
19var size = view.size;
20
21var Boid = Base.extend({
22 initialize: function(position, maxSpeed, maxForce) {
23 var strength = Math.random() * 0.5;
24 this.acc = new Point(0, 0);
25 this.vel = Point.random() * 2 - 1;
26 this.loc = position.clone();
27 this.r = 30;
28 this.maxSpeed = maxSpeed + strength;
29 this.maxForce = maxForce + strength;
30 this.head = headSymbol.place();
31 this.path = new Path();
32 this.shortPath = new Path();
33 this.shortPath.strokeWidth = 4;
34 for (var i = 0, l = strength * 10 + 10; i < l; i++) {
35 this.path.add(this.loc);
36 if (i < 3)
37 this.shortPath.add(this.loc);
38 }
39
40 this.firstSegment = this.path.segments[0];
41 this.count = 0;
42 this.lastRot = 0;
43 },
44
45 run: function(boids) {
46 this.lastLoc = this.loc.clone();
47 if (!groupTogether) {
48 this.flock(boids);
49 } else {
50 this.align(boids);
51 }
52 this.borders();
53
54 this.update();
55 this.firstSegment.point = this.loc;
56 var lastPoint = this.firstSegment.point;
57 var lastVector = this.loc - this.lastLoc;
58 var segments = this.path.segments;
59 for (var i = 1, l = segments.length; i < l; i++) {
60 var segment = segments[i];
61 var vector = lastPoint - segment.point;
62 this.count += this.vel.length * 10;
63 var rotLength = Math.sin((this.count + i * 3) / 300);
64 var rotated = lastVector.rotate(90).normalize(rotLength);
65 lastPoint += lastVector.normalize(-5 - this.vel.length / 3);
66 segment.point = lastPoint;
67 segment.point += rotated;
68 lastVector = vector;
69 }
70 this.path.smooth();
71 this.head.position = this.loc;
72 var vector = this.loc - this.lastLoc;
73 var rot = vector.angle;
74 this.head.rotate(rot - this.lastRot);
75 this.lastRot = rot;
76
77 var shortSegments = this.shortPath.segments;
78 for (var i = 0; i < 3; i++)
79 shortSegments[i] = segments[i].clone();
80 },
81
82 // We accumulate a new acceleration each time based on three rules
83 flock: function(boids) {
84 var sep = this.separate(boids) * 3;
85 var ali = this.align(boids);
86 var coh = this.cohesion(boids);
87 this.acc += sep + ali + coh;
88 },
89
90 update: function() {
91 // Update velocity
92 this.vel += this.acc;
93 // Limit speed (vector#limit?)
94 this.vel.length = Math.min(this.maxSpeed, this.vel.length);
95 this.loc += this.vel;
96 // Reset acceleration to 0 each cycle
97 this.acc.length = 0;
98 },
99
100 seek: function(target) {
101 this.acc += this.steer(target, false);
102 },
103
104 arrive: function(target) {
105 this.acc += this.steer(target, true);
106 },
107
108 // A method that calculates a steering vector towards a target
109 // Takes a second argument, if true, it slows down as it approaches
110 // the target
111 steer: function(target, slowdown) {
112 var steer,
113 desired = target - this.loc,
114 d = desired.length;
115 if (d > 0) {
116 // Two options for desired vector magnitude
117 // (1 -- based on distance, 2 -- maxSpeed)
118 if (slowdown && d < 100) {
119 // // This damping is somewhat arbitrary:
120 desired.length = this.maxSpeed * (d / 100);
121 } else {
122 desired.length = this.maxSpeed;
123 }
124 steer = desired - this.vel;
125 steer.length = Math.min(this.maxForce, steer.length);
126 } else {
127 steer = new Point(0, 0);
128 }
129 return steer;
130 },
131
132 borders: function() {
133 var loc = this.loc;
134 var r = this.r;
135 var oldLoc = this.loc.clone();
136 var width = size.width;
137 var height = size.height;
138 if (loc.x < -r) loc.x = width + r;
139 if (loc.y < -r) loc.y = height + r;
140 if (loc.x > width + r) loc.x = -r;
141 if (loc.y > height + r) loc.y = -r;
142 var vector = this.loc - oldLoc;
143 if (!vector.isZero())
144 this.path.position += vector;
145 },
146
147 separate: function(boids) {
148 var desiredSeperation = 60;
149 var steer = new Point(0, 0);
150 var count = 0;
151 // For every boid in the system, check if it's too close
152 for (var i = 0, l = boids.length; i < l; i++) {
153 var other = boids[i];
154 var d = other.loc.getDistance(this.loc);
155 if (d > 0 && d < desiredSeperation) {
156 // Calculate vector pointing away from neighbor
157 var diff = this.loc - other.loc;
158 steer += diff.normalize(1 / d);
159 count++;
160 }
161 }
162 // Average -- divide by how many
163 if (count > 0)
164 steer /= count;
165 if (steer.length > 0) {
166 // Implement Reynolds: Steering = Desired - Velocity
167 steer.length = this.maxSpeed;
168 steer -= this.vel;
169 steer.length = Math.min(steer.length, this.maxForce);
170 }
171 return steer;
172 },
173
174 // Alignment
175 // For every nearby boid in the system, calculate the average velocity
176 align: function(boids) {
177 var neighborDist = 25;
178 var steer = new Point(0, 0);
179 var count = 0;
180 var nearest = 999;
181 var closestPoint;
182 for (var i = 0, l = boids.length; i < l; i++) {
183 var other = boids[i];
184 var d = this.loc.getDistance(other.loc);
185 if (d > 0 && d < nearest) {
186 closestPoint = other.loc;
187 nearest = d;
188 }
189 if (d > 0 && d < neighborDist) {
190 steer += other.vel;
191 count++;
192 }
193 }
194
195 if (count > 0)
196 steer /= count;
197 if (steer.length > 0) {
198 // Implement Reynolds: Steering = Desired - Velocity
199 steer.length = this.maxSpeed;
200 steer -= this.vel;
201 steer.length = Math.min(steer.length, this.maxForce);
202 }
203 return steer;
204 },
205
206 // Cohesion
207 // For the average location (i.e. center) of all nearby boids,
208 // calculate steering vector towards that location
209 cohesion: function(boids) {
210 var neighborDist = 100;
211 var sum = new Point(0, 0);
212 var count = 0;
213 for (var i = 0, l = boids.length; i < l; i++) {
214 var other = boids[i];
215 var d = this.loc.getDistance(other.loc);
216 if (d > 0 && d < neighborDist) {
217 sum += other.loc; // Add location
218 count++;
219 }
220 }
221 if (count > 0) {
222 sum /= count;
223 // Steer towards the location
224 return this.steer(sum, false);
225 }
226 return sum;
227 }
228});
229
230var heartPath = new Path([
231 [[514.6962890625, 624.703125], [7.0966796875, -26.3369140625], [-7.10205078125, -27.0244140625]],
232 [[484.29052734375, 548.6025390625], [13.16845703125, 23.7060546875], [-13.173828125, -23.70703125]],
233 [[407.84619140625, 438.14453125], [37.79296875, 49.935546875], [-27.71630859375, -36.6435546875]],
234 [[356.654296875, 368.400390625], [6.41015625, 9.8505859375], [-10.53759765625, -16.02978515625]],
235 [[333.80712890625, 324.25146484375], [4.69189453125, 13.3994140625], [-4.697265625, -13.39892578125]],
236 [[326.76416015625, 283.53857421875], [0, 13.74267578125], [0, -25.42431640625]],
237 [[352.18798828125, 219.634765625], [-16.95263671875, 17.17822265625], [16.94775390625, -17.1787109375]],
238 [[415.0615234375, 193.8671875], [-24.96826171875, 0], [25.19287109375, 0]],
239 [[480.68310546875, 220.66552734375], [-18.552734375, -17.86572265625], [13.96826171875, 13.28662109375]],
240 [[514.6962890625, 280.10302734375], [-8.70703125, -26.3369140625], [7.55859375, -25.88037109375]],
241 [[546.6484375, 221.0087890625], [-13.7431640625, 13.517578125], [19.0087890625, -18.32177734375]],
242 [[612.61328125, 193.5234375], [-24.9677734375, 0], [24.7373046875, 0]],
243 [[675.486328125, 219.119140625], [-17.177734375, -17.06005859375], [17.1787109375, 17.06591796875]],
244 [[701.2548828125, 280.10302734375], [0, -23.58837890625], [0, 20.61376953125]],
245 [[686.1376953125, 344.52197265625], [10.076171875, -22.33203125], [-10.08203125, 22.33203125]],
246 [[627.73046875, 432.3046875], [28.8603515625, -36.1875], [-37.5673828125, 47.412109375]],
247 [[545.6171875, 549.1171875], [17.1787109375, -30.458984375], [-13.517578125, 24.0498046875]]
248]);
249heartPath.closed = true;
250heartPath.position = view.center;
251heartPath.strokeColor = null;
252heartPath.scale(1.5);
253
254var groupTogether = false;
255var pathLength = heartPath.length;
256var mouseDown = false;
257var boids = [];
258
259// Add the boids:
260for (var i = 0; i < 300; i++) {
261 var position = view.center;
262 boids.push(new Boid(position, 10, 0.05));
263}
264
265function onFrame(event) {
266 for (var i = 0, l = boids.length; i < l; i++) {
267 if (groupTogether) {
268 var length = ((i + event.count / 30) % l) / l * pathLength;
269 var point = heartPath.getPointAt(length);
270 boids[i].arrive(point);
271 }
272 boids[i].run(boids);
273 }
274}
275
276// Reposition the heart path whenever the window is resized:
277function onResize(event) {
278 size = view.size;
279 heartPath.position = view.center;
280}
Note: See TracBrowser for help on using the repository browser.