现在的位置: 首页 > 综合 > 正文

[AI-Steering编程]二.寻找行为

2012年06月08日 ⁄ 综合 ⁄ 共 10177字 ⁄ 字号 评论关闭

二.寻找行为

2.1
目的

实现机车自动移动到指定点.
2.2
实现

l计算到目标的转向力
l随转向力转向,实现寻找行为
2.3
讨论

l计算到目标的转向力
所谓寻找行为实际就是机车自动移到指定的目标点,要实现寻找,那么一定要有促使机车向目标点移动的转向力,转向力又怎么算呢?按照<AdvancED_ActionScript_Animation>里讲的,转向力应该是desiredVeloctiy和当前velocity的矢量差,而desiredVelocity是目标position与机车当前position的矢量差,什么什么什么啊,是不是看的头大了啊,没关系,看一下下面的分解图你就明白了:


steerForce.jpg



假设左图的圆圈处是我们的target位置,那么desiredVelocity就是机车的position与target的position的矢量差(绿色),当然desiredVelocity不会是整个绿色线段的长度大小,否则机车就直接跳到target处了,所以我们把desiredVelocity限制在最大速度maxSpeed以内,也就是以最大的速度向目标行驶,转向力force是desiredVelocity与velocity的矢量差,代码
如下:

                   public function seek(target:Vector2D):void {
                            var desiredVelocity:Vector2D = target.substract(_position);      
                            //计算desiredVelocity
                            desiredVelocity.normalize();                                                                  
                            //将desiredVelocity单位化
                            desiredVelocity = desiredVelocity.multiply(_maxSpeed);             
                            //desiredVelociy乘以最大速度maxSpeed,最大速度向目标前进
                           
                            var force:Vector2D = desiredVelocity.substract(_velocity);
                            steerForce = _steerForce.add(force);
                            //这里是用的steerForce的setter方法赋值的,因为setter方法有对steerForce的一个过滤处理
                   }

同样我对update中的velocity和velocity的setter方法也做以一些优化:

                   public function update():void {
                            velocity = _velocity.add(_steerForce);    //速度与转向力的矢量叠加,改为了setter赋值
                            _position = _position.add(_velocity);                 //位置与速度的矢量叠加
                           
                            this.x = _position.x;
                            this.y = _position.y;
                           
                            this.rotation = _velocity.angle * 180 / Math.PI;
                   }
                   public function set velocity(value:Vector2D):void {
                            value.truncate(_maxSpeed);                             //限制速度矢量的最大值
                            _velocity = value;
                   }

文档Main类,我们让机车把鼠标
的位置作为target,把seek方法加进去后,代码如下:

                   private function enterFrameHandler(e:Event):void {
                            vech.seek(new Vector2D(mouseX, mouseY));
                            vech.update();
                   }

这样运行完代码之后,我发现一个问题,机车像一磁铁一样,方向一直朝向鼠标,并没有转向的动作,具体效果
可以参考示例” 2-1-force1.swf
”.
mouseTarget.jpg


2-1-force1.swf


(2.98 KB)


看过那个上面的示例之后,你会想为什么没有转向动作呢?机车转的太快,对,转的太快就意味着转向力太大,自己观察你会发现,红色的转向力有时候特别长,也就是转向力特别大,实际现实中,你转方向盘的劲儿再大,也不可能一下子把车头调过来,是吧!^_^!所以我们要给转向力加一个最大值,并在steerForce的setter方法中用最大值加以限制:

                   private var _maxForce:Number = 1;      //机车的最大转向力;

                   public function set steerForce(value:Vector2D):void {
                            value.truncate(_maxForce);                    //限制转向力的最大值,因为"方向盘转的角度有限"
                            _steerForce = value.divide(_mass);           //大质量的机车转弯比较慢
                   }

这样转向力有了限制,机车无法在一次运算后”瞄准”target,我们就能看出转向的动作来了,请参考示例” 2-1-force2.swf”
2-1-force2.swf


(2.98 KB)

forceLimit.jpg



l随转向力转向,实现寻找行为


为了让运动更加生动,我添加了一个targetObj类,让机车自动去寻找targetObj的实例,targetObj类代码如下:

package ladeng6666.steering
{
         import flash.display.Sprite;
        
         public class TargetObj extends Sprite
         {
                   public function TargetObj()
                   {
                            draw();
                   }
                   private function draw():void {
                            var radius:Number = 5;
                            var span:Number = 3;
                           
                            graphics.lineStyle(1);
                            graphics.drawCircle(0, 0, radius);
                            graphics.moveTo(0, -radius - span);
                            graphics.lineTo(0, radius  + span);
                            graphics.moveTo( -radius - span, 0);
                            graphics.lineTo(radius  + span, 0);
                   }
                   public function get position():Vector2D {
                            return new Vector2D(this.x, this.y);
                   }
         }
        
}


本节讨论后完整的Velocity类代码如下:

package ladeng6666.steering
{
         import flash.display.Sprite;
        
         public class Vechile extends Sprite
         {
                   private var _color:uint;                    //机车的颜色
                   private var _position:Vector2D;                //机车的坐标
                   private var _velocity:Vector2D;                 //机车的速度向量
                   private var _steerForce:Vector2D;    //机车受到的外力
                  
                   private var _maxSpeed:Number=10;         //机车的最大速度,默认为10;
                   private var _mass:Number = 1;                 //机车的质量,默认为1;
                   private var _maxForce:Number = 1;      //机车的最大转向力;
                  
                   public function Vechile(color:uint=0xffffff)
                   {
                            _color = color;
                            _position = new Vector2D();
                            _velocity = new Vector2D();
                            _steerForce = new Vector2D();
                           
                            drawVechile();
                   }
                  
                   private function drawVechile():void {
                            graphics.clear();
                            graphics.lineStyle(0);
                            graphics.beginFill(_color, 0.8);
                            graphics.moveTo(10, 0);
                            graphics.lineTo( -10, 5);
                            graphics.lineTo( -10, -5);
                            graphics.lineTo(10, 0);
                            graphics.endFill();
                   }
                   //下面的setter和getter应该就不用解释了吧
                   public function set position(value:Vector2D):void {
                            _position = value;
                   }
                   public function get position():Vector2D {
                            return _position;
                   }
                   public function set velocity(value:Vector2D):void {
                            value.truncate(_maxSpeed);                             //限制速度矢量的最大值
                            _velocity = value;
                   }
                   public function get velocity():Vector2D {
                            return _velocity;
                   }
                   public function set steerForce(value:Vector2D):void {
                            value.truncate(_maxForce);                             //限制转向力的最大值,因为"方向盘转的角度有限"
                            _steerForce = value.divide(_mass);                   //大质量的机车转弯比较慢
                   }
                   public function get steerForce():Vector2D {
                            return _steerForce;
                   }
                   public function set maxSpeed(value:Number):void {
                            _maxSpeed = value;
                   }
                   public function get maxSpeed():Number {
                            return _maxSpeed;
                   }
                   public function set mass(value:Number):void {
                            if (value< 1) return;
                            _mass = value;
                            this.scaleX = this.scaleY = value;              //这一句实现机车大小的变化
                   }
                   public function get mass():Number {
                            return _mass;
                   }
                   public function update():void {
                            velocity = _velocity.add(_steerForce);              //速度与转向力的矢量叠加
                            _position = _position.add(_velocity);                 //位置与速度的矢量叠加
                           
                            this.x = _position.x;
                            this.y = _position.y;
                           
                            this.rotation = _velocity.angle * 180 / Math.PI;
                            steerForce = new Vector2D();
                   }
                   public function seek(target:Vector2D):void {
                            var desiredVelocity:Vector2D = target.substract(_position);      
                            //计算desiredVelocity
                            desiredVelocity.normalize();                                                                  
                            //将desiredVelocity单位化
                            desiredVelocity = desiredVelocity.multiply(_maxSpeed);             
                            //desiredVelociy乘以最大速度maxSpeed,最大速度向目标前进
                           
                            var force:Vector2D = desiredVelocity.substract(_velocity);
                            //计算转向力
                            steerForce = _steerForce.add(force);
                            //讲计算出来的转向力与原转向力叠加
                   }
         }
        
}


本节讨论后完整的Main
类代码如下:

package 
{
         import flash.display.Graphics;
         import flash.display.Sprite;
         import flash.events.Event;
        
         import ladeng6666.steering.Vector2D;
         import ladeng6666.steering.Vechile;
         import ladeng6666.steering.TargetObj;
 
         public class Main extends Sprite
         {
                   private var vech:Vechile;                           //机车实例
                   private var targetObj:TargetObj; //机车寻找的目标
                  
                   public function Main()
                   {
                            targetObj = new TargetObj();
                            vech = new Vechile();
                            vech.mass = 2;                                                   //机车的质量
                            addChild(vech);
                            addChild(targetObj);
                           
                            addEventListener(Event.ENTER_FRAME, enterFrameHandler);
                   }
                   //按照帧频随速度更新机车的位置
                   private function enterFrameHandler(e:Event):void {
                            vech.seek(targetObj.position);
                            vech.update();
                           
                            var dis:Vector2D = vech.position.substract(targetObj.position);
                            //找到目标后,随机移动目标
                            if (dis.length < 5) {
                                     targetObj.x = Math.random() * stage.stageWidth;
                                     targetObj.y = Math.random() * stage.stageHeight;
                            }
                   }
         }
}


具体效果请参考示例
”2-2.swf”,

好了
,

今天就到这里了
,23:54


,

太晚了
,

睡觉了
!12/6/2009
2-2.swf


(3.42 KB)

本章的源代码如下:




chapter2.rar


(19.7 KB)

抱歉!评论已关闭.