You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 07:45:01