行为5

漫游行为模拟

漫游的目的

  漫游是指角色在场景中毫无目的的移动

.这通常用来模拟巡视和觅食,

也有纯粹是为了漫游而漫游的.


漫游行为 

   简单的使用随机而产生的布朗运动,会让角色感觉像一个神经病的傻瓜.

   我们需要更自然更平滑的感觉.

    有个办法,通常设想在角色前方有个圆,然后把圆上任意一点作为目标,每次更新都想这个随机点移动.

   由于目标点总是落在假象的圆上,  所以转向力永远不会一下子就变化很大.  可以参照右图加以理解!


交通工具的前端凸出个圆圈,目标被限制在该圆圈上,然后我们移向目标。每帧给目标添加一个随机的位置,随着时间的推移,沿着圆周移来移去,以创建一个没有抖动的往复运动。

利用不同的圆圈尺寸、到交通工具的距离、每帧的随机位移的大小,这个方法可以产生所有范围的往复运动,从非常光滑的波状式转弯到狂野的Strictly Ballroom式旋转,再到以脚尖立地的旋转。





   目标
<AdvancED ActionScript3>的描述,实现机车的漫游行为.
  实现
l创建圆
l在圆上添加随机点,引导机车转向
l向圆上的随机点转向
  讨论
l创建圆



在机车的正前方添加一个圆.要添加圆,就一定要有圆心.

这个圆心处在机车的正前方,也就是说要在velocity的延长线上,

通过上面的图解也能看的出来,那这个圆心离机车多远呢?我们定义这个距离为  _wanderDistance:


                   private var _wanderDistance:Number = 50;             //机车漫游的圆心位置

                   public function set wanderDistance(value):void {
                            _wanderDistance = value;
                   }
                   public function get wanderDistance():Number {
                            return _wanderDistance;
                   }

然后是圆心的计算:

                            var center:Vector2D = _velocity.clone().normalize().multiply(_wanderDistance);
                            //在机车的正前方_wanderDistance位置,添加圆的圆心

再多啰嗦两句,velocity.clone().normalize()的作用是将velocity单位化,因为我们要的只是velocity的方向,

然后在velocity的方向上乘以_wanderDistance就是圆心的位置了!

另外,圆心的位置是实时更新的,所以上面的代码在wander方法中,要和update方法一起更新的.



圆心定下来了,下面是圆的半径:


                   private var _wanderRadius:Number = 30;                         //机车漫游目标的范围

                   public function set wanderRadius(value):void {
                            _wanderRadius = value;
                   }
                   public function get wanderRadius():Number {
                            return _wanderRadius;
                   }



l在圆上添加随机点,引导机车转向
这样,图中的那个圆我们就画出来了”,然后,就是在圆上添加随机的点,引导机车转向.
所谓随机是相对于圆心来讲的.所以随机点的位置可以用

     圆心矢量center   加上偏移矢量offset,

为了让随机点落在圆上,

     我们就把偏移量offset的长度限定为半径wanderRadius.

     然后随机化偏移量offset的角度就好了,代码如下:

                            var offset:Vector2D = new Vector2D(0);      //随机点与圆心的偏移量
                            offset.length = _wanderRadius;             //为是随机点落在圆心上,限定偏移量的长度为_wanderRadius
                            offset.angle = _wanderAngle;               //随机偏移的角度
                            _wanderAngle += (Math.random()-0.5);
                            var force:Vector2D = center.add(offset);//圆心矢量加偏移矢量确定随机点,随机点确定后,直接添加随机点方向的转向力.


l向圆上的随机点转向
随机点确定后,直接添加随机点方向的转向力force,然后这个转向力force与之前的steerForce叠加即是新的作用力:

                            steerForce = _steerForce.add(force);
                            //讲计算出来的转向力与原转向力叠加




                   public function wander():void {
                            var center:Vector2D = _velocity.clone().normalize().multiply(_wanderDistance);
                            //在机车的正前方_wanderDistance位置,添加圆的圆心
                            var offset:Vector2D = new Vector2D(0);
                            //随机点与圆心的偏移量
                            offset.length = _wanderRadius;
                            //为是随机点落在圆心上,限定偏移量的长度为_wanderRadius
                            offset.angle = _wanderAngle;
                            //随机偏移的角度
                            _wanderAngle += (Math.random()-0.5);
                            
                            var force:Vector2D = center.add(offset);
                            //圆心矢量加偏移矢量确定随机点,随机点确定后,直接添加随机点方向的转向力.
                            steerForce = _steerForce.add(force);
                            //讲计算出来的转向力与原转向力叠加
                   }

         public class Wander extends Sprite
         {
                   private var wanderVehicle:Vehicle;                     //漫游机车实例
                   
                   public function Wander() 
                   {
                            wanderVehicle = new Vehicle();
                            wanderVehicle.position = new Vector2D(100, 200);
                            
                            addChild(wanderVehicle);
                            
                            addEventListener(Event.ENTER_FRAME, enterFrameHandler);
                   }
                   //按照帧频随速度更新机车的位置
                   private function enterFrameHandler(e:Event):void {
                            wanderVehicle.wander();
                            wanderVehicle.update();  //如下代码
                   }
         }


wanderVehicle.update 的代码:

重点:

velocity = _velocity.add(_steerForce); //速度与转向力的矢量叠加
_position = _position.add(_velocity); //位置与速度的矢量叠加


public function update():void {
			velocity = _velocity.add(_steerForce);		//速度与转向力的矢量叠加
			_position = _position.add(_velocity);		//位置与速度的矢量叠加
			
			this.x = _position.x;
			this.y = _position.y;
			//判断并设置边缘行为
			if (_edgeBehavior == "bounce") {
				bounce();
			}else if (_edgeBehavior == "wrap") {
				wrap();
			}
			this.rotation = _velocity.angle * 180 / Math.PI;
		}



---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

C++ 代码:





//--------------------------- Wander -------------------------------------
//
//  This behavior makes the agent wander about randomly
//------------------------------------------------------------------------
Vector2D SteeringBehavior::Wander()
{ 
  //<span style="font-family: 'Times New Roman';">每秒加到目标的随机位移的最大值 * 记录最近更新的时间</span>
  double JitterThisTimeSlice = m_dWanderJitter * m_pVehicle->TimeElapsed();

  //<span style="font-family: 'Times New Roman';">首先,加一个小的随机向量到目标位置</span>
<span style="font-family:Times New Roman;">  //</span><span style="font-family: 'Times New Roman';">RandomClamped 返回-1到1之间的一个数</span><span style="font-family:Times New Roman;">
  m_vWanderTarget += Vector2D(RandomClamped() * JitterThisTimeSlice,
                              RandomClamped() * JitterThisTimeSlice);

  //把这个新的向量重新投影回单元圆周上</span>
<span style="font-family:Times New Roman;"> //先标准化,确定方向,再乘以半径回到圆上了。
  m_vWanderTarget.Normalize();
  m_vWanderTarget *= m_dWanderRadius;

  //上面两行代码表示:先标准化再乘以半径,标准化只表示方向,再乘以半径表示加上大小






  //移动目标位置在智能体前面WanderDist位置。
  Vector2D target = m_vWanderTarget + Vector2D(m_dWanderDistance, 0);

  //吧目标投影到世界空间

  Vector2D Target = PointToWorldSpace(target,
                                       m_pVehicle->Heading(),
                                       m_pVehicle->Side(), 
                                       m_pVehicle->Pos());

  //移向它,操控力
  return Target - m_pVehicle->Pos(); 
}</span>



注意:wander距离和这个方法返回的操控力的角度变化之间的关系。当wander圆圈交通工具很远时,这个方法使角度发生小变化,因此交通工具只能小转弯。当圆圈移近交通工具时,他就可以大转弯了。




















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值