1 /**
  2  * The Render Engine
  3  * ArrivalBehavior
  4  *
  5  * @fileoverview Arrival behavior, based on Craig Reynolds "Autonomous Steering Behaviors" article.
  6  *               The arrival behavior is similar to the seek behavior, where a vehicle will navigate
  7  *               to a target.  However, the arrival behavior will slow as it approaches the target.
  8  *
  9  * @author: Brett Fattori (brettf@renderengine.com)
 10  * @author: $Author: bfattori $
 11  * @version: $Revision: 1555 $
 12  *
 13  * Copyright (c) 2011 Brett Fattori (brettf@renderengine.com)
 14  *
 15  * Permission is hereby granted, free of charge, to any person obtaining a copy
 16  * of this software and associated documentation files (the "Software"), to deal
 17  * in the Software without restriction, including without limitation the rights
 18  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 19  * copies of the Software, and to permit persons to whom the Software is
 20  * furnished to do so, subject to the following conditions:
 21  *
 22  * The above copyright notice and this permission notice shall be included in
 23  * all copies or substantial portions of the Software.
 24  *
 25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 26  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 27  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 28  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 29  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 30  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 31  * THE SOFTWARE
 32  */
 33 
 34 // Load all required engine components
 35 R.Engine.define({
 36     "class":"R.components.logic.behaviors.Arrival",
 37     "requires":[
 38         "R.components.logic.behaviors.BaseBehavior"
 39     ]
 40 });
 41 
 42 // Add behavior options
 43 if (R.Engine.options.behaviors === undefined) {
 44     R.Engine.options.behaviors = {};
 45 }
 46 
 47 $.extend(R.Engine.options.behaviors, {
 48     "arrivalSlowingDistance":50
 49 });
 50 
 51 
 52 /**
 53  * @class The arrival behavior component. Causes the vehicle to seek the destination, but slow as it
 54  *        approaches it.
 55  * @param destination The point to seek
 56  * @param [slowingDistance] The distance (in pixels) at which slowing should occur.  The velocity
 57  *        will be scaled as it nears the destination and stop when it is at, or almost at, the
 58  *        destination.
 59  * @extends R.components.logic.behaviors.BaseBehavior
 60  * @constructor
 61  */
 62 R.components.logic.behaviors.Arrival = function () {
 63     "use strict";
 64     return R.components.logic.behaviors.BaseBehavior.extend(/** @scope R.components.logic.behaviors.Arrival.prototype */{
 65 
 66         slowDist:0,
 67         arrived:false,
 68         target:null,
 69 
 70         /** @private */
 71         constructor:function (target, slowingDistance) {
 72             this.base("arrival");
 73             this.arrived = false;
 74             this.setTarget(target);
 75             this.slowDist = slowingDistance || R.Engine.options.behaviors.arrivalSlowingDistance;
 76         },
 77 
 78         destroy:function () {
 79             this.base();
 80             this.destPt.destroy();
 81         },
 82 
 83         reset:function () {
 84             this.arrived = false;
 85             this.base();
 86         },
 87 
 88         /**
 89          * Set the target to seek.
 90          * @param target {R.math.Point2D|R.objects.Object2D} The point, or object,
 91          *    to seek.
 92          */
 93         setTarget:function (target) {
 94             this.target = target;
 95         },
 96 
 97         /**
 98          * This method is called by the game object to run the component,
 99          * updating its state.
100          *
101          * @param renderContext {R.rendercontexts.AbstractRenderContext} The context the component will render within.
102          * @param time {Number} The global engine time
103          * @param dt {Number} The delta between the world time and the last time the world was updated
104          *          in milliseconds.
105          */
106         execute:function (time, dt) {
107             var destPt = R.math.Vector2D.create(0, 0);
108             if (this.target.__POINT2D) {
109                 destPt.set(this.target);
110             } else if (this.target instanceof R.objects.Object2D && !this.target.isDestroyed()) {
111                 destPt.set(this.target.getOriginPosition());
112             } else {
113                 // Not a point or object, return zero steering
114                 return R.math.Vector2D.ZERO;
115             }
116 
117             var gO = this.getGameObject(), mC = this.getTransformComponent(), pt = R.clone(gO.getOriginPosition()),
118                 offs = R.clone(destPt).sub(pt), distance = offs.len(), steering = R.math.Vector2D.create(0, 0);
119 
120             if (!this.getGameObject() || this.getGameObject().isDestroyed()) {
121                 return steering;
122             }
123 
124             if (distance > 5) {
125                 offs.normalize();
126 
127                 if (distance < this.slowDist) {
128                     offs.mul(mC.getMaxSpeed() * (distance / this.slowDist));
129                 } else {
130                     offs.mul(mC.getMaxSpeed());
131                 }
132                 steering.set(offs.sub(mC.getVelocity()));
133             } else {
134                 steering.set(R.math.Vector2D.ZERO);
135                 this.arrived = true;
136             }
137 
138             offs.destroy();
139             pt.destroy();
140             destPt.destroy();
141 
142             return steering;
143         },
144 
145         /**
146          * True if the vehicle has "arrived" at it's destination
147          * @return {Boolean}
148          */
149         isArrived:function () {
150             return this.arrived;
151         }
152 
153     }, /** @scope R.components.logic.behaviors.Arrival.prototype */{
154         getClassName:function () {
155             return "R.components.logic.behaviors.Arrival";
156         }
157     });
158 };
159