如何避免Unity的Random.Range生成重复值导致GameObject角度重叠?
问题根因
当前代码生成的旋转可选组合极少:
- 首个子节点固定使用0°绕X轴旋转
- 非首个子节点仅存在4种可选旋转:
±黄金角绕X轴、±黄金角绕Y轴
多次随机采样必然会出现重复角度,最终导致GameObject重叠。
解决方案1:增加角度随机偏移(最低改造成本)
适合对角度精度要求不高的场景,在基础角度上叠加小范围随机偏移,即可大概率避免角度重复:
// 可自定义的角度偏移范围,根据实际树枝粗细调整即可 public float angleJitterRange = 5f; public Branch CreateBranch() { GameObject newBranchGo = new GameObject("Branch"); newBranchGo.transform.position = transform.position; newBranchGo.transform.parent = transform; newBranchGo.transform.rotation = transform.rotation; var baseAngle = tree.GoldenAngle; if (tree.NumChildren == 1) { // 首个节点可加微小偏移避免后续重复,不需要可直接去掉随机部分 float angle = 0 + Random.Range(-angleJitterRange * 0.5f, angleJitterRange * 0.5f); newBranchGo.transform.Rotate(angle, 0f, 0f, Space.Self); } else { float angle = baseAngle; if (Random.Range(0f, 1f) < 0.8f) { angle = -angle; } // 叠加随机偏移,确保每次生成的角度存在差异 angle += Random.Range(-angleJitterRange, angleJitterRange); if (Random.Range(0f, 1f) < 0.5f) { newBranchGo.transform.Rotate(angle, 0f, 0f, Space.Self); } else { newBranchGo.transform.Rotate(0f, angle, 0f, Space.Self); } } Branch branch = newBranchGo.AddComponent<Branch>(); branch.BranchInit(tree, GetComponent<Bud>()); return branch; }
解决方案2:历史角度去重(100%避免重复)
适合对角度精度要求高、不允许随意偏移的场景,通过存储已使用的旋转参数,每次生成前校验去重即可:
首先在当前类中添加两个成员变量:
// 存储已使用的旋转参数:(轴索引0=X/1=Y, 角度值) private List<(int axis, float angle)> _usedRotations = new List<(int, float)>(); // 浮点数精度校验阈值,避免浮点误差导致重复判定失效 private const float AngleEpsilon = 0.1f;
修改CreateBranch方法如下:
public Branch CreateBranch() { GameObject newBranchGo = new GameObject("Branch"); newBranchGo.transform.position = transform.position; newBranchGo.transform.parent = transform; newBranchGo.transform.rotation = transform.rotation; var baseAngle = tree.GoldenAngle; int targetAxis; float finalAngle; // 循环生成直到拿到未使用的旋转参数 while (true) { if (tree.NumChildren == 1) { targetAxis = 0; finalAngle = 0f; } else { finalAngle = Random.Range(0f, 1f) < 0.8f ? -baseAngle : baseAngle; targetAxis = Random.Range(0f, 1f) < 0.5f ? 0 : 1; } // 校验是否重复 bool isDuplicate = false; foreach (var rot in _usedRotations) { if (rot.axis == targetAxis && Mathf.Abs(rot.angle - finalAngle) < AngleEpsilon) { isDuplicate = true; break; } } if (!isDuplicate) { _usedRotations.Add((targetAxis, finalAngle)); break; } } // 应用最终旋转 if (targetAxis == 0) { newBranchGo.transform.Rotate(finalAngle, 0f, 0f, Space.Self); } else { newBranchGo.transform.Rotate(0f, finalAngle, 0f, Space.Self); } Branch branch = newBranchGo.AddComponent<Branch>(); branch.BranchInit(tree, GetComponent<Bud>()); return branch; }
注意:如果后续有树枝销毁的逻辑,需要同步删除
_usedRotations中对应旋转的记录,否则会占用名额导致无法生成对应角度的新树枝。
内容的提问来源于stack exchange,提问作者capocchione
相关产品推荐
相关产品推荐

