看图说事: feel 和seek 唯一的不同就是 就是force 的方向不一样,seek force的方向是朝向目标,feel则相反。
注意看速度和转向力的矢量叠加,叠加后加载postion上,这就是当前智能体的位置。
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;
}
------------------------------------------------------------------------------------
假设上图的圆圈处是我们的target位置,那么desiredVelocity就是机车的position与target的position的矢量差(绿色),当然desiredVelocity不会是整个绿色线段的长度大小,否则机车就直接跳到target处了,所以我们把desiredVelocity限制在最大速度maxSpeed以内,也就是以最大的速度向目标行驶,转向力force是desiredVelocity与velocity的矢量差
Vector2D SteeringBehavior::Seek(Vector2D TargetPos)
{
//预期的速度,理想化情况下到达目标位置所需要的速度。它是从智能体到目标的向量,大小为智能体的当前最大速度。
Vector2D DesiredVelocity = Vec2DNormalize(TargetPos - m_pVehicle->Pos())
* m_pVehicle->MaxSpeed();
//预期速度 - 当前速度 = 操控力 见图3-2 P68
return (DesiredVelocity - m_pVehicle->Velocity());
}
例子效果参见
http://bbs.9ria.com/forum.php?mod=viewthread&tid=41805
Vector2D SteeringBehavior::Flee(Vector2D TargetPos)
{
Vector2D DesiredVelocity = Vec2DNormalize(m_pVehicle->Pos() - TargetPos)
* m_pVehicle->MaxSpeed();
return (DesiredVelocity - m_pVehicle->Velocity());
}
随转向力转向,实现避开行为
寻找行为是把机车向target拉,避开行为则是把机车往target外推,所以把add(force)改成substract(force)即可:
以下是AS 代码
和上面的C++代码意思是一样的。
public function flee(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. substract (force);
//将计算出来的转向力与原转向力做矢量差
}
参见例子:feel.swf
注意:
(1)现实中不管是什么车总有它的最大的速度,当速度达到这个最大值后,将以最大值作匀速运动,所以我们也对velocity作一下限制. ————这就是maxSpeed 的作用
(2)转向力相对于质量的处理,从相对的角度上来讲,同样大小的力作用到质量大的机车上时,我们把质量缩小比例到小质量,转向力也等比的缩小,这样我们把质量等同后,质量大的机车受到的转向力相对就会小,所以我们将转向力除以质量,来处理质量与转向力之间的关系,steerForce方法变更如下:
public function set steerForce(value:Vector2D):void {
_steerForce = value.divide(_mass);
}
(3) 想为什么没有转向动作呢 ? 机车转的太快 , 对 , 转的太快就意味着转向力太大 , 自己观察你会发现 , 红色的转向力有时候特别长 , 也就是转向力特别大 , 实际现实中 , 你转方向盘的劲儿再大 , 也不可能一下子把车头调过来 , 是吧 !^_^! 所以我们要给转向力加一个最大值 , 并在 steerForce 的 setter 方法中用最大值加以限制 :
private var _maxForce:Number = 1; //机车的最大转向力;
public function set steerForce(value:Vector2D):void {
value.truncate(_maxForce); //限制转向力的最大值,因为"方向盘转的角度有限"
_steerForce = value.divide(_mass); //大质量的机车转弯比较慢
}
这样转向力有了限制
,
机车无法在一次运算后
”
瞄准
”target,
我们就能看出转向的动作来了
(4)当机车行驶到边缘时,如果不冲出舞台,那么会有两种边缘行为edgeBehavior:折返和卷屏.我们先给这个边缘行为进行定义:
然后定义两种边缘行为:
private function bounce():void {
if (stage == null) return;
if (_position.x < 0) {
_position.x = 0;
_velocity.x *= -1;
}else if (_position.x > stage.stageWidth) {
_position.x = stage.stageWidth;
_velocity.x *= -1;
}
if (_position.y < 0) {
_position.y = 0;
_velocity.y *= -1;
}else if (_position.y > stage.stageHeight) {
_position.y = stage.stageHeight;
_velocity.y *= -1;
}
}
private function wrap():void {
if (stage == null) return;
if (_position.x < 0) _position.x = stage.stageWidth;
if (_position.x > stage.stageWidth) _position.x = 0;
if (_position.y < 0) _position.y = stage.stageHeight;
if (_position.y > stage.stageHeight) _position.y = 0;
}