Unity库函数GetUniqueInt生成唯一整数数组时崩溃求助
问题原因与解决方案
咱们先拆解导致Unity卡死甚至内存溢出的核心问题,再给出落地的修复方案:
一、核心崩溃原因
结合你提供的代码片段和调用场景GetUniqueInt(5,5)来看,无限循环是导致卡死和内存溢出的罪魁祸首,大概率是以下两种情况之一:
1. 拼写错误引发的逻辑异常
你的代码片段里写了int[] temp = new int[intLengt...——这里明显少了字母h,正确应该是intLength。如果这个拼写错误没修正,要么编译报错,要么运行时会因为数组长度异常,导致重复检查逻辑完全失效,直接陷入无限循环。
2. 逻辑缺陷:无法终止的循环
如果GetUniqueInt的设计逻辑是「从0到intLength-1的范围内,生成intCount个不重复整数」,那会出现两种致命问题:
- 当
intCount > intLength时,根本不可能凑出足够多的唯一值,循环会永远跑下去,持续占用CPU和内存直到溢出; - 哪怕是
(5,5)这种合法参数,如果随机数范围写错(比如写成Random.Range(0, intLength+1)),也可能出现某个值永远无法被选中,导致循环无法终止。
二、修复方案
推荐两种高效且安全的实现方式,彻底避免无限循环问题:
方案1:洗牌法(适合intCount接近intLength的场景)
先创建包含所有可能值的数组,用Fisher-Yates算法打乱顺序,再取前intCount个值,完全跳过重复检查环节,效率拉满:
using UnityEngine; namespace MajorSolution { public static class MajorMath { public static int[] GetUniqueInt(int intCount, int intLength) { // 先做参数校验,从根源避免无效调用 if (intCount <= 0 || intLength <= 0 || intCount > intLength) { Debug.LogError($"无效参数:intCount({intCount})不能大于intLength({intLength}),且两者必须大于0"); return new int[0]; } // 生成包含0到intLength-1的完整数组 int[] allValues = new int[intLength]; for (int i = 0; i < intLength; i++) { allValues[i] = i; } // Fisher-Yates洗牌算法打乱数组 for (int i = intLength - 1; i > 0; i--) { int randomIndex = Random.Range(0, i + 1); // 交换元素 (allValues[i], allValues[randomIndex]) = (allValues[randomIndex], allValues[i]); } // 截取前intCount个元素作为结果 int[] returnValue = new int[intCount]; System.Array.Copy(allValues, returnValue, intCount); return returnValue; } } }
方案2:HashSet检查法(适合intCount远小于intLength的场景)
用HashSet快速判断值是否重复,同时增加循环次数上限,彻底杜绝无限循环:
using UnityEngine; using System.Collections.Generic; namespace MajorSolution { public static class MajorMath { public static int[] GetUniqueInt(int intCount, int intLength) { // 参数校验必不可少 if (intCount <= 0 || intLength <= 0 || intCount > intLength) { Debug.LogError($"无效参数:intCount({intCount})不能大于intLength({intLength}),且两者必须大于0"); return new int[0]; } HashSet<int> usedValues = new HashSet<int>(); int[] returnValue = new int[intCount]; int index = 0; // 设置最大尝试次数,防止极端情况陷入循环 int maxAttempts = intCount * 10; int attempts = 0; while (index < intCount && attempts < maxAttempts) { int randomValue = Random.Range(0, intLength); // HashSet.Add()会自动判断是否重复,重复返回false if (usedValues.Add(randomValue)) { returnValue[index] = randomValue; index++; } attempts++; } // 如果尝试次数耗尽仍未凑够,抛出错误提示 if (index < intCount) { Debug.LogError($"无法生成足够的唯一整数,尝试次数已达上限"); return new int[0]; } return returnValue; } } }
三、关键注意事项
- 必须加参数校验:在函数开头就拦截非法参数,从根源避免无效调用;
- 注意随机数范围:Unity的
Random.Range(min, max)是左闭右开的,要生成0到intLength-1的数,必须写Random.Range(0, intLength); - 优先选洗牌法:当intCount接近intLength时,洗牌法的效率远高于重复检查法,不会出现循环次数过多的问题。
内容的提问来源于stack exchange,提问作者Shane Powell
相关产品推荐
相关产品推荐

