控制一個(gè)GameObject隨著某一個(gè)路徑進(jìn)行移動(dòng)柏副,這是一個(gè)經(jīng)常需要用到的功能。一個(gè)比較常用的實(shí)現(xiàn)方式是利用DoTween這樣的插件來(lái)做到,其他的方式也都大同小異棵介,原理都是通過(guò)設(shè)置一條路徑摩骨,然后每一幀都利用這個(gè)路徑來(lái)計(jì)算當(dāng)前需要出現(xiàn)的位置擎椰,然后把目標(biāo)GameObject放到那個(gè)位置上秉沼。
那這里我就對(duì)這種方式進(jìn)行一個(gè)封裝州刽,寫(xiě)一個(gè)類(lèi)來(lái)專(zhuān)門(mén)做這件事呕寝,這樣以后每次需要用這個(gè)功能的時(shí)候就只要一行代碼就可以實(shí)現(xiàn)勋眯。原理很簡(jiǎn)單,代碼也不復(fù)雜下梢。
using UnityEngine;
using System.Collections.Generic;
namespace LDFW.Math
{
[System.Serializable]
public class LDFWPath
{
public AnimationCurve xValueCurve;
public AnimationCurve yValueCurve;
public AnimationCurve zValueCurve;
public float totalDistance;
public bool useSmoothCurve = true;
public LDFWPath()
{
Init();
}
public void Init()
{
xValueCurve = new AnimationCurve();
yValueCurve = new AnimationCurve();
zValueCurve = new AnimationCurve();
totalDistance = 0;
}
public void ConstructPath(Vector3[] pathPoints)
{
if (pathPoints == null || pathPoints.Length < 2)
{
return;
}
Init();
float[] pathDistance = new float[pathPoints.Length];
totalDistance = 0;
pathDistance[0] = 0;
for (int i = 1; i < pathPoints.Length; i++)
{
totalDistance += Vector3.Distance(pathPoints[i], pathPoints[i - 1]);
pathDistance[i] = totalDistance;
}
float currentDistance = 0;
float currentPercentage = 0;
Vector3 inTangent = Vector3.zero;
Vector3 outTangent = Vector3.zero;
// Add first point
if (useSmoothCurve)
AddSmoothKeyFrame(pathPoints[0], 0);
else
{
float deltaPercentage = pathDistance[1] / totalDistance;
if (deltaPercentage == 0)
AddSmoothKeyFrame(pathPoints[0], 0);
else
AddTangentKeyFrame(pathPoints[0], 0, Vector3.zero, (pathPoints[1] - pathPoints[0]) / (pathDistance[1] / totalDistance));
}
// Add rest points
for (int i = 1; i < pathPoints.Length; i++)
{
currentDistance += Vector3.Distance(pathPoints[i], pathPoints[i - 1]);
currentPercentage = currentDistance / totalDistance;
if (useSmoothCurve)
{
AddSmoothKeyFrame(pathPoints[i], currentPercentage);
}
else
{
if (i == pathPoints.Length - 1)
{
inTangent = (pathPoints[i] - pathPoints[i - 1]) / ((pathDistance[i] - pathDistance[i - 1]) / totalDistance);
outTangent = Vector3.zero;
}
else
{
inTangent = (pathPoints[i] - pathPoints[i - 1]) / ((pathDistance[i] - pathDistance[i - 1]) / totalDistance);
outTangent = (pathPoints[i + 1] - pathPoints[i]) / ((pathDistance[i + 1] - pathDistance[i]) / totalDistance);
}
AddTangentKeyFrame(pathPoints[i], currentPercentage, inTangent, outTangent);
}
}
}
public void ConstructPath(List<Vector3> pointList)
{
for (int i = 1; i < pointList.Count; i++)
{
if (pointList[i] == pointList[i - 1])
{
pointList.RemoveAt(i);
i--;
}
}
ConstructPath(pointList.ToArray());
}
public void AddSmoothKeyFrame(Vector3 position, float percentage)
{
percentage = Mathf.Clamp(percentage, 0, 1);
int x = xValueCurve.AddKey(percentage, position.x);
int y = yValueCurve.AddKey(percentage, position.y);
int z = zValueCurve.AddKey(percentage, position.z);
}
public void AddTangentKeyFrame(Vector3 position, float percentage, Vector3 inTangent, Vector3 outTangent)
{
percentage = Mathf.Clamp(percentage, 0, 1);
int x = xValueCurve.AddKey(new Keyframe(percentage, position.x, inTangent.x, outTangent.x));
int y = yValueCurve.AddKey(new Keyframe(percentage, position.y, inTangent.y, outTangent.y));
int z = zValueCurve.AddKey(new Keyframe(percentage, position.z, inTangent.z, outTangent.z));
}
public Vector3 Evaluate(float percentage)
{
return new Vector3(xValueCurve.Evaluate(percentage), yValueCurve.Evaluate(percentage), zValueCurve.Evaluate(percentage));
}
}
}