【发布时间】:2014-12-31 16:21:40
【问题描述】:
我在我的 Unity 2D 游戏中实现了 A* 寻路算法。一切正常,但在搜索大地图时可能会导致卡顿。
问题是由在主线程上执行的 While-Loop 引起的。我希望算法能够在单独的线程上运行,以在函数运行时阻止游戏发抖。
我对协程的理解是它们更适合用于顺序函数,而不是像这样的繁重计算。该函数必须返回一个值或使用引用来附加一个值。
如何在不阻塞主线程的情况下实现这种占用大量 CPU 的计算? IE。多线程?
编辑:
Heisenbug 指出的协程的当前实现。
从“繁重的计算功能”中提取的不完整,应该在多个帧中分散到均匀的工作负载。
//if the daemon is currently searching
public bool Searching;
//Create list for the algorithm
Pathfinding_Path Path = new Pathfinding_Path();
List<Pathfinding_Point> OpenList = new List<Pathfinding_Point>();
List<Pathfinding_Point> ClosedList = new List<Pathfinding_Point>();
//Agent is the object that shall pathfind, position is goal, callback
public IEnumerator Pathfind(GameObject Agent, Vector3 Position, Func<Pathfinding_Path,Vector3, bool,bool> Callback)
{
//Abort if already searching
if (Searching)
yield break;
Searching = true;
//If the target position is not clear, abort
if (!IsClear(Position))
{
Searching = false;
yield break;
}
//Get the size of the agent
Vector3 AgentSize = GetSize(Agent);
//Start the algorithm
Pathfinding_Point start = CreatePoint(AgentSize, Agent.transform.position, Position, 0);
//Get possible steps from the first position
CreateAdjacent(start, Position);
//Add the node to the search tree
OpenList.Add(start);
//Keep track of how many iterations the function has ran (to not keep on going forever)
int iterations = 0;
//If there is an object to visit and the number of iterations is allowed
while (OpenList.Count > 0 && iterations < 250)
{
iterations++;
//Get the best node and visit it
Pathfinding_Point point = GetBest(OpenList);
OpenList.Remove(point);
ClosedList.Add(point);
//Add all neighbors to the search tree
foreach (Pathfinding_Point adjacent in point.Adjacent)
{
if (!ClosedList.Contains(adjacent))
{
if (!OpenList.Contains(adjacent))
{
adjacent.Parent = point;
//The goal position is near, this is goal
if (Vector3.Distance(adjacent.Position, Position) <= AgentSize.sqrMagnitude * 0.5f)
{
//Add the final point to the path
Path.Add(adjacent);
//Get the last point
Pathfinding_Point step = Path.Points[0];
//Track backwards to find path
while(step.Parent != null){
Path.Add(step.Parent);
step = step.Parent;
}
Path.Finalize();
//Return the final path somehow (preferably using a callback method)
Callback(Path, Position, false);
Searching = false;
//Don't run the function no more
yield break;
}
else if (IsClear(adjacent))
{
//Add to search tree
CreateAdjacent(adjacent, Position);
OpenList.Add(adjacent);
}
}
else
{
//If the score is lower this way, re-calculate it
if (point.G + 1 < adjacent.G)
{
adjacent.G = point.G + 1;
adjacent.F = adjacent.G + adjacent.H;
}
}
}
}
}
//If there are no more ways to go
if(OpenList.Count == 0)
yield break;
//Here, the search has exceeded its limit on 250 iterations and shall continue after a small delay
yield return new WaitForSeconds(0.005f);
//The callback will run this function again, until the goal is reached or if there are no more nodes to visit
Callback(Path, Position, true);
}
应该处理搜索功能可能到达的不同情况的回调
//Path to use if it succeded, position that was the initial target, if the search is not yet finished and should be continued
bool GetPath(Pathfinding_Path Path, Vector3 pz, bool Continue)
{
//Run the function again with the same parameters as the first time
if (Continue)
{
StartCoroutine(Pathfinder.Pathfind(gameObject, pz, GetPath));
}
else if (Path.Points.Count > 0)
{
//A path has been found
InvestigatePath = Path;
}
return true;
}
【问题讨论】:
-
如果您不发布代码,我们应该如何提供帮助?它从来没有像“把你所有的代码放在一个协程中,完成”那么简单。
-
@LearnCocos2D 抱歉不够清楚。这个问题没有涉及真正的代码。我想知道如何在统一、异步函数或任何你喜欢的方式中进行多线程处理。我可以给你代码,但它只会很混乱,因为它不会给问题增加任何内容。
-
您的 A* 例程是否非常依赖 Unity 对象?我悲观地猜测 Unity 的方法/对象不是线程安全的,所以如果你可以将它的变量/逻辑与 Unity 的主线程分开,这基本上变成了一个非常简单的 C# 问题(并且 C# 有许多有用的多线程工具)
-
@Katana314 没有线程安全是正确的。我确实使用 Unity Physics 函数,我猜这些函数属于“统一对象”类别。
标签: c# unity3d path-finding coroutine