Index: experimental/flocking_geese/js/goose.js |
diff --git a/experimental/flocking_geese/js/goose.js b/experimental/flocking_geese/js/goose.js |
deleted file mode 100644 |
index fd56b291179a282f88614ccbefd1ae231529fa0c..0000000000000000000000000000000000000000 |
--- a/experimental/flocking_geese/js/goose.js |
+++ /dev/null |
@@ -1,383 +0,0 @@ |
-// Copyright (c) 2011 The Native Client Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-/** |
- * @file |
- * The Goose object. This implements a single goose that flocks with other |
- * geese in the flocking simulation. Taken almost directly from |
- * http://processingjs.org/learning/topic/flocking with references to |
- * http://harry.me/2011/02/17/neat-algorithms---flocking. |
- */ |
- |
- |
-goog.provide('Goose'); |
- |
-goog.require('goog.Disposable'); |
-goog.require('goog.math.Vec2'); |
- |
-/** |
- * A Goose. Starts the goose with a location and a velocity. |
- * @param {?goog.math.Vec2} opt_location The initial location of this |
- * goose. If not given, then the goose is started at (0, 0). |
- * @param {?goog.math.Vec2} opt_velocity The initial velocity of this goose. |
- * If not given, then the goose is assigned a random velocity. |
- * @constructor |
- * @extends {goog.Disposable} |
- */ |
-Goose = function(opt_location, opt_velocity) { |
- goog.Disposable.call(this); |
- /** |
- * The goose's current location. |
- * @type {goog.math.Vec2} |
- * @private |
- */ |
- if (opt_location) { |
- this.location_ = opt_location.clone(); |
- } else { |
- this.location_ = new goog.math.Vec2(0, 0); |
- } |
- |
- /** |
- * The goose's current velocity. |
- * @type {goog.math.Vec2} |
- * @private |
- */ |
- if (opt_velocity) { |
- this.velocity_ = opt_velocity.clone(); |
- } else { |
- this.velocity_ = new goog.math.Vec2.randomUnit(); |
- } |
-}; |
-goog.inherits(Goose, goog.Disposable); |
- |
-/** |
- * The maximum speed of a goose. Measured in meters/second. |
- * @type {number} |
- */ |
-Goose.prototype.MAX_SPEED = 2.0; |
- |
-/** |
- * The maximum force that can be applied to turn a goose when computing the |
- * aligment. Measured in meters/second/second. |
- * @type {number} |
- */ |
-Goose.prototype.MAX_TURNING_FORCE = 0.05; |
- |
-/** |
- * The neighbour radius of a goose. Only geese within this radius will affect |
- * the flocking computations of this goose. Measured in pixels. |
- * @type {number} |
- */ |
-Goose.prototype.NEIGHBOUR_RADIUS = 64.0; |
- |
-/** |
- * The minimum distance that a goose can be from this goose. If another goose |
- * comes within this distance of this goose, the flocking algorithm tries to |
- * move the geese apart. Measured in pixels. |
- * @type {number} |
- */ |
-Goose.prototype.PERSONAL_SPACE = 32.0; |
- |
-/** |
- * The distance at which attractors have effect on a goose's direction. |
- * @type {number} |
- */ |
-Goose.prototype.ATTRACTOR_RADIUS = 320.0; |
- |
-/** |
- * The goose will try to turn towards geese within this distance (computed |
- * during the cohesion phase). Measured in pixels. |
- * @type {number} |
- */ |
-Goose.prototype.MAX_TURNING_DISTANCE = 100.0; |
- |
-/** |
- * The weights used when computing the weighted sum the three flocking |
- * components. |
- * @type {number} |
- */ |
-Goose.prototype.SEPARATION_WEIGHT = 2.0; |
-Goose.prototype.ALIGNMENT_WEIGHT = 1.0; |
-Goose.prototype.COHESION_WEIGHT = 1.0; |
- |
-/** |
- * Override of disposeInternal() to dispose of retained objects and unhook all |
- * events. |
- * @override |
- */ |
-Goose.prototype.disposeInternal = function() { |
- this.domElement_ = null; |
- Speedometer.superClass_.disposeInternal.call(this); |
-} |
- |
-/** |
- * Accessor for location. |
- * @return {goog.math.Vec2} The current location. |
- */ |
-Goose.prototype.location = function() { |
- return this.location_; |
-} |
- |
-/** |
- * Accessor for velocity. |
- * @return {goog.math.Vec2} The current velocity. |
- */ |
-Goose.prototype.velocity = function() { |
- return this.velocity_; |
-} |
- |
-/** |
- * Run one tick of the simulation. Compute a new acceleration based on the |
- * flocking algorithm (see Goose.flock()) and update the goose's location |
- * by integrating acceleration and velocity. |
- * @param {!Array.<Goose>} geese The list of all the geese in the flock. |
- * @param {!Array.<goog.math.Vec2>} attractors The list of attractors. |
- * Geese have affinity for these points. |
- * @param {?goog.math.Rect} opt_flockBox The geese will stay inside of this |
- * box. If the parameter is not given, the geese don't have boundaries. |
- */ |
-Goose.prototype.simulationTick = function(geese, attractors, opt_flockBox) { |
- var acceleration = this.flock(geese, attractors); |
- this.velocity_.add(acceleration); |
- // Limit the velocity to a maximum speed. |
- this.velocity_.clamp(this.MAX_SPEED); |
- this.location_.add(this.velocity_); |
- // Wrap the goose location to the flock box. |
- if (opt_flockBox) { |
- if (this.location_.x < opt_flockBox.left) { |
- this.location_.x = opt_flockBox.left + opt_flockBox.width; |
- } |
- if (this.location_.x > (opt_flockBox.left + opt_flockBox.width)) { |
- this.location_.x = opt_flockBox.left; |
- } |
- if (this.location_.y < opt_flockBox.top) { |
- this.location_.y = opt_flockBox.top + opt_flockBox.height; |
- } |
- if (this.location_.y > (opt_flockBox.top + opt_flockBox.height)) { |
- this.location_.y = opt_flockBox.top; |
- } |
- } |
-} |
- |
-/** |
- * Implement the flocking algorithm in five steps: |
- * 1. Compute the separation component, |
- * 2. Compute the alignment component, |
- * 3. Compute the flock cohesion component. |
- * 4. Compute the effect of the attractors and blend this in with the |
- * cohesion component. |
- * 5. Create a weighted sum of the three components and use this as the |
- * new acceleration for the goose. |
- * This is an O(n^2) version of the algorithm. There are ways to speed this |
- * up using spatial coherence techniques, but this version is much simpler. |
- * @param {!Array.<Goose>} geese The list of all the neighbouring geese (in |
- * this implementation, this is all the geese in the flock). |
- * @param {!Array.<goog.math.Vec2>} attractors The list of attractors. |
- * Geese have affinity for these points. |
- * @return {goog.math.Vec2} The acceleration vector for this goose based on the |
- * flocking algorithm. |
- */ |
-Goose.prototype.flock = function(geese, attractors) { |
- // Loop over all the neighbouring geese in the flock, accumulating |
- // the separation mean, the alignment mean and the cohesion mean. |
- var separationCount = 0; |
- var separation = new goog.math.Vec2(0, 0); |
- var alignCount = 0; |
- var alignment = new goog.math.Vec2(0, 0); |
- var cohesionCount = 0; |
- var cohesion = new goog.math.Vec2(0, 0); |
- for (var i = 0; i < geese.length; i++) { |
- var goose = geese[i]; |
- // Compute the distance from this goose to its neighbour. |
- var gooseDirection = goog.math.Vec2.difference( |
- this.location_, goose.location()); |
- var distance = gooseDirection.magnitude(); |
- separationCount = this.accumulateSeparation_( |
- distance, gooseDirection, separation, separationCount); |
- alignCount = this.accumulateAlignment_( |
- distance, goose, alignment, alignCount); |
- cohesionCount = this.accumulateCohesion_( |
- distance, goose, cohesion, cohesionCount); |
- } |
- // Compute the means and create a weighted sum. This becomes the goose's new |
- // acceleration. |
- if (separationCount > 0) { |
- separation.scale(1.0 / separationCount); |
- } |
- if (alignCount > 0) { |
- alignment.scale(1.0 / alignCount); |
- // Limit the effect that alignment has on the final acceleration. The |
- // alignment component can overpower the others if there is a big |
- // difference between this goose's velocity and its neighbours'. |
- alignment.clamp(this.MAX_TURNING_FORCE); |
- } |
- |
- // Compute the effect of the attractors and blend this in with the flock |
- // cohesion component. An attractor has to be within ATTRACTOR_RADIUS to |
- // effect the heading of a goose. |
- for (var i = 0; i < attractors.length; i++) { |
- var attractorDirection = goog.math.Vec2.difference( |
- attractors[i], this.location_); |
- var distance = attractorDirection.magnitude(); |
- if (distance < this.ATTRACTOR_RADIUS) { |
- attractorDirection.scale(1000); // Each attractor acts like 1000 geese. |
- cohesion.add(attractorDirection); |
- cohesionCount += 1; |
- } |
- } |
- |
- // If there is a non-0 cohesion component, steer the goose so that it tries |
- // to follow the flock. |
- if (cohesionCount > 0) { |
- cohesion.scale(1.0 / cohesionCount); |
- cohesion = this.turnTowardsTarget(cohesion); |
- } |
- |
- // Compute the weighted sum. |
- separation.scale(this.SEPARATION_WEIGHT); |
- alignment.scale(this.ALIGNMENT_WEIGHT); |
- cohesion.scale(this.COHESION_WEIGHT); |
- var weightedSum = cohesion.clone(); |
- weightedSum.add(alignment); |
- weightedSum.add(separation); |
- return weightedSum; |
-} |
- |
-/** |
- * Add a neighbouring goose's contribution to the separation mean. Only |
- * consider geese that have moved inside of this goose's personal space. |
- * Modifies the separation accumulator |separation| in-place. |
- * @param {!number} distance The distance from this goose to the neighbouring |
- * goose. |
- * @param {!goog.math.Vec2} gooseDirection The direction vector from this |
- * goose to the neighbour. |
- * @param {!goog.math.Vec2} separation The accumulated separation from all the |
- * neighbouring geese. |
- * @param {!number} separationCount The current number of geese that have |
- * contributed to the separation component so far. |
- * @return {!number} The new count of geese that contribute to the separation |
- * component. If the goose under consideration does not contribute, this |
- * value is the same as |separationCount|. |
- * @private |
- */ |
-Goose.prototype.accumulateSeparation_ = function(distance, |
- gooseDirection, |
- separation, |
- separationCount) { |
- if (distance > 0 && distance < this.PERSONAL_SPACE) { |
- var weightedDirection = gooseDirection; |
- weightedDirection.normalize(); |
- weightedDirection.scale(1.0 / distance); |
- separation.add(weightedDirection); |
- separationCount++; |
- } |
- return separationCount; |
-} |
- |
-/** |
- * Add a neighbouring goose's contribution to the alignment mean. Alignment is |
- * the average velocity of the neighbours. Only consider geese that are within |
- * |NEIGHBOUR_RADIUS|. Modifies the alignment accumulator |alignment| in-place. |
- * @param {!number} distance The distance from this goose to the neighbouring |
- * goose. |
- * @param {!Goose} goose The neighbouring goose under consideration. |
- * @param {!goog.math.Vec2} alignment The accumulated alignment from all the |
- * neighbouring geese. |
- * @param {!number} alignCount The current number of geese that have |
- * contributed to the alignment component so far. |
- * @return {!number} The new count of geese that contribute to the alignment |
- * component. If the goose under consideration does not contribute, this |
- * value is the same as |alignCount|. |
- * @private |
- */ |
-Goose.prototype.accumulateAlignment_ = function(distance, |
- goose, |
- alignment, |
- alignCount) { |
- if (distance > 0 && distance < this.NEIGHBOUR_RADIUS) { |
- alignment.add(goose.velocity()); |
- alignCount++; |
- } |
- return alignCount; |
-} |
- |
-/** |
- * Add a neighbouring goose's contribution to the cohesion mean. Cohesion is |
- * based on the average location of the neighbours. The goose attempts to |
- * point to this average location. Only consider geese that are within |
- * |NEIGHBOUR_RADIUS|. Modifies the cohesion accumulator |cohesion| in-place. |
- * @param {!number} distance The distance from this goose to the neighbouring |
- * goose. |
- * @param {!Goose} goose The neighbouring goose under consideration. |
- * @param {!goog.math.Vec2} cohesion The accumulated cohesion from all the |
- * neighbouring geese. |
- * @param {!number} cohesionCount The current number of geese that have |
- * contributed to the cohesion component so far. |
- * @return {!number} The new count of geese that contribute to the cohesion |
- * component. If the goose under consideration does not contribute, this |
- * value is the same as |cohesionCount|. |
- * @private |
- */ |
-Goose.prototype.accumulateCohesion_ = function(distance, |
- goose, |
- cohesion, |
- cohesionCount) { |
- if (distance > 0 && distance < this.NEIGHBOUR_RADIUS) { |
- cohesion.add(goose.location()); |
- cohesionCount++; |
- } |
- return cohesionCount; |
-} |
- |
-/** |
- * Turn the goose towards a target. The amount of turning force is clamped |
- * to |MAX_TURNING_FORCE|. |
- * @param {!goog.math.Vec2} target Turn the goose towards this target. |
- * @return {goog.math.Vec2} A vector representing the new direction of the |
- * goose. |
- */ |
-Goose.prototype.turnTowardsTarget = function(target) { |
- var desiredDirection = goog.math.Vec2.difference(target, this.location_); |
- var distance = desiredDirection.magnitude(); |
- var newDirection = new goog.math.Vec2(0, 0); |
- if (distance > 0) { |
- desiredDirection.normalize(); |
- // If the target is within the turning affinity distance, then make the |
- // desired direction based on distance to the target. Otherwise, base |
- // the desired direction on MAX_SPEED. |
- if (distance < this.MAX_TURNING_DISTANCE) { |
- // Some pretty arbitrary dampening. |
- desiredDirection.scale(this.MAX_SPEED * distance / 100.0); |
- } else { |
- desiredDirection.scale(this.MAX_SPEED); |
- } |
- newDirection = goog.math.Vec2.difference(desiredDirection, this.velocity_); |
- newDirection.clamp(this.MAX_TURNING_FORCE); |
- } |
- return newDirection; |
-} |
- |
-/** |
- * Clamp a vector to a maximum magnitude. Works on the vector in-place. |
- * @param {!goog.math.Vec2} v The vector. |
- * @param {!number} max_mag The maximum magnitude of the vector. |
- */ |
-goog.math.Vec2.prototype.clamp = function(max_mag) { |
- var mag = this.magnitude(); |
- if (mag > max_mag && max_mag != 0) { |
- this.normalize(); |
- this.scale(max_mag); |
- } |
-} |
- |
-/** |
- * Compute the "heading" of a vector - this is the angle in radians between |
- * the vector and the x-axis. |
- * @return {!number} The "heading" angle in radians. |
- */ |
-goog.math.Vec2.prototype.heading = function() { |
- var angle = Math.atan2(this.y, this.x); |
- return angle; |
-} |
- |