版本:2022.3
语言:英文
Mathf
调试

随机

切换到脚本

“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;
}

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

if (randomPoint < probs[i])

…改为小于或等于测试,可以避免额外的返回语句,但也会在概率为零的情况下偶尔选择一个项。

对连续随机值进行加权

如果您有离散结果,浮点数数组方法效果很好,但在某些情况下,您可能希望产生更多连续的结果——比如说,您想随机化找到宝箱中金币的数量,并希望它可以在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窗口,显示当前选择的GameObject、资产或项目设置的信息,允许您检查和编辑值。更多信息请参见这里
参见词汇表
窗口直观地查看并编辑曲线,而无需计算值。

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

洗牌List

一个常见的游戏机制是从一组已知的项目中选择,但以随机顺序获得。例如,一副牌通常会洗牌,以确保它们不是按照可预测的顺序抽取的。您可以通过访问数组的每个元素,并将其与数组中随机索引的另一个元素交换来洗牌数组中的项目:

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。这可以通过按顺序迭代项目、为每个项目做出是否将其添加到所选集的随机决定来实现。在访问项目时,选择该项目的概率等于需要的项目数量除以剩余的项目数量。

例如,假设有十个出生点可用,但只需要选择五个。第一个项目被选择的概率将是10 / 5或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分量来缩放立方体。如果其中一个轴被设置为0,则点将始终位于一个单平面上。例如,在“地面”上随机选择一个点通常是一个设置X和Z分量随机并且设置Y分量为零的问题。

当体积是一个球体时(即,当您希望在一个原点给定的半径内选择一个随机点时),您可以使用Random.insideUnitSphere乘以所需的半径

var randWithinRadius = Random.insideUnitSphere * radius;

请注意,如果您将生成的向量中的一个分量设置为0,您将无法得到一个正确的圆形内的随机点。虽然这个点确实随机且位于正确的半径范围内,但概率会严重偏向于圆心,因此点会非常不均匀地分布。您应该使用 Random.insideUnitCircle 来完成这个任务。

var randWithinCircle = Random.insideUnitCircle * radius;

Mathf
调试