首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Unity3D BezierCurve -样条沃克跟随AI?

Unity3D BezierCurve -样条沃克跟随AI?
EN

Stack Overflow用户
提问于 2019-11-14 02:20:06
回答 1查看 943关注 0票数 2

我一直在努力创造一个有能力(但公平)赛车AI的游戏,我有几个限制,我正在努力满足。以下是顺序的条件:

1.)AI逻辑和玩家控制都共享相同的汽车控制器来驾驶和转弯等。AI车辆只是通过一个夹紧(-1比1)的数值取决于汽车试图转弯和油门是接合多远。AI和玩家共享布尔值来刹车,并使用SHIFT键进行漂移旋转。

2.)AI需要做出明智、明智的决定,让玩家在正确的转身量、何时滑行等方面做出正确的决定。

我最初使用的是一个简单的路径点增量系统,根据路径点的不同,让AI继续绕着跑道运行。使用正确的车轮摩擦曲线值(我碰巧在网上幸运地找到了这个值),这实际上是可行的。然而,当我更努力的车轮摩擦值,特别是,仍然希望有一个更平滑的路径跟踪和转向逻辑的AI,它建议我使用三次Bezier样条。我发现猫式编码教程很吸引人(我相信你们中的很多人都知道这一点,但是下面的链接是供感兴趣的人参考的):

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

然后,我从本教程中获得了使用样条沃克作为人工智能的一个方法点的想法,并有效地“戏弄”了汽车跟随样条步行器,就像这个视频:

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

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

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

下面是我当前计算代码片段的进展--我正在尝试通过旧的waypoint对象存储样条上位置之间的距离,这些对象恰好具有相同的转换坐标:

代码语言:javascript
复制
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);
    }

这是在样条步行器的更新函数中,当向样条提供了追逐车和它的旧路径时:

代码语言:javascript
复制
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);

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

代码语言:javascript
复制
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赛车的当前起点和终点之间有更多的距离时,我更接近于让样条路径点跳到赛车的前面,但这仍然不是我想要实现的。

有人有什么特别的建议吗?提示,在方向上的轻推,和代码将是非常棒的。提前感谢!

更新

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

代码语言:javascript
复制
float currCarSplineProgress = currCarDistance / overallDistance;

我已经改变了:

代码语言:javascript
复制
float currCarSplineProgress = (currCarDistance) / currSplineLength;

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

代码语言:javascript
复制
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;

然而,当赛车取得足够的进步时,意外的事情仍然会发生--样条步行者会突然跳到前面的一个部分!

有什么见解吗?

EN

回答 1

Stack Overflow用户

发布于 2019-12-08 17:56:22

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

为了确保目标总是在AI之前,将目标的位置设置为AI在样条上的位置,增加一些与AI移动速度有关的值。

我建议查看统一标准资产包:

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

在那里有一个汽车人工智能系统,通过跟踪一个沿着样条移动的目标来工作。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58848436

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档