我一直在努力开发一款能胜任(但还算不错)的赛车AI的游戏,但我遇到了一些要克服的限制。条件如下:
1。)AI逻辑和播放器控件都共享相同的汽车控制器来驾驶和转弯,依此类推。根据汽车试图转弯的距离,AI车辆简单地传递一个固定的(-1到1)值。油门已接合。 AI和播放器都共享布尔值来刹车,并使用SHIFT键漂移漂移
2。)AI需要做出明智的明智决定,让玩家做出正确的转弯,何时滑行等操作。
我最初使用普通的航路点增量系统,以使AI继续根据航路点在轨道上重叠。有了合适的车轮摩擦曲线值(我很幸运在网上找到了),这实际上可以正常工作。但是,尽管我尤其在车轮摩擦值上作了更多努力,并且仍然希望为AI拥有更平滑的轨迹跟随和转向逻辑,但我还是建议使用三次贝塞尔曲线样条曲线。我发现Catlike Coding教程非常有趣(我相信很多人都知道这一点,但是下面是有兴趣的人的链接):
https://catlikecoding.com/unity/tutorials/curves-and-splines/
然后我想到了从本教程中将Spline Walker用作AI的唯一途径,并有效地“逗弄”汽车以跟随spline walker,如以下视频所示:
https://www.youtube.com/watch?v=UcA4K2rmX-U#action=share
但是,这是我的大问题-如果我想让我的汽车跟随花键助步器,同时始终将花键助步器保持在前面,则必须确保花键助步器遵循的“进度”相对于接下来的汽车,花键助行器保持在前面,因此汽车不会决定减速和停车。
我一直在寻找做到这一点的例子,但我不能说我做得太成功了。
这是我当前计算代码片段的进度-我正尝试通过碰巧共享相同变换坐标的旧路点对象来存储样条线上位置之间的距离:
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;
但是,当汽车前进得足够快时,仍然会发生意想不到的事情-花键助步器会突然跳到前面的部分之一!
有什么见解吗?