很多時候我們需要做類似上圖的OffMeshLink的跳躍功能,並方便添加跳躍動畫,Unity本身沒提供,但是有官方的案例提供了方法,很多人沒找到,故貼出來
原鏈接:https://github.com/Unity-Technologies/NavMeshComponents/blob/master/Assets/Examples/Scripts/AgentLinkMover.cs
我在它的基礎上添加了兩個多播委托及快速轉向(紅字顯示),用來檢測跳躍開始及結束,方便用來做跳躍動畫的,而且NavMeshAgentde轉速太慢,我添加一個快速轉向到落地點的方法。
用不到的就用原版吧。
using UnityEngine; using System.Collections; using UnityEngine.AI; public enum OffMeshLinkMoveMethod { Teleport, NormalSpeed, Parabola, Curve } [RequireComponent(typeof(NavMeshAgent))] public class AgentLinkMover : MonoBehaviour { public OffMeshLinkMoveMethod method = OffMeshLinkMoveMethod.Parabola; public AnimationCurve curve = new AnimationCurve(); public float CurveTime = .5f; public float FaceTime = .1f; public delegate void OnStartEvent(); public event OnStartEvent OnStart; public delegate void OnCompleteEvent (); public event OnCompleteEvent OnComplete; IEnumerator Start() { NavMeshAgent agent = GetComponent<NavMeshAgent>(); agent.autoTraverseOffMeshLink = false; while (true) { if (agent.isOnOffMeshLink) { yield return StartCoroutine (FaceToTarget (agent, FaceTime)); if (method == OffMeshLinkMoveMethod.NormalSpeed) yield return StartCoroutine(NormalSpeed(agent)); else if (method == OffMeshLinkMoveMethod.Parabola) yield return StartCoroutine(Parabola(agent, 2.0f, 0.5f)); else if (method == OffMeshLinkMoveMethod.Curve) yield return StartCoroutine(Curve(agent, CurveTime)); agent.CompleteOffMeshLink(); agent.updateRotation = true; OnComplete (); } yield return null; } } IEnumerator FaceToTarget(NavMeshAgent agent,float duration){ agent.updateRotation = false; OffMeshLinkData data = agent.currentOffMeshLinkData; Quaternion startRotation = agent.transform.rotation; Vector3 endPos = data.endPos + Vector3.up * agent.baseOffset; var endRotation = Quaternion.LookRotation (new Vector3 (endPos.x - agent.transform.position.x, 0, endPos.z - transform.position.z)); float normalizedTime = 0.0f; while (normalizedTime < 1.0f) { agent.transform.rotation = Quaternion.Slerp(startRotation ,endRotation ,normalizedTime); normalizedTime += Time.deltaTime / duration; yield return null; } OnStart (); } IEnumerator NormalSpeed(NavMeshAgent agent) { OffMeshLinkData data = agent.currentOffMeshLinkData; Vector3 endPos = data.endPos + Vector3.up * agent.baseOffset; while (agent.transform.position != endPos) { agent.transform.position = Vector3.MoveTowards(agent.transform.position, endPos, agent.speed * Time.deltaTime); yield return null; } } IEnumerator Parabola(NavMeshAgent agent, float height, float duration) { OffMeshLinkData data = agent.currentOffMeshLinkData; Vector3 startPos = agent.transform.position; Vector3 endPos = data.endPos + Vector3.up * agent.baseOffset; float normalizedTime = 0.0f; while (normalizedTime < 1.0f) { float yOffset = height * 4.0f * (normalizedTime - normalizedTime * normalizedTime); agent.transform.position = Vector3.Lerp(startPos, endPos, normalizedTime) + yOffset * Vector3.up; normalizedTime += Time.deltaTime / duration; yield return null; } } IEnumerator Curve(NavMeshAgent agent, float duration) { OffMeshLinkData data = agent.currentOffMeshLinkData; Vector3 startPos = agent.transform.position; Vector3 endPos = data.endPos + Vector3.up * agent.baseOffset; float normalizedTime = 0.0f; while (normalizedTime < 1.0f) { float yOffset = curve.Evaluate(normalizedTime); agent.transform.position = Vector3.Lerp(startPos, endPos, normalizedTime) + yOffset * Vector3.up; normalizedTime += Time.deltaTime / duration; yield return null; } } }
用法,附着到NavMeshAgent物體上,選擇需要的移動方式即可,然后搭配一下代碼食用更佳:
AgentLinkMover mover = GetComponent<AgentLinkMover>(); mover.OnStart += () => print("start"); mover.OnComplete += () => print("complete");