1 /** 2 * The Render Engine 3 * ObstacleAvoidanceBehavior 4 * 5 * @fileoverview Obstacle avoidance behavior, based on Craig Reynolds "Autonomous Steering Behaviors" article. 6 * This behavior will avoid the objects which are provided to it. It will actively try to 7 * steer around the obstacles. 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.ObstacleAvoidance", 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 "obstacleAvoidanceRadius":60, 49 "obstacleAvoidanceFutureDistance":40 50 }); 51 52 /** 53 * @class The obstacle avoidance behavior component. This behavior will actively steer around 54 * the list of obstacles provided to it. 55 * @param obstacles {Array} The obstacle list to compare against 56 * @param [radius=150] {Number} The radius around each vehicle to use in collision detection 57 * @param [futureDist=60] {Number} The distance in front of the vehicle to perform checking 58 * @extends R.components.logic.behaviors.BaseBehavior 59 * @constructor 60 */ 61 R.components.logic.behaviors.ObstacleAvoidance = function () { 62 "use strict"; 63 return R.components.logic.behaviors.BaseBehavior.extend(/** @scope R.components.logic.behaviors.ObstacleAvoidance.prototype */{ 64 65 radius:0, 66 futureDist:0, 67 vehicles:null, 68 69 /** @private */ 70 constructor:function (obstacles, radius, futureDist) { 71 this.base("obstacleavoid"); 72 this.vehicles = obstacles; 73 this.radius = radius || R.Engine.options.behaviors.obstacleAvoidanceRadius; 74 this.futureDist = futureDist || R.Engine.options.behaviors.obstacleAvoidanceFutureDistance; 75 }, 76 77 /** 78 * This method is called by the game object to run the component, 79 * updating its state. 80 * 81 * @param renderContext {R.rendercontexts.AbstractRenderContext} The context the component will render within. 82 * @param time {Number} The global engine time 83 * @param dt {Number} The delta between the world time and the last time the world was updated 84 * in milliseconds. 85 */ 86 execute:function (time, dt) { 87 // No vehicles? nothing to do 88 if (!this.vehicles) { 89 return R.math.Vector2D.ZERO; 90 } 91 92 if (!this.getGameObject() || this.getGameObject().isDestroyed()) { 93 return R.math.Vector2D.ZERO; 94 } 95 96 var steering = R.math.Vector2D.create(0, 0), count = 0; 97 98 for (var i = 0; i < this.vehicles.length; i++) { 99 var other = this.vehicles[i]; 100 if (other === this.getGameObject()) { 101 // If this is our game object, skip it... 102 continue; 103 } 104 105 if (other.isDestroyed() || this.getGameObject().isDestroyed()) { 106 return R.math.Vector2D.ZERO; 107 } 108 109 var oPos = R.math.Vector2D.create(other.getOriginPosition()), 110 gO = this.getGameObject(), mC = this.getTransformComponent(), 111 fwd = R.clone(mC.getVelocity()).normalize().mul(this.futureDist), 112 gPos = R.math.Vector2D.create(gO.getOriginPosition()).add(fwd), 113 diff = R.clone(gPos).sub(oPos), d = diff.len(); 114 115 if (d > 0 && d < this.radius) { 116 // They are close to each other 117 diff.normalize(); //.div(d); 118 steering.add(diff); 119 count++ 120 } 121 122 oPos.destroy(); 123 gPos.destroy(); 124 fwd.destroy(); 125 diff.destroy(); 126 127 } 128 129 if (count > 0) { 130 steering.div(count); 131 } 132 133 if (steering.len() > 0) { 134 steering.normalize().mul(mC.getMaxSpeed()).sub(mC.getVelocity()).truncate(mC.getMaxForce()); 135 } 136 137 return steering; 138 } 139 140 }, /** @scope R.components.logic.behaviors.ObstacleAvoidance.prototype */{ 141 getClassName:function () { 142 return "R.components.logic.behaviors.ObstacleAvoidance"; 143 } 144 }); 145 }; 146