OLD | NEW |
| (Empty) |
1 // Copyright 2011 (c) The Native Client Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 /** | |
6 * @file | |
7 * The JavaScript simulation of the flocking algorithm. Owns an array of | |
8 * geese, and runs the flocking simulation that computes new goose locations. | |
9 */ | |
10 | |
11 goog.provide('Flock'); | |
12 | |
13 goog.require('FrameCounter'); | |
14 goog.require('Goose'); | |
15 goog.require('goog.Disposable'); | |
16 goog.require('goog.array'); | |
17 | |
18 /** | |
19 * Constructor for the Flock class. | |
20 * @constructor | |
21 * @extends {goog.Disposable} | |
22 */ | |
23 Flock = function() { | |
24 goog.Disposable.call(this); | |
25 | |
26 /** | |
27 * The flock of geese. | |
28 * @type {Array.<Goose>} | |
29 * @private | |
30 */ | |
31 this.geese_ = []; | |
32 | |
33 /** | |
34 * An array of attractors. The flock has affinity for these points, and | |
35 * will head toward them when close enough. | |
36 * @type {Array.<goog.Math.Vec2>} | |
37 */ | |
38 this.attractors = []; | |
39 | |
40 /** | |
41 * The framerate meter. | |
42 * type {FrameCounter} | |
43 * @private | |
44 */ | |
45 this.frameCounter_ = new FrameCounter(); | |
46 | |
47 /** | |
48 * The goose sprite image. | |
49 * @type {Image} | |
50 * @private | |
51 */ | |
52 this.gooseImage_ = new Image(); | |
53 this.gooseImage_.src = 'images/Flock32_red.png'; | |
54 } | |
55 goog.inherits(Flock, goog.Disposable); | |
56 | |
57 /** | |
58 * The angular increment between goose sprites. Measured in radians. | |
59 * @type {number} | |
60 * @private | |
61 */ | |
62 Flock.prototype.GOOSE_HEADING_INCREMENT_ = (5.0 * Math.PI) / 180.0; | |
63 | |
64 /** | |
65 * Override of disposeInternal() to dispose of retained objects. | |
66 * @override | |
67 */ | |
68 Flock.prototype.disposeInternal = function() { | |
69 goog.array.clear(this.geese_); | |
70 delete this.frameCounter_; | |
71 Flock.superClass_.disposeInternal.call(this); | |
72 } | |
73 | |
74 /** | |
75 * Create a flock of geese. The geese start at the given location with | |
76 * random velocities. Any previous geese are deleted and the simulation | |
77 * starts with an entirely new flock. | |
78 * @param {!number} size The size of the flock. | |
79 * @param {?goog.math.Vec2} opt_initialLocation The initial location of each | |
80 * goose in the flock. | |
81 */ | |
82 Flock.prototype.resetFlock = function(size, opt_initialLocation) { | |
83 goog.array.clear(this.geese_); | |
84 var initialLocation = opt_initialLocation || new goog.math.Vec2(0, 0); | |
85 for (var goose = 0; goose < size; goose++) { | |
86 this.geese_[goose] = new Goose(initialLocation); | |
87 } | |
88 this.frameCounter_.reset(); | |
89 } | |
90 | |
91 /** | |
92 * Run one tick of the simulation, recording the time. | |
93 * @param {?goog.math.Rect} opt_flockBox The geese will stay inside of this | |
94 * box. If the parameter is not given, the geese don't have boundaries. | |
95 * @return {number} the simulation tick duration in miliseconds. | |
96 */ | |
97 Flock.prototype.flock = function(opt_flockBox) { | |
98 var flockBox = opt_flockBox || new goog.math.Rect(0, 0, 200, 200); | |
99 this.frameCounter_.beginFrame(); | |
100 for (var goose = 0; goose < this.geese_.length; goose++) { | |
101 this.geese_[goose].simulationTick(this.geese_, this.attractors, flockBox); | |
102 } | |
103 this.frameCounter_.endFrame(); | |
104 return this.frameCounter_.framesPerSecond(); | |
105 } | |
106 | |
107 /** | |
108 * Render the flock into the given canvas. | |
109 * @param {!Canvas} canvas The target canvas. | |
110 */ | |
111 Flock.prototype.render = function(canvas) { | |
112 if (!this.gooseImage_.complete) { | |
113 return; | |
114 } | |
115 var context2d = canvas.getContext('2d'); | |
116 for (var g = 0; g < this.geese_.length; g++) { | |
117 var goose = this.geese_[g]; | |
118 var heading = goose.velocity().heading(); | |
119 if (heading < 0.0) { | |
120 heading = Math.PI * 2.0 + heading; | |
121 } | |
122 // The goose points down the positive x-axis when its heading is 0. | |
123 //context2d.rotate(heading); | |
124 var spriteWidth = this.gooseImage_.height; | |
125 var spriteOffset = Math.floor(heading / this.GOOSE_HEADING_INCREMENT_) * | |
126 spriteWidth; | |
127 context2d.drawImage(this.gooseImage_, | |
128 spriteOffset, 0, spriteWidth, this.gooseImage_.height, | |
129 goose.location().x - spriteWidth / 2, | |
130 goose.location().y - spriteWidth / 2, | |
131 spriteWidth, this.gooseImage_.height); | |
132 } | |
133 context2d.fillStyle = 'blue'; | |
134 for (var a = 0; a < this.attractors.length; a++) { | |
135 context2d.fillRect(this.attractors[a].x - 2, this.attractors[a].y - 2, 4, 4)
; | |
136 } | |
137 } | |
OLD | NEW |