控制一个GameObject随着某一个路径进行移动,这是一个经常需要用到的功能。一个比较常用的实现方式是利用DoTween这样的插件来做到,其他的方式也都大同小异,原理都是通过设置一条路径,然后每一帧都利用这个路径来计算当前需要出现的位置,然后把目标GameObject放到那个位置上。
那这里我就对这种方式进行一个封装,写一个类来专门做这件事,这样以后每次需要用这个功能的时候就只要一行代码就可以实现。原理很简单,代码也不复杂。
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));
}
}
}