游戏角色移动

碰撞检测

Posted by Iteevo on September 15, 2017

本文首发于 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;
        }

	}
}