本文首发于 Iteevo Blog 转载请保留链接。
碰撞检测
游戏场景中很多运动的角色,为了避免角色在运动期间相互穿插对方,我们需要做碰撞检测。一般的做法是检测当前角色与其它角色之间是否会发生碰撞,如果有可能发生碰撞,就要避让最短时间内会碰撞的角色。在以下代码中采用的是靠右行驶原则,选择碰撞点右边的一个零界点作为当前角色运动的中间目标点。
public class CollisionAvoidance : MonoBehaviour {
//public Transform[] candidates;
public Seek MySeek;
public float detectRadius = 6f;
public float radius = 1;
public Vector3 vel ;
// Use this for initialization
void Start () {
MySeek = GetComponent<Seek>();
}
// Update is called once per frame
void Update () {
float shortTime = float.MaxValue;
Collider[] candidates = Physics.OverlapSphere(transform.position, detectRadius,1<<LayerMask.NameToLayer("Entity"));
CollisionAvoidance target = null;
for (int i = 0; i < candidates.Length;i++)
{
if (candidates[i].gameObject == gameObject)
continue;
CollisionAvoidance ad = candidates[i].GetComponent<CollisionAvoidance>();
Vector3 deltaVel = ad.vel - vel;
Vector3 dis = candidates[i].transform.position - transform.position;
if (Vector3.Dot(deltaVel, dis) < 0)
{
float time = dis.magnitude / Vector3.Project(deltaVel, dis).magnitude;
if (time < shortTime)
{
shortTime = time;
target = ad;
}
}
}
if (shortTime < float.MaxValue)
{
Vector3 posA = target.transform.position + target.vel * shortTime;
Vector3 posB = transform.position + vel * shortTime;
if ((posA - posB).sqrMagnitude < radius * radius)
{
MySeek.TargetPos = posB + Vector3.Cross(Vector3.up, vel) * radius;
}
}
else
{
MySeek.TargetPos = vel * 2f + transform.position;
}
}
}