Version: 6000.3
语言: 中文
使用常用数学函数
编译和代码重新加载

使用随机性

切换到脚本

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.

从数组中选择随机项目

随机选择数组元素归结为选择一个介于 0 和数组的最大索引值(等于数组长度减去 1)之间的随机整数。这可以使用内置的Random.Range功能:

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

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

选择不同概率的项目

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

  • 50% 的几率进行友好的问候
  • 25%的几率逃跑
  • 20% 几率立即攻击
  • 5% 的几率提供金钱作为礼物

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

表示 0% 到 100% 概率空间的条带被分成四个段,分别代表条带长度的 50%、25%、20% 和 5%。飞镖嵌入沿条带的 82% 点,在 20% 段内。
表示 0% 到 100% 概率空间的条带被分成四个段,分别代表条带长度的 50%、25%、20% 和 5%。飞镖嵌入沿条带的 82% 点,在 20% 段内。

在脚本中,纸条实际上是一个浮点数组,其中包含按顺序排列的项目的不同概率。随机点是通过乘法得到的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;
}

请注意,final return 语句是必要的,因为Random.value可以返回结果 1。在这种情况下,搜索不会在任何地方找到随机点。更改线路:

if (randomPoint < probs[i])

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

对连续随机值进行加权

如果您有离散结果,浮点数组方法效果很好,但在某些情况下,您希望产生更连续的结果 - 例如,您想要随机化在宝箱中找到的金块数量,并且您希望最终可以得到 1 到 100 之间的任何数字, 但是为了让更低的数字更有可能。使用浮点数组方法执行此作需要设置一个包含 100 个浮点数(即纸条上的部分)的数组,这很笨拙;如果您不局限于整数,而是想要范围内的任何数字,则不可能使用这种方法。

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

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

通过读取 0 和 1 来选择介于 0 和 1 之间的“原始”随机值Random.value.然后将其传递给curve.Evaluate(),将其视为水平坐标,并返回该水平位置的曲线的相应垂直坐标。曲线的浅部分被采摘的机会更大,而较陡的部分被采摘的机会较低。

线性曲线根本不对值进行加权;水平坐标等于曲线上每个点的垂直坐标。
线性曲线根本不对值进行加权;水平坐标等于曲线上每个点的垂直坐标。
这条曲线在开始时较浅,然后在结束时较陡,因此它有更大的低值机会和高值的几率。您可以看到 x=0.5 的线上曲线的高度约为 0.25,这意味着有 50% 的机会获得介于 0 和 0.25 之间的值。
这条曲线在开始时较浅,然后在结束时较陡,因此它有更大的低值机会和高值的几率。您可以看到 x=0.5 的线上的曲线高度约为 0.25,这意味着有 50% 的机会获得介于 0 和 0.25 之间的值。
这条曲线在开始和结束处都很浅,这使得接近极端值的值更常见,而中间的曲线陡峭,这将使这些值变得罕见。另请注意,对于这条曲线,高度值已向上移动:曲线的底部为 1,曲线的顶部为 10,这意味着曲线生成的值将在 1-10 范围内,而不是像前面的曲线那样为 0-1。
这条曲线在开始和结束处都很浅,这使得接近极端值的值更常见,而中间的曲线陡峭,这将使这些值变得罕见。另请注意,对于这条曲线,高度值已向上移动:曲线的底部为 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;
使用常用数学函数
编译和代码重新加载