flash on 2011-10-28 kihon forked:1favorite:3lines:297license : see code comments modified : 2011-10-28 02:37:19 Embed Tweet package { import com.bit101.components.HUISlider; import flash.display.Sprite; import flash.events.Event; public class Main extends Sprite { private var vehicles:Vector.<SteeredVehicle> = new Vector.<SteeredVehicle>(); private var distSlider:HUISlider; private var radiusSlider:HUISlider; public function Main() { distSlider = new HUISlider(this, 0, 400, "Distance", distSliderHandler); radiusSlider = new HUISlider(this, 0, 420, "Radius", radiusSliderHandler); distSlider.minimum = 0.0, distSlider.maximum = 200.0, distSlider.value = 50.0; radiusSlider.minimum = 0.0, radiusSlider.maximum = 100.0, radiusSlider.value = 25.0; vehicles.push(addChild(new SteeredVehicle(230, 230))); addEventListener(Event.ENTER_FRAME, onEnterFrame); } private function distSliderHandler(event:Event):void { for each (var vehicle:SteeredVehicle in vehicles) { vehicle.wanderDist = distSlider.value; } } private function radiusSliderHandler(event:Event):void { for each (var vehicle:SteeredVehicle in vehicles) { vehicle.wanderRadius = radiusSlider.value; } } private function onEnterFrame(event:Event):void { for each (var vehicle:SteeredVehicle in vehicles) { vehicle.wander(); vehicle.update(); } } } } class Vector2D { public var x:Number; public var y:Number; public function Vector2D(x:Number, y:Number) { this.x = x; this.y = y; } public static function get ZERO():Vector2D { return new Vector2D(0, 0); } public function add(vec:Vector2D):Vector2D { this.x += vec.x; this.y += vec.y; return this; } public function subtract(vec:Vector2D):Vector2D { this.x -= vec.x; this.y -= vec.y; return this; } public function multiply(value:Number):Vector2D { this.x *= value; this.y *= value; return this; } public function divide(value:Number):Vector2D { this.x /= value; this.y /= value; return this; } public function get length():Number { return Math.sqrt(x * x + y * y); } public function set length(value:Number):void { var a:Number = angle; x = Math.cos(a) * value; y = Math.sin(a) * value; } public function dot(vec:Vector2D):Number { return this.x * vec.x + this.y * vec.y; } public function normalize(thickness:Number = 1.0):Vector2D { if (length == 0) { this.x = 1.0; return this; } var scale:Number = thickness / length; this.x *= scale; this.y *= scale; return this; } public function distance(vec:Vector2D):Number { return Math.sqrt(distanceSquared(vec)); } public function distanceSquared(vec:Vector2D):Number { var tx:Number = this.x - vec.x; var ty:Number = this.y - vec.y; return tx * tx + ty * ty; } public function truncate(max:Number):Vector2D { length = Math.min(length, max); return this; } public function clone():Vector2D { return new Vector2D(x, y); } public function get angle():Number { return Math.atan2(y, x); } public function set angle(radian:Number):void { var len:Number = length; x = Math.cos(radian) * len; y = Math.sin(radian) * len; } } import flash.display.Sprite; class Vehicle extends Sprite { public static const WRAP:String = "wrap"; public static const BOUNCE:String = "bounce"; public var edgeBehavior:String = WRAP; public var velocity:Vector2D; public var maxSpeed:Number = 10.0; public var mass:Number = 1.0; public function Vehicle(x:Number, y:Number) { this.x = x; this.y = y; velocity = Vector2D.ZERO; } public function update():void { velocity.truncate(maxSpeed); this.x += velocity.x; this.y += velocity.y; if (edgeBehavior == WRAP) wrap(); else if (edgeBehavior == BOUNCE) bounce(); rotation = velocity.angle * 180 / Math.PI; draw(); } private function wrap():void { if (this.x < 0) { this.x = stage.stageWidth - 1; } else if (stage.stageWidth <= this.x) { this.x = 0; } if (this.y < 0) { this.y = stage.stageHeight - 1; } else if (stage.stageHeight <= this.y) { this.y = 0; } } private function bounce():void { if (this.x < 0) { velocity.x = -velocity.x; this.x = 0; } else if (stage.stageWidth <= this.x) { velocity.x = -velocity.x; this.x = stage.stageWidth - 1; } if (this.y < 0) { velocity.y = -velocity.y; this.y = 0; } else if (stage.stageHeight <= this.y) { velocity.y = -velocity.y; this.y = stage.stageHeight - 1; } } public function get position():Vector2D { return new Vector2D(x, y); } protected function draw():void { graphics.clear(); graphics.lineStyle(2.0, 0x0); graphics.moveTo(5, 0); graphics.lineTo(-10, -5); graphics.lineTo(-10, 5); graphics.lineTo(5, 0); } } class SteeredVehicle extends Vehicle { public var force:Vector2D; public var maxForce:Number = 1.0; public var arriveDist:Number = 100.0; public var wanderDist:Number = 50.0; public var wanderRadius:Number = 20.0; public var wanderAngle:Number = 0.0; public var wanderAngleRange:Number = 0.5; public function SteeredVehicle(x:Number, y:Number) { super(x, y); force = Vector2D.ZERO; } public function seek(target:Vector2D):void { var desiredVelocity:Vector2D = target.subtract(position); desiredVelocity.normalize().multiply(maxSpeed).subtract(velocity); force.add(desiredVelocity); } public function flee(target:Vector2D):void { var desiredVelocity:Vector2D = target.subtract(position); desiredVelocity.normalize().multiply(maxSpeed).subtract(velocity); force.subtract(desiredVelocity); } public function arrive(target:Vector2D):void { var desiredVelocity:Vector2D = target.subtract(position); var dist:Number = desiredVelocity.length; desiredVelocity.normalize().multiply(maxSpeed); if (dist < arriveDist) desiredVelocity.multiply(dist / arriveDist); desiredVelocity.subtract(velocity); force.add(desiredVelocity); } public function pursue(target:Vehicle):void { var frame:Number = target.position.distance(position) / maxSpeed; var predictedTarget:Vector2D = target.position.clone().add(target.velocity.clone().multiply(frame)); seek(predictedTarget); } public function evade(target:Vehicle):void { var frame:Number = target.position.distance(position) / maxSpeed; var predictedTarget:Vector2D = target.position.clone().add(target.velocity.clone().multiply(frame)); flee(predictedTarget); } public function wander():void { var center:Vector2D = velocity.clone().normalize().multiply(wanderDist); var offset:Vector2D = Vector2D.ZERO; offset.length = wanderRadius; offset.angle = wanderAngle; center.add(offset).subtract(velocity); force.add(center); wanderAngle += Math.random() * wanderAngleRange - wanderAngleRange / 2; } override public function update():void { force.truncate(maxForce); force.divide(mass); velocity.add(force); force = Vector2D.ZERO; super.update(); } override protected function draw():void { super.draw(); var center:Vector2D = velocity.clone().normalize().multiply(wanderDist); center.angle -= velocity.angle; graphics.drawCircle(center.x, center.y, wanderRadius); var offset:Vector2D = Vector2D.ZERO; offset.length = wanderRadius; offset.angle = wanderAngle; center.add(offset); graphics.beginFill(0xED1A3D); graphics.drawCircle(center.x, center.y, 5); graphics.endFill(); } } Code Fullscreen Preview Fullscreen andrewexex88.. atakanckilic.. aobyrne : aiAIinteractiveWandererwandererwanderflwandering ai interactiveWanderer wanderer wanderfl wandering target clone Math.sqrt normalize rotation Math.max Math.atan2 Math.cos Event length Math.sin Math.min addEventListener String Event.ENTER_FRAME push addChild Math.PI Vector Math.random sort new page view favorite forked pv310 Interactive wanderer explorer aobyrne forked:1 favorite:0lines:310 (diff:46) tag: ai interactiveWanderer seeking seeking-behavior wanderer wandering