C# 如何更新Unity GameObject以沿样条曲线移动?

C# 如何更新Unity GameObject以沿样条曲线移动?,c#,unity3d,interpolation,gameobject,catmull-rom-curve,C#,Unity3d,Interpolation,Gameobject,Catmull Rom Curve,下午好 我试图在Unity中实现一个游戏对象,在给定8个受约束的随机值的情况下,它沿着三次CatMull Rom样条线移动。我已经实现了一个函数ComputePointOnCatmullRomCurve,它返回立方Catmull Rom曲线上的一个点(给定从0到1的标量“u”和表示插值使用的4个点的段数) 我在实现更新功能以使游戏对象平稳移动时遇到困难。每次更新我都会调用ComputePointOnCatmullRomCurve,每次都会增加段号。然后将GameObjects的位置设置为函数的结

下午好

我试图在Unity中实现一个游戏对象,在给定8个受约束的随机值的情况下,它沿着三次CatMull Rom样条线移动。我已经实现了一个函数ComputePointOnCatmullRomCurve,它返回立方Catmull Rom曲线上的一个点(给定从0到1的标量“u”和表示插值使用的4个点的段数)

我在实现更新功能以使游戏对象平稳移动时遇到困难。每次更新我都会调用ComputePointOnCatmullRomCurve,每次都会增加段号。然后将GameObjects的位置设置为函数的结果

然而,这会导致游戏对象移动非常快。我相信我的更新函数是不正确的,但是我不确定如何根据插值函数输出的点移动游戏对象

如果有人能够向我解释我做错了什么,或者提供一个例子或链接到一个例子,那将是非常有帮助的

计算曲线上点的函数:

Vector3 ComputePointOnCatmullRomCurve(float u, int segmentNumber)
{
    // TODO - compute and return a point as a Vector3       
    // Points on segment number 0 start at controlPoints[0] and end at controlPoints[1]
    // Points on segment number 1 start at controlPoints[1] and end at controlPoints[2]
    //       etc...

    Vector3 point = new Vector3();

    float c0 = ((-u + 2f) * u - 1f) * u * 0.5f;
    float c1 = (((3f * u - 5f) * u) * u + 2f) * 0.5f;
    float c2 = ((-3f * u + 4f) * u + 1f) * u * 0.5f;
    float c3 = ((u - 1f) * u * u) * 0.5f;

    Vector3 p0 = controlPoints[(segmentNumber - 1) % NumberOfPoints];
    Vector3 p1 = controlPoints[segmentNumber % NumberOfPoints];
    Vector3 p2 = controlPoints[(segmentNumber + 1) % NumberOfPoints];
    Vector3 p3 = controlPoints[(segmentNumber + 2) % NumberOfPoints];

    point.x = (p0.x * c0) + (p1.x * c1) + (p2.x * c2) + (p3.x * c3);
    point.y = (p0.y * c0) + (p1.y * c1) + (p2.y * c2) + (p3.y * c3);
    point.x = (p0.z * c0) + (p1.z * c1) + (p2.z * c2) + (p3.z * c3);

    return point;
}
void Update () {
    // TODO - use time to determine values for u and segment_number in this function call
    // 0.5 Can be used as u
    time += DT;

    segCounter++;

    Vector3 temp = ComputePointOnCatmullRomCurve(time, segCounter);
    transform.position = temp;
}
const int NumberOfPoints = 8;
Vector3[] controlPoints;

const int MinX = -5;
const int MinY = -5;
const int MinZ = 0;

const int MaxX = 5;
const int MaxY = 5;
const int MaxZ = 5;

float time = 0;
const float DT = 0.01f;
public static int segCounter = 0;
更新功能:

Vector3 ComputePointOnCatmullRomCurve(float u, int segmentNumber)
{
    // TODO - compute and return a point as a Vector3       
    // Points on segment number 0 start at controlPoints[0] and end at controlPoints[1]
    // Points on segment number 1 start at controlPoints[1] and end at controlPoints[2]
    //       etc...

    Vector3 point = new Vector3();

    float c0 = ((-u + 2f) * u - 1f) * u * 0.5f;
    float c1 = (((3f * u - 5f) * u) * u + 2f) * 0.5f;
    float c2 = ((-3f * u + 4f) * u + 1f) * u * 0.5f;
    float c3 = ((u - 1f) * u * u) * 0.5f;

    Vector3 p0 = controlPoints[(segmentNumber - 1) % NumberOfPoints];
    Vector3 p1 = controlPoints[segmentNumber % NumberOfPoints];
    Vector3 p2 = controlPoints[(segmentNumber + 1) % NumberOfPoints];
    Vector3 p3 = controlPoints[(segmentNumber + 2) % NumberOfPoints];

    point.x = (p0.x * c0) + (p1.x * c1) + (p2.x * c2) + (p3.x * c3);
    point.y = (p0.y * c0) + (p1.y * c1) + (p2.y * c2) + (p3.y * c3);
    point.x = (p0.z * c0) + (p1.z * c1) + (p2.z * c2) + (p3.z * c3);

    return point;
}
void Update () {
    // TODO - use time to determine values for u and segment_number in this function call
    // 0.5 Can be used as u
    time += DT;

    segCounter++;

    Vector3 temp = ComputePointOnCatmullRomCurve(time, segCounter);
    transform.position = temp;
}
const int NumberOfPoints = 8;
Vector3[] controlPoints;

const int MinX = -5;
const int MinY = -5;
const int MinZ = 0;

const int MaxX = 5;
const int MaxY = 5;
const int MaxZ = 5;

float time = 0;
const float DT = 0.01f;
public static int segCounter = 0;
变量:

Vector3 ComputePointOnCatmullRomCurve(float u, int segmentNumber)
{
    // TODO - compute and return a point as a Vector3       
    // Points on segment number 0 start at controlPoints[0] and end at controlPoints[1]
    // Points on segment number 1 start at controlPoints[1] and end at controlPoints[2]
    //       etc...

    Vector3 point = new Vector3();

    float c0 = ((-u + 2f) * u - 1f) * u * 0.5f;
    float c1 = (((3f * u - 5f) * u) * u + 2f) * 0.5f;
    float c2 = ((-3f * u + 4f) * u + 1f) * u * 0.5f;
    float c3 = ((u - 1f) * u * u) * 0.5f;

    Vector3 p0 = controlPoints[(segmentNumber - 1) % NumberOfPoints];
    Vector3 p1 = controlPoints[segmentNumber % NumberOfPoints];
    Vector3 p2 = controlPoints[(segmentNumber + 1) % NumberOfPoints];
    Vector3 p3 = controlPoints[(segmentNumber + 2) % NumberOfPoints];

    point.x = (p0.x * c0) + (p1.x * c1) + (p2.x * c2) + (p3.x * c3);
    point.y = (p0.y * c0) + (p1.y * c1) + (p2.y * c2) + (p3.y * c3);
    point.x = (p0.z * c0) + (p1.z * c1) + (p2.z * c2) + (p3.z * c3);

    return point;
}
void Update () {
    // TODO - use time to determine values for u and segment_number in this function call
    // 0.5 Can be used as u
    time += DT;

    segCounter++;

    Vector3 temp = ComputePointOnCatmullRomCurve(time, segCounter);
    transform.position = temp;
}
const int NumberOfPoints = 8;
Vector3[] controlPoints;

const int MinX = -5;
const int MinY = -5;
const int MinZ = 0;

const int MaxX = 5;
const int MaxY = 5;
const int MaxZ = 5;

float time = 0;
const float DT = 0.01f;
public static int segCounter = 0;
谢谢


Matt

您的更新功能有两个错误

第一个错误:

Vector3 ComputePointOnCatmullRomCurve(float u, int segmentNumber)
{
    // TODO - compute and return a point as a Vector3       
    // Points on segment number 0 start at controlPoints[0] and end at controlPoints[1]
    // Points on segment number 1 start at controlPoints[1] and end at controlPoints[2]
    //       etc...

    Vector3 point = new Vector3();

    float c0 = ((-u + 2f) * u - 1f) * u * 0.5f;
    float c1 = (((3f * u - 5f) * u) * u + 2f) * 0.5f;
    float c2 = ((-3f * u + 4f) * u + 1f) * u * 0.5f;
    float c3 = ((u - 1f) * u * u) * 0.5f;

    Vector3 p0 = controlPoints[(segmentNumber - 1) % NumberOfPoints];
    Vector3 p1 = controlPoints[segmentNumber % NumberOfPoints];
    Vector3 p2 = controlPoints[(segmentNumber + 1) % NumberOfPoints];
    Vector3 p3 = controlPoints[(segmentNumber + 2) % NumberOfPoints];

    point.x = (p0.x * c0) + (p1.x * c1) + (p2.x * c2) + (p3.x * c3);
    point.y = (p0.y * c0) + (p1.y * c1) + (p2.y * c2) + (p3.y * c3);
    point.x = (p0.z * c0) + (p1.z * c1) + (p2.z * c2) + (p3.z * c3);

    return point;
}
void Update () {
    // TODO - use time to determine values for u and segment_number in this function call
    // 0.5 Can be used as u
    time += DT;

    segCounter++;

    Vector3 temp = ComputePointOnCatmullRomCurve(time, segCounter);
    transform.position = temp;
}
const int NumberOfPoints = 8;
Vector3[] controlPoints;

const int MinX = -5;
const int MinY = -5;
const int MinZ = 0;

const int MaxX = 5;
const int MaxY = 5;
const int MaxZ = 5;

float time = 0;
const float DT = 0.01f;
public static int segCounter = 0;
您在每一帧增加当前段的索引(
segmentNumber
)。我想这应该只在对象完成沿上一条样条线线段的移动时进行

提示:

对于由多个面片定义的样条曲线,我通常在
[0,n]
范围内表示时间(
u
),其中
n
是定义曲线的段数。这样,只需从参数中提取整数部分,即可检索当前修补程序的索引(
segmentNumber
)。比如:

int segmentNumber =  Mathf.FloorToInt(u);
float segmentU = u - segmentNumber;
第二个错误

我不知道你的DT变量是什么,但是除非你在别的地方用帧增量时间来缩放它,否则你必须这样做。基本上,您可以通过以下方式增加时间:

time += Time.deltaTime * speedAlongCurve;

我希望它能有所帮助。

既然你说它移动得太快,那么改变
time+=DT
to
time+=DT*time.deltaTime解决您的计时问题?看到了吗?您是否在每次更新调用中增加实体所在的段数?@Chris adding Time.delatime无法解决此问题。时间变量可以设置为常量,例如0.5,但仍会发生快速运动。@MattCoubrough是的,每次更新时段的参考点都会增加,用于基于该初始点进行插值的其他三个点在计算点AtmullRomCurveOkay内初始化,因此,时间的变化将允许游戏对象沿曲线移动。每次更新更改游戏对象的索引都会迫使它从一个位置跳到另一个位置。所以问题是在适当的时候增加分段数,对吗?很抱歉,我很难理解您在包含的第一段代码中试图实现的目标。正如上面的评论所述,我很难理解您包含的代码段是如何工作的。只有在(time==1)的情况下,我才能通过增加段号来获得函数实现。我还将时间重置为0。然而,我有一种感觉,这只是巧合,而且有一种更合适的方法来循环遍历段。@马特·科兹瓦拉:没关系,第一个片段只是一个提示,当时间=1时,它在功能上应该等同于增量段索引。所以,如果你喜欢这样做,并工作,它是好的。第一个片段只是做了同样的事情:例如,假设您在时间0.5处于第二个片段,使用您的方法->t=0.5 seg=1,使用片段tTot=1.5 seg=floortoint(1.5)=1,t=1.5-1=0.5。都一样。