您的位置:首页 > 其它

关于游戏中拦截算法的实现

2015-11-08 23:49 225 查看
拦截,顾名思义,在追及目标的时候,预测目标在未来一段时间会到达的位置,并提前朝着这个位置前进。

在追及者速度大于被追及者(且称猎物)速度时,采用拦截算法能有效利用速度效率,并且能在某些情况下解决普通追及算法所出现的问题(例如追及者被甩尾会浪费速度效率)

拦截算法的关键是求出追及者速度的方向,需要猎物此刻相对追及者的位置、猎物的速度大小及其方向。

思路大致为:算出猎物相对于追及者的速度和位移,然后用相对位移除以相对速度得出预计拦截所需时间,再用猎物的速度乘拦截时间再加上猎物自身位移得出预计拦截点,

最后让追及者朝着拦截点运动进行拦截。(上述除时间其他变量均为向量,即带大小和方向)

简单的拦截算法在unity中实现,关键脚本如下:

public class Enemy : MonoBehaviour
{
float cTime;//预计拦截时间
public int speedMag = 5;//速度级数
Vector3 speed = new Vector3();追及者速度

Vector3 target = new Vector3();//预测拦截点
Vector3 pPos = new Vector3();//相对位移
Vector3 pSpeedVec3 = new Vector3();//相对速度

Player player;//获得猎物的速度和位置

void Awake()
{
player = GameObject.FindGameObjectWithTag("Player").GetComponent<Player>();
}

void Update()
{
transform.position += speed * Time.deltaTime;//实现运动

pSpeedVec3 = player.speed - speed;//该段为拦截算法
pPos = player.transform.position - transform.position;
cTime = pPos.magnitude / pSpeedVec3.magnitude;
target = player.transform.position + player.speed * cTime;

CatchAt(target);//追及者朝着拦截点运动
}

void CatchAt(Vector3 target)
{
Vector3 dir = (target - transform.position).normalized * speedMag;
if (dir.x > 0)
{
speed.x = Mathf.Min(speed.x + 1, dir.x);
}
else if (dir.x < 0)
{
speed.x = Mathf.Max(speed.x - 1, dir.x);
}
if (dir.z > 0)
{
speed.z = Mathf.Min(speed.z + 1, dir.z);
}
else if (dir.z < 0)
{
speed.z = Mathf.Max(speed.z - 1, dir.z);
}
}
}


该demo中,拦截算法每帧执行一次,故追及者每刻都会根据猎物的位置和速度来调整自身的拦截方向,所以即使猎物在进行变速运动,追及者都能完成拦截算法。

问:拦截算法的关键就是求出追及者速度的方向,然而在拦截算法的计算中却用到追及者的速度向量,是否相悖?
答:看上去确实有矛盾,但在该案例中,先把追及者速度初始化为零,此时拦截算法中的相对速度即为猎物速度,因此拦截算法能正常得出拦截点,再由CatchAt()函数将速度校准。
Ps:CatchAt函数是通过改变速度的分量大小来改变速度的方向,因此在校准速度时速度大小也会变化。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: