二.寻找行为
2.1
目的
实现机车自动移动到指定点.
2.2
实现
l计算到目标的转向力
l随转向力转向,实现寻找行为
2.3
讨论
l计算到目标的转向力
所谓寻找行为实际就是机车自动移到指定的目标点,要实现寻找,那么一定要有促使机车向目标点移动的转向力,转向力又怎么算呢?按照<AdvancED_ActionScript_Animation>里讲的,转向力应该是desiredVeloctiy和当前velocity的矢量差,而desiredVelocity是目标position与机车当前position的矢量差,什么什么什么啊,是不是看的头大了啊,没关系,看一下下面的分解图你就明白了:
假设左图的圆圈处是我们的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
”.
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)
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)