版本:Unity 6 (6000.0)
语言:English
使用常见的数学函数
Gizmos 和 Handles

使用随机数

切换到脚本编写

Random 类提供了一种简单的方法来生成各种常见的随机值类型。

此页面概述了 Random 类及其在脚本编写中的常见用法。有关 Random 类每个成员的详尽参考以及更多技术细节,请参阅Random 脚本参考

请按照以下链接了解更多详细信息和这些有用方法的示例。

简单的随机数

Random.value 为您提供一个介于 0.0 和 1.0 之间的随机浮点数。一种常见的用法是将其转换为介于零和您选择的范围内的数字,方法是将结果相乘。

Random.Range 为您提供一个介于您提供的最小值和最大值之间的随机数字。它返回整数或浮点数,具体取决于提供的最小值和最大值是整数还是浮点数。

圆形或球体内随机点

Random.insideUnitCircle 返回半径为 1 的圆形内的随机(同样,您可以将结果相乘以获得任意大小圆形内的随机点)。

Random.insideUnitSphere 返回半径为 1 的球体内随机

Random.onUnitSphere 返回半径为 1 的球体表面上的随机

其他类型的随机值

Unity 的随机数类还提供了一些其他类型的随机值。

要生成随机旋转,请使用Random.rotation

要生成随机颜色,请使用Random.ColorHSV

从数组中选择随机项

随机选择数组元素归结为在零到数组的最大索引值(等于数组长度减一)之间选择一个随机整数。这可以通过内置的 Random.Range 函数轻松完成

var element = myArray[Random.Range(0, myArray.Length)];

请注意,Random.Range 返回一个范围内的值,该范围包含第一个参数但不包含第二个参数,因此在此处使用 myArray.Length 会给出正确的结果。

选择具有不同概率的项

有时,您需要随机选择项目,但某些项目比其他项目更有可能被选中。例如,NPC 在遇到玩家时可能会以几种不同的方式做出反应:-

  • 50% 的概率发出友好的问候
  • 25% 的概率逃跑
  • 20% 的概率立即发起攻击
  • 5% 的概率赠送金钱作为礼物

您可以将这些不同的结果可视化为一条纸条,将其分成若干部分,每个部分占据纸条总长度的一部分。所占的分数等于选择该结果的概率。做出选择相当于沿着纸条的长度随机选择一个点(例如,通过投掷飞镖),然后查看它位于哪个部分。

在脚本中,纸条实际上是一个浮点数数组,这些浮点数按顺序包含项目的不同概率。随机点是通过将 Random.value 乘以数组中所有浮点数的总和获得的(它们不需要加起来等于 1;重要的是不同值的相对大小)。要查找点位于哪个数组元素“中”,首先检查它是否小于第一个元素中的值。如果是,则第一个元素是被选中的元素。否则,从点值中减去第一个元素的值,并将其与第二个元素进行比较,依此类推,直到找到正确的元素。在代码中,这将类似于以下内容:-

float Choose (float[] probs) {

    float total = 0;

    foreach (float elem in probs) {
        total += elem;
    }

    float randomPoint = Random.value * total;

    for (int i= 0; i < probs.Length; i++) {
        if (randomPoint < probs[i]) {
            return i;
        }
        else {
            randomPoint -= probs[i];
        }
    }
    return probs.Length - 1;
}

请注意,最后的 return 语句是必要的,因为 Random.value 可以返回 1 的结果。在这种情况下,搜索将找不到任何地方的随机点。将代码行

if (randomPoint < probs[i])

…更改为小于或等于测试将避免额外的 return 语句,但也将允许偶尔选择一个项目,即使它的概率为零。

加权连续随机值

如果您的结果是离散的,则浮点数数组方法效果很好,但也有这样的情况:您希望生成更连续的结果——例如,您想随机化宝箱中发现的金币数量,并且您希望能够得到 1 到 100 之间的任何数字,但要使较低的数字更有可能。使用浮点数数组方法执行此操作需要设置一个包含 100 个浮点数的数组(即纸条上的部分),这很笨拙;如果您不受限于整数,而是想要范围内的任何数字,则无法使用这种方法。

对于连续结果,更好的方法是使用 AnimationCurve 将“原始”随机值转换为“加权”值;通过绘制不同的曲线形状,您可以生成不同的权重。代码也更易于编写

float CurveWeightedRandom(AnimationCurve curve) {
    return curve.Evaluate(Random.value);
}

通过读取 Random.value 选择一个介于 0 和 1 之间的“原始”随机值。然后将其传递给 curve.Evaluate(),后者将其视为水平坐标,并返回该水平位置处曲线的相应垂直坐标。曲线的浅部分更有可能被选中,而陡峭的部分更有可能不被选中。

A linear curve does not weight values at all; the horizontal coordinate is equal to the vertical coordinate for each point on the curve.
线性曲线根本不会对值进行加权;对于曲线上的每个点,水平坐标都等于垂直坐标。
This curve is shallower at the beginning, and then steeper at the end, so it has a greater chance of low values and a reduced chance of high values. You can see that the height of the curve on the line where x=0.5 is at about 0.25, which means theres a 50% chance of getting a value between 0 and 0.25.
此曲线在开始时较浅,然后在末尾较陡,因此它获得较低值的概率更大,而获得较高值的概率较小。您可以看到,在 x=0.5 的线上,曲线的的高度约为 0.25,这意味着有 50% 的概率获得介于 0 和 0.25 之间的值。
This curve is shallow at both the beginning and the end, making values close to the extremes more common, and steep in the middle which will make those values rare. Notice also that with this curve, the height values have been shifted up: the bottom of the curve is at 1, and the top of the curve is at 10, which means the values produced by the curve will be in the 1-10 range, instead of 0-1 like the previous curves.
此曲线在开头和结尾都较浅,使接近极值的值更常见,而在中间则较陡,这将使这些值变得稀有。还要注意,使用此曲线时,高度值已向上移动:曲线的底部位于 1,曲线的顶部位于 10,这意味着曲线产生的值将在 1-10 范围内,而不是像之前的曲线那样在 0-1 范围内。

请注意,这些曲线不是您可能在概率论指南中看到的概率分布曲线,而是更像是逆累积概率曲线。

通过在您的某个脚本一段代码,允许您创建自己的组件、触发游戏事件、随时间推移修改组件属性并以您喜欢的任何方式响应用户输入。 更多信息
参见 词汇表
上定义一个公共 AnimationCurve 变量,您将能够通过检查器一个 Unity 窗口,显示有关当前选定的游戏对象、资产或项目设置的信息,允许您检查和编辑值。 更多信息
参见 词汇表
窗口以可视化的方式查看和编辑曲线,而无需计算值。

此技术生成浮点数。如果您想计算整数结果——例如,您想要 82 个金币,而不是 82.1214 个金币——您可以将计算出的值传递给 Mathf.RoundToInt() 等函数。

洗牌列表

一种常见的游戏机制是从已知的一组项目中进行选择,但要使它们以随机顺序出现。例如,一副纸牌通常会被洗牌,以便它们不会以可预测的顺序被抽取。您可以通过访问每个元素并将其与数组中随机索引处的另一个元素交换来洗牌数组中的项目:-

void Shuffle (int[] deck) {
    for (int i = 0; i < deck.Length; i++) {
        int temp = deck[i];
        int randomIndex = Random.Range(i, deck.Length);
        deck[i] = deck[randomIndex];
        deck[randomIndex] = temp;
    }
}

从一组项目中选择而不重复

一项常见的任务是从一组项目中随机选择多个项目,但不要选择相同的项目多次。例如,您可能希望在随机的生成点生成多个 NPC,但要确保每个点只生成一个 NPC。这可以通过按顺序迭代项目来完成,为每个项目做出一个随机决定,即是否将其添加到选定的集中。当访问每个项目时,它被选中的概率等于仍然需要的项目数量除以剩余可选择项目的数量。

例如,假设有十个生成点可用,但只需要选择五个。第一个项目被选中的概率将是 5/10 或 0.5。如果它被选中,则第二个项目的概率将是 4/9 或 0.44(即,仍然需要四个项目,九个项目可供选择)。但是,如果第一个项目未被选中,则第二个项目的概率将是 5/9 或 0.56(即,仍然需要五个项目,九个项目可供选择)。这将持续到集合包含所需的五个项目为止。您可以在代码中按如下方式完成此操作:-

Transform[] spawnPoints;

Transform[] ChooseSet (int numRequired) {
    Transform[] result = new Transform[numRequired];

    int numToChoose = numRequired;

    for (int numLeft = spawnPoints.Length; numLeft > 0; numLeft--) {

        float prob = (float)numToChoose/(float)numLeft;

        if (Random.value <= prob) {
            numToChoose--;
            result[numToChoose] = spawnPoints[numLeft - 1];

            if (numToChoose == 0) {
                break;
            }
        }
    }
    return result;
}

请注意,尽管选择是随机的,但选定集中的项目将与它们在原始数组中的顺序相同。如果项目要按顺序逐个使用,则排序可能会使它们部分可预测,因此可能需要在使用前对数组进行洗牌。

空间中的随机点

可以通过将 Vector3 的每个分量设置为 Random.value 返回的值来选择立方体体积中的随机点

var randVec = Vector3(Random.value, Random.value, Random.value);

这会在边长为一个单位的立方体内部生成一个点。可以通过将向量的 X、Y 和 Z 分量乘以所需的边长来简单地缩放立方体。如果其中一个轴设置为零,则该点将始终位于单个平面内。例如,在“地面”上选择一个随机点通常是随机设置 X 和 Z 分量并将 Y 分量设置为零的问题。

当体积是球体时(即,当您想要从原点到给定半径内的随机点时),您可以使用乘以所需半径的 Random.insideUnitSphere

var randWithinRadius = Random.insideUnitSphere * radius;

请注意,如果您将结果向量的其中一个分量设置为零,则不会在圆形内获得正确的随机点。尽管该点确实是随机的并且位于正确的半径内,但概率严重偏向圆的中心,因此点将分布非常不均匀。为此任务,您应该改用 Random.insideUnitCircle:-

var randWithinCircle = Random.insideUnitCircle * radius;

使用常见的数学函数
Gizmos 和 Handles