【问题标题】:Unity3D BezierCurve - Spline Walker Following AI?Unity3D BezierCurve - 跟随 AI 的 Spline Walker?
【发布时间】:2019-11-14 02:20:06
【问题描述】:

我一直在努力创建一个具有称职(但公平)赛车 AI 的游戏,并且我有几个我正在努力解决的限制。以下是条件:

1.) AI 逻辑和玩家控制都共享同一个汽车控制器来驱动和转弯等。AI 车辆只是根据汽车试图转弯的距离传递一个钳制的(-1 到 1)值,并且油门接合。 AI 和玩家共享布尔值来刹车,并用 SHIFT 键漂移转向

2.) AI 需要做出明智、明智的决定,让玩家在应用适当的转弯量、何时滑行等方面做出明智的决定。

我最初使用简单的航路点增量系统让 AI 根据航路点继续绕轨道运行。使用正确的车轮摩擦曲线值(我碰巧在网上找到了),这实际上可以正常工作。然而,当我特别在车轮摩擦值上苦苦挣扎时,并且仍然希望为 AI 提供更平滑的路径跟随和转向逻辑时,有人建议我使用三次贝塞尔样条曲线。我发现 Catlike 编码教程很吸引人(我相信你们中的许多人都知道这一点,但是下面的链接供任何感兴趣的人使用):

https://catlikecoding.com/unity/tutorials/curves-and-splines/

然后我想到了使用本教程中的 Spline Walker 作为 AI 的唯一航路点,并有效地“逗弄”汽车跟随 spline walker,就像这个视频:

https://www.youtube.com/watch?v=UcA4K2rmX-U#action=share

但是,这是我的大问题 - 如果我想让我的车跟随样条助行器,同时保持样条助行器始终在前面,我必须确保样条助行器跟随的“进度”是相对于后面的车,样条助行器在前面保持一点点,这样车就不会决定减速和停车。

我一直在寻找这样做的例子,我不能说我太成功了。

这是我当前的进度计算代码 sn-ps - 我正在尝试通过碰巧共享相同变换坐标的旧航点对象存储样条曲线上位置之间的距离:

private void Start()
    {
        Rigidbody rb = chasingCar.GetComponent<Rigidbody>();
        if(path)
        {
            nodes = path.GetComponentsInChildren<Transform>();
        }
        Array.Resize(ref distances, nodes.Length-1);
        for (int i = 0; i < nodes.Length-1; i++)
        {
            //start storing the distances between two successive waypoints on the spline
            distances[i] = Vector3.Distance(nodes[i].position, nodes[i + 1].position);
            totalDistance += distances[i];
        }
        Debug.Log("First distance value is " + distances[0] + " and overall distance est is " + totalDistance);
        Debug.Log("Second distance value is " + distances[1] + " and overall distance est is " + totalDistance);
        Debug.Log("Fifth distance value is " + distances[4] + " and overall distance est is " + totalDistance);
    }

当追车及其旧航路点路径已提供给样条时,这是样条步行器的更新功能:

Vector3 position;
        if (chasingCar && path)
        {
            float distFromCar = Vector3.Distance(transform.position, chasingCar.transform.position);
            Debug.Log("Distance from car " + distFromCar);
            if(distFromCar < 35)
            {
                //get current spline waypoint
                //int splineIdx = GetSplineIndex(progress);
                int splineIdx = chasingCar.GetComponent<CarEngine>().GetCurrentNodeTarget();
                //declare next spline waypoint
                int splineIdxNext = splineIdx + 1;
                if (path && splineIdxNext == (nodes.Length))
                    splineIdxNext = 0;
                Debug.Log("Current splineIdx " + splineIdx);
                //float currCarDistance = Vector3.Distance(chasingCar.transform.position, nodes[splineIdx].position);
                float currCarDistance = SumSplineProgress(splineIdx);
                float overallDistance = Vector3.Distance(nodes[splineIdx].position, nodes[splineIdxNext].position);
                float currCarSplineProgress = currCarDistance / overallDistance;
                float overallProgress = (currCarDistance) / (totalDistance);
                progress = overallProgress;

            }
            else
            {
                progress += Time.deltaTime / duration;
            }
            Debug.Log("Chasing, current progress: " + progress);
            position = spline.GetPoint(progress);

最后,这是我过去尝试用来计算样条步行器进度的函数:

int GetSplineIndex(float progress)
{
    float curProgress = progress * (totalDistance);
    Debug.Log("Current calculated progress " + curProgress);
    return System.Convert.ToInt32(Mathf.Floor(curProgress));
}

float SumSplineProgress(int index)
{
    float currTotalDistance = 0f;
    for(int i = index; i > -1; i--)
    {
        currTotalDistance += distances[i];
    }
    return currTotalDistance;
}

我可能只是让自己变得比我需要的更难,但我只想说,我真的很难过。当 AI 汽车的当前起点和终点航路点之间的距离更远时,我已经接近让样条航路点在汽车前面跳跃更多,但这仍然不是我想要实现的目标。

这里有人有什么特别的建议吗?提示,方向的轻推和代码会很棒。提前致谢!

更新

是的,我仍在在努力!在之前的样条计算代码中有一些我认为是错误的逻辑 - 例如,这个:

float currCarSplineProgress = currCarDistance / overallDistance;

我已经改成这样了:

float currCarSplineProgress = (currCarDistance) / currSplineLength;

该部分的想法是检查汽车在整个样条曲线中接近的当前曲线上的进度,并相应地定位样条曲线步行器,以便在需要时向前跳转到下一条样条曲线。这是完整的更新代码:

Vector3 position;
        if (chasingCar && path)
        {
            float distFromCar = Vector3.Distance(transform.position, chasingCar.transform.position);
            Debug.Log("Distance from car " + distFromCar);
            if(distFromCar < 50)
            {
                //get current spline waypoint
                //int splineIdx = GetSplineIndex(progress);
                int splineIdx = chasingCar.GetComponent<CarEngine>().GetCurrentNodeTarget()-1;
                //declare next spline waypoint
                int splineIdxNext = splineIdx + 1;
                if(splineIdx == -1)
                {
                    splineIdx = nodes.Length - 2;
                    splineIdxNext = 0;
                }
                if (path && splineIdxNext == (nodes.Length))
                    splineIdxNext = 0;
                Debug.Log("Current splineIdx " + splineIdx);
                //float currCarDistance = GetConvertedDistance(chasingCar.transform.position, nodes[splineIdx].position);
                float currCarDistance = Vector3.Distance(chasingCar.transform.position, nodes[splineIdx].position);
                float restDistance = Vector3.Distance(chasingCar.transform.position, nodes[splineIdxNext].position);
                //float currCarDistance = SumSplineProgress(splineIdx);
                Debug.Log("currCarDistance " + currCarDistance);
                //float currSplineLength = Vector3.Distance(nodes[splineIdx].position, nodes[splineIdxNext].position);
                float currSplineLength = currCarDistance + restDistance;
                float overallDistance = 0;
                float nextOverallDist = 0f;
                if(splineIdx != 0)
                    overallDistance = SumSplineProgress(splineIdx-1);
                Debug.Log("overallDistance " + overallDistance);
                float currCarSplineProgNext = 0f;
                if (splineIdxNext != 1 && splineIdxNext != 0)
                {
                    nextOverallDist = SumSplineProgress(splineIdxNext - 1);
                    currCarSplineProgNext = (currCarDistance) / nextOverallDist;
                }
                Debug.Log("currSplineLength " + currSplineLength);
                float currCarSplineProgress = (currCarDistance) / currSplineLength;
                float leading = 10f;
                if (distFromCar < 20)
                    leading += 15f;
                float overallProgress;
                Debug.Log("currCarSplineProgress " + currCarSplineProgress);
                if (currCarSplineProgress < .7f)
                {
                    overallProgress = (currSplineLength + (currCarDistance * .3f)) / (totalDistance);
                }
                else
                {
                    Debug.Log("Jumping to next waypoint...");
                    overallProgress = (nextOverallDist + (currCarDistance * .3f)) / (totalDistance);
                }
                Debug.Log("Overall progress " + overallProgress);
                //if (overallProgress >= 1f)
                //    overallProgress = 0f;
                progress = overallProgress;

            }
            else
            {
                progress += Time.deltaTime / duration;
            }
            Debug.Log("Chasing, current progress: " + progress);
            position = spline.GetPoint(progress);
        }
        else
        {
            position = spline.GetPoint(progress);
        }
        transform.localPosition = position;

然而,当汽车取得足够的进展时,意外的事情仍然会发生 - 花键步行器会突然跳到前面的部分!

有什么见解吗?

【问题讨论】:

    标签: unity3d artificial-intelligence racing


    【解决方案1】:

    你有正确的想法让 AI 追逐一个沿样条线移动的目标。我相信这就是赛车游戏中大多数 AI 的工作方式。

    为确保目标始终领先于 AI,请将目标的位置设置为 AI 在样条线上的位置加上与 AI 移动速度相关的某个值。

    我建议查看 Unity 标准资产包:

    https://assetstore.unity.com/packages/essentials/asset-packs/standard-assets-for-unity-2017-3-32351

    其中有一个汽车 AI 系统,它通过跟踪沿样条线移动的目标来工作。

    【讨论】:

    • 您好,谢谢您的回复。我知道航点 AI 会工作,因为它会跟随目标。我想诀窍在于,由于我当前尝试计算/平移样条助行器位置的方式,样条助行器可能会落后于人工智能汽车或处于同一位置。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多