1 /**
  2  * The Render Engine
  3  * SeekBehavior
  4  *
  5  * @fileoverview Seek behavior, based on Craig Reynolds "Autonomous Steering Behaviors" article.
  6  *               The seek behavior will move the game object toward the provided destination
  7  *               position.
  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.Seek",
 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     "seekNearDistance":10
 49 });
 50 
 51 /**
 52  * @class The seek behavior component.  Causes an object to move toward a target.
 53  * @param target {R.math.Point2D|R.objects.Object2D} The point, or {@link R.objects.Object2D}, toward which the vehicle should seek
 54  * @extends R.components.logic.behaviors.BaseBehavior
 55  * @constructor
 56  */
 57 R.components.logic.behaviors.Seek = function () {
 58     "use strict";
 59     return R.components.logic.behaviors.BaseBehavior.extend(/** @scope R.components.logic.behaviors.Seek.prototype */{
 60 
 61         target:null,
 62         arrived:false,
 63 
 64         /** @private */
 65         constructor:function (target) {
 66             this.base("seek");
 67             this.setTarget(target);
 68             this.arrived = false;
 69         },
 70 
 71         destroy:function () {
 72             this.base();
 73             this.destPt.destroy();
 74         },
 75 
 76         reset:function () {
 77             this.arrived = false;
 78             this.base();
 79         },
 80 
 81         /**
 82          * Set the target to seek.
 83          * @param target {R.math.Point2D|R.objects.Object2D} The point, or object,
 84          *    to seek.
 85          */
 86         setTarget:function (target) {
 87             this.target = target;
 88         },
 89 
 90         /**
 91          * This method is called by the game object to run the component,
 92          * updating its state.
 93          *
 94          * @param renderContext {R.rendercontexts.AbstractRenderContext} The context the component will render within.
 95          * @param time {Number} The global engine time
 96          * @param dt {Number} The delta between the world time and the last time the world was updated
 97          *          in milliseconds.
 98          */
 99         execute:function (time, dt) {
100             var destPt = R.math.Vector2D.create(0, 0);
101             if (this.target.__POINT2D) {
102                 destPt.set(this.target);
103             } else if (this.target instanceof R.objects.Object2D && !this.target.isDestroyed()) {
104                 destPt.set(this.target.getOriginPosition());
105             } else {
106                 // Not a point or object, return zero steering
107                 return R.math.Vector2D.ZERO;
108             }
109 
110             // Calculate the desired velocity to steer toward the destination
111             var gO = this.getGameObject(), mC = this.getTransformComponent(), pt = R.clone(gO.getPosition()).add(gO.getOrigin()),
112                 offs = R.clone(destPt).sub(pt), distance = offs.len(), steering = R.math.Vector2D.create(0, 0);
113 
114             offs.normalize().mul(mC.getMaxSpeed());
115             steering.set(offs.sub(mC.getVelocity()));
116 
117             offs.destroy();
118 
119             if (this.nearPoint(pt, destPt, R.Engine.options.behaviors.seekNearDistance)) {
120                 this.arrived = true;
121             }
122 
123             pt.destroy();
124             destPt.destroy();
125             return steering;
126         },
127 
128         /**
129          * True if the object is near its destination.  You can change the "near"
130          * distance, by setting <code>R.Engine.options.behaviors.seekNearDistance</code>.
131          * @return {Boolean}
132          */
133         isArrived:function () {
134             return this.arrived;
135         },
136 
137         /**
138          * Determine if the first point is near the second point, within the
139          * set threshold.
140          * @param pt1
141          * @param pt2
142          * @param threshold
143          * @private
144          */
145         nearPoint:function (pt1, pt2, threshold) {
146             if (pt1 && pt2) {
147                 var p = R.math.Vector2D.create(pt1).sub(pt2), near = p.len() < threshold;
148                 p.destroy();
149                 return near;
150             }
151             return false;
152         }
153 
154     }, /** @scope R.components.logic.behaviors.Seek.prototype */{
155         getClassName:function () {
156             return "R.components.logic.behaviors.Seek";
157         }
158     });
159 };
160