上一篇 讲到了追踪算法的比较简单的形式,看上去比较假,因为AI控制的对象过于精确地跟踪目标。一种更自然的追踪方式可以这样做,使得跟踪者的方向矢量与从跟踪目标的中心到跟踪者的中心所定义的方向矢量靠拢。
如图所示:
这个算法的基本思路是这样的:假设AI控制的对象即追踪者有如下属性
1、Position:(tracker.x,tracker.y)
2、Velocity:(tracker.vx,tracker.vy)
追踪目标有如下属性:
1、Postion:(target.x,target.y)
2、Velocity:(target.vx,target.vy)
接下来就是调整追踪者的速度向量的常用逻辑:
1、计算从跟踪者到跟踪目标的向量:TV=(target.x-tracker.x,target.y-tracker.y)=(tvx,tvy),归一化TV,这样就可以得到一个单位向量,从而方便计算它与坐标轴的角度。归一化也即是sqrt(x^2+y^2).
2、调整追踪者当前的速度向量,加上一个按rate比例缩放过的TV*
tracker.x+=rate*tvx;
traker.y+=rate*tvy;
注意这一步才是关键,它使得导弹的追踪不在是从前的直接紧密追踪而是会有一个变轨迹的过程,另外当rate等于1的时候,跟踪向量会合的更快,跟踪算法对目标跟踪的根据紧密,并更快地的修正目标的运动。
3、跟踪者的速度向量修改过后,有可能向量的速度会溢出最大值。换言之,跟踪者一旦锁定了目标的方向就会继续沿着该方向加速。所以需要设置一个上限,让追踪者的速度从某处慢下来
在Unity5.1.1实现的效果图如图所示:
在这里我还调整了导弹的追踪方向rotation的变化,其实如果是3D空间就可以直接使用lookAt方法来使得导弹的运动方向始终朝向目标,但是在2D平面上就没有这么好的方法供我们调用了,所以我自己写了一个算法。如果不加这个方向修正算法的结果如图所示:
导弹的运行是不是显得非常的生硬,运动的轨迹和导弹头的朝向并不一致,这一段的修正导弹头的方向的代码如下:
void LookAtTarget() { float zAngles; if(moveVy==0) { zAngles = moveVx >= 0 ? -90 : 90; } zAngles = Mathf.Atan(moveVx / moveVy) * (-180 / Mathf.PI); if(moveVy<0) { zAngles = zAngles - 180; } Vector3 tempAngles = new Vector3(0, 0, zAngles); Quaternion tempQua = this.transform.rotation; tempQua.eulerAngles = tempAngles; this.transform.rotation = tempQua; }
算法的计算思路是:
注意:这个平面上的角度主要是Z轴的角度变化,而Z轴的角度是导弹头方向直线与y轴的夹角,这点比较蛋疼。另外坐标的顶点是位于屏幕的左上角。
1、根据导弹的运动速度矢量来调整导弹头的方向
2、导弹的速度矢量为x和y方向的矢量和,根据反三角函数来计算出导弹与屏幕坐标y轴的夹角
3、要特别注意当moveVy为0的情况,不考虑这个会导致计算反三角的时候分母为零而因溢出而报错,以及moveVy小于0的情况,不考虑这个会使得方向刚好会想法。
最终的代码为:
本文转自:CSDN - 凯尔八阿哥,转载此文目的在于传递更多信息,版权归原作者所有。