如何在GameObject数组中找到离指定对象最近的两个GameObject(排除自身)
问题描述
我正在开发一款游戏,需要从同一个GameObject列表中找到离某一指定GameObject最近的2个GameObject,要求返回结果不超过2个,且不能返回被检测的GameObject本身。
输入输出
- 期望输入:
GameObject[] objects, GameObject currentObject
- 期望输出:
GameObject[] closestObjects, GameObject currentObject
尝试的代码
我尝试了以下代码(其中paths对应objects,pathToTest对应currentObject,bestTargets对应closestObjects):
GameObject [ ] GetClosestPaths ( GameObject [ ] paths, GameObject pathToTest ) { GameObject[] bestTargets = new GameObject[2]; float closestDistanceSqr = Mathf.Infinity; Vector3 currentPosition = pathToTest.transform.position; Transform[] pathTransforms = new Transform[paths.Length]; for ( int i = 0; i < paths.Length; i++ ) { pathTransforms [ i ] = paths [ i ].transform; } for ( int i = 0; i < pathTransforms.Length; i++ ) { if ( pathTransforms [ i ].position != currentPosition && paths [ i ] != pathToTest ) { Transform potentialTarget = pathTransforms[i]; Vector3 directionToTarget = potentialTarget.position - currentPosition; float dSqrToTarget = directionToTarget.sqrMagnitude; if ( dSqrToTarget < closestDistanceSqr ) { if ( bestTargets [ 0 ] == null ) { bestTargets [ 0 ] = paths [ i ]; } closestDistanceSqr = dSqrToTarget; if ( paths [ i ].transform.position != bestTargets [ 0 ].transform.position ) { bestTargets [ 0 ] = paths [ i ]; } else { bestTargets [ 1 ] = paths [ i ]; } } } } return bestTargets; }
这段代码来自Stackoverflow,但完全无法正常工作,项目因此面临搁置,希望得到帮助。
解决方案
问题分析
原代码的核心问题在于逻辑混乱:
- 仅维护一个
closestDistanceSqr变量,无法同时追踪第一近和第二近的距离 - 替换目标的逻辑错误,会覆盖已找到的最近目标,且无法正确填充第二近的对象
- 用
position != currentPosition判断是否为自身不可靠,不同对象可能位置相同,应直接用对象引用比较paths[i] != pathToTest
修正后的代码
以下是逻辑清晰、满足需求的实现:
GameObject[] GetClosestObjects(GameObject[] objects, GameObject currentObject) { // 存储候选对象与对应平方距离(避免开方,提升性能) List<(GameObject obj, float distanceSqr)> candidates = new List<(GameObject, float)>(); Vector3 currentPos = currentObject.transform.position; foreach (GameObject obj in objects) { // 直接排除自身 if (obj == currentObject) continue; float distanceSqr = (obj.transform.position - currentPos).sqrMagnitude; candidates.Add((obj, distanceSqr)); } // 按距离升序排序,取前2个 var sortedCandidates = candidates.OrderBy(c => c.distanceSqr).Take(2).ToList(); // 生成结果数组,不足2个时剩余位置为null GameObject[] result = new GameObject[2]; for (int i = 0; i < sortedCandidates.Count; i++) { result[i] = sortedCandidates[i].obj; } return result; }
代码说明
- 用
List存储有效候选对象及其平方距离,避免频繁数组操作 - 以对象引用
obj == currentObject排除自身,比位置判断更可靠 - 借助Linq的
OrderBy和Take快速筛选前2近对象,逻辑直观 - 结果数组不足2个时,剩余位置保留为
null,符合“返回结果不超过2个”的要求
性能优化版本
如果对象列表规模很大,Linq排序效率有限,可以手动维护前2近的对象,仅遍历一次列表:
GameObject[] GetClosestObjectsOptimized(GameObject[] objects, GameObject currentObject) { GameObject closest1 = null; GameObject closest2 = null; float distSqr1 = float.MaxValue; float distSqr2 = float.MaxValue; Vector3 currentPos = currentObject.transform.position; foreach (GameObject obj in objects) { if (obj == currentObject) continue; float distSqr = (obj.transform.position - currentPos).sqrMagnitude; // 更新前两名对象 if (distSqr < distSqr1) { closest2 = closest1; distSqr2 = distSqr1; closest1 = obj; distSqr1 = distSqr; } else if (distSqr < distSqr2) { closest2 = obj; distSqr2 = distSqr; } } return new GameObject[] { closest1, closest2 }; }
该方法时间复杂度为O(n),适合处理大量对象的场景。
内容的提问来源于stack exchange,提问作者Tauras129
相关产品推荐
相关产品推荐

