Unity3D說明文檔翻譯-Adding Random Gameplay Elements

Adding Random Gameplay Elements

添加隨機遊戲元素

Randomly chosen items or values are important in many games. This sections shows how you can use Unity’s built-in random functions to implement some common game mechanics.

隨機選擇項和值在許多遊戲中非常重要.這部分教你如何使用Unity的內建隨機函數來實現常見遊戲功能.

Choosing a Random Item from an Array

從數組選擇一個隨機項

Picking an array element at random boils down to choosing a random integer between zero and the array’s maximum index value (which is equal to the length of the array minus one). This is easily done using the built-in Random.Range function:-

隨機挑選一個數組元素歸根到底就是隨機選擇一個在0和數組最大索引值(等於數組長度減1)之間的整數.這使用內建的隨機->值域函數很容易做到:

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

Note that Random.Range returns a value from a range that includes the first parameter but excludes the second, so using myArray.Length here gives the correct result.

注意,Random.Range函數返回一個給定值域內的值,包括第一參數但不包括第二個,所以這裏使用的myArray.Length是正確的.

Choosing Items with Different Probabilities

用不同概率選擇項

Sometimes, you need to choose items at random but with some items more likely to be chosen than others. For example, an NPC may react in several different ways when it encounters a player:-

有時,你需要隨機選擇項但某些項比其他項更能被選中.如當一個NPC碰到一個玩家時可能有幾種不同的反應方式:

· 50% chance of friendly greeting

· 25% chance of running away

· 20% chance of immediate attack

· 5% chance of offering money as a gift

· 50%機會友好招呼

· 25%機會跑開

· 20%機會立即攻擊

· 5%機會提供金錢作爲禮物

· 

You can visualise these different outcomes as a paper strip divided into sections each of which occupies a fraction of the strip’s total length. The fraction occupied is equal to the probability of that outcome being chosen. Making the choice is equivalent to picking a random point along the strip’s length (say by throwing a dart) and then seeing which section it is in.

你可以想像這些不同結果爲一張紙條分爲幾個部分,每個佔據紙條總長度的以部分.被佔據的部分相當於選定結果的概率.使選擇等於隨機沿着紙條的長度上的點(稱爲投一個鏢)然後看它在哪部分.

In the script, the paper strip is actually an array of floats that contain the different probabilities for the items in order. The random point is obtained by multiplying Random.value by the total of all the floats in the array (they need not add up to 1; the significant thing is the relative size of the different values). To find which array element the point is “in”, firstly check to see if it is less than the value in the first element. If so, then the first element is the one selected. Otherwise, subtract the first element’s value from the point value and compare that to the second element and so on until the correct element is found. In code, this would look something like the following:-

在腳本上,紙條實際上是一個浮點數組包含提供的不同概率項.隨機點通過Random.value乘以數組中所有浮點數的總和(它們不需要加1,重要的是不同值的相對大小)獲得.找到點在哪個數組元素內,首先檢查它是否小於第一個元素的值.如果是則第一個元素是一個選擇.否則,從點的值減去第一個元素的值再和第二個元素比較等等,直到找到正確的元素.在代碼中,看起來像下面這樣:

 

//JS

 

function Choose(probs: float[]) {

    var total = 0;

    

    for (elem in probs) {

        total += elem;

    }

    

    var randomPoint = Random.value * total;

    

    for (i = 0; i < probs.Length; i++) {

        if (randomPoint < probs[i])

            return i;

        else

            randomPoint -= probs[i];

    }

    

    return probs.Length - 1;

}

 

//C#

 

    float Choose (float[] probs) {

 

        float total = 0;

//將數組所有項相加

        foreach (float elem in probs) {

            total += elem;

        }

//獲取在0到數組所有項總和間的隨機值

        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;

    }

 

Note that the final return statement is necessary because Random.value can return a result of 1. In this case, the search will not find the random point anywhere. Changing the line

注意,最後一個返回語句是必須的,因爲Random.value函數可能返回1.在這種情況下,將搜索不到隨機點的位置.改變行

 if (randomPoint < probs[i])

…to a less-than-or-equal test would avoid the extra return statement but would also allow an item to be chosen occasionally even when its probability is zero.

爲小於等於測試將避免額外的返回語句但也允許一個項偶爾被選中即使當它可能是0.

Weighting continuous random values

連續加權隨機數

The array of floats method works well if you have discrete outcomes, but there are also situations where you want to produce a more continuous result - say, you want to randomize the number of gold pieces found in a treasure chest, and you want it to be possible to end up with any number between 1 and 100, but to make lower numbers more likely. Using the array-of-floats method to do this would require that you set up an array of 100 floats (i.e. sections on the paper strip) which is unwieldy; and if you aren’t limited to whole numbers but instead want any number in the range, it’s impossible to use that approach.

浮點數組方法在你有離散的結果時工作得很好,但也有一些情況下如你想要製作許多連續的結果.比如說你想隨機許多金幣在寶箱內找到,並且你想它在1到100內,但更傾向於小點的數.使用浮點數組方法需要你設置一個包含100內浮點數的數組(即紙片上分成的部分數),這是很笨拙的做法.且如果你不限制整體數量相反想要範圍內的任意數,是不可能使用這種方法的.

A better approach for continuous results is to use an AnimationCurve to transform a ‘raw’ random value into a ‘weighted’ one; by drawing different curve shapes, you can produce different weightings. The code is also simpler to write:

一個關於連續結果的更好方法是使用動畫曲線來轉換原始的隨機值爲一個加權的.通過繪製不同曲線形狀,你可以製作不同權重.代碼也更容易寫:

//JS

 

function CurveWeightedRandom(curve: AnimationCurve) {

    return curve.Evaluate(Random.value);

}

 

//C#

 

float CurveWeightedRandom(AnimationCurve curve) {

    return curve.Evaluate(Random.value);

}

A ‘raw’ random value between 0 and 1 is chosen by reading from Random.value. It is then passed to curve.Evaluate(), which treats it as a horizontal coordinate, and returns the corresponding vertical coordinate of the curve at that horizontal position. Shallow parts of the curve have a greater chance of being picked, while steeper parts have a lower chance of being picked.

通過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 there’s 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.

 

Notice that these curves are not probability distribution curves like you might find in a guide to probability theory, but are more like inverse cumulative probability curves.

注意,這些曲線不是你在概率論上看到的概率分佈曲線,但更像反累積概率曲線.

By defining a public AnimationCurve variable on one of your scripts, you will be able to see and edit the curve through the Inspector window visually, instead of needing to calculate values.

在你的腳本上定義一個公共動畫曲線變量時,你將能在檢視面板窗口上可看到和編輯此曲線,而不是需要去計算值.

This technique produces floating-point numbers. If you want to calculate an integer result - for example, you want 82 gold pieces, rather than 82.1214 gold pieces - you can just pass the calculated value to a function like Mathf.RoundToInt().

此技術產生浮點數.如果你想計算一個整數結果.如,你想82個金幣而不是82.1444個金幣,你僅需把計算值傳入一個函數像Mathf.RoundToInt().

Shuffling a List

混編列表

A common game mechanic is to choose from a known set of items but have them arrive in random order. For example, a deck of cards is typically shuffled so they are not drawn in a predictable sequence. You can shuffle the items in an array by visiting each element and swapping it with another element at a random index in the array:-

一個常見遊戲技術是從一組已知項選擇但要按隨機順序.例如,代表一副撲克牌洗牌,這樣它們便被引入了一個不可知的順序.你可以通過訪問數組內每個元素並和另一個元素通過隨機索引交換洗牌任何數組:

//JS

 

function Shuffle(deck: int[]) {

    for (i = 0; i < deck.Length; i++) {

        var temp = deck[i];

        var randomIndex = Random.Range(0, deck.Length);

        deck[i] = deck[randomIndex];

        deck[randomIndex] = temp;

    }

}

 

//C#

 

    void Shuffle (int[] deck) {

        for (int i = 0; i < deck.Length; i++) {

            int temp = deck[i];

            int randomIndex = Random.Range(0, deck.Length);

            deck[i] = deck[randomIndex];

            deck[randomIndex] = temp;

        }

    }

 

Choosing from a Set of Items Without Repetition

選定一組項目不帶重複項

A common task is to pick a number of items randomly from a set without picking the same one more than once. For example, you may want to generate a number of NPCs at random spawn points but be sure that only one NPC gets generated at each point. This can be done by iterating through the items in sequence, making a random decision for each as to whether or not it gets added to the chosen set. As each item is visited, the probability of its being chosen is equal to the number of items still needed divided by the number still left to choose from.

一個常見的任務是沒有重複的從一個組中挑選若干項.例如,你可能想生成若干NPC在隨機刷怪點但每個點只能生成一個NPC.這可通過順序迭代項做到,隨機決定每個點是否被添加到選中組.當每個項被訪問時,它被選中的概率等於仍然需要的項的數量除以可供選擇的項的數量.

As an example, suppose that ten spawn points are available but only five must be chosen. The probability of the first item being chosen will be 5 / 10 or 0.5. If it is chosen then the probability for the second item will be 4 / 9 or 0.44 (ie, four items still needed, nine left to choose from). However, if the first was not chosen then the probability for the second will be 5 / 9 or 0.56 (ie, five still needed, nine left to choose from). This continues until the set contains the five items required. You could accomplish this in code as follows:-

舉個例子,假如有10個刷怪點可用但僅選挑選5個.第一個項被挑選的概率爲5/10或0.5.如果它被選中則第二項將是4/9或0.44(即,4個依然需要,9個可供選擇).然而,如果第一個沒有被選中則第二個的概率將是5/9或0.56(即,5個依然需要,9個可供選擇).以此繼續直到組包含所需的5個項.你可以通過如下代碼實現:

 

//JS

 

 

var spawnPoints: Transform[];

 

function ChooseSet(numRequired: int) {

    var result = new Transform[numRequired];

    

    var numToChoose = numRequired;

    

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

        // Adding 0.0 is simply to cast the integers to float for the division.

        var prob = (numToChoose + 0.0) / (numLeft + 0.0);

        

        if (Random.value <= prob) {

            numToChoose--;

            result[numToChoose] = spawnPoints[numLeft - 1];

            

            if (numToChoose == 0)

                break;

        }

    }

    

    return result;

}

 

 

//C#

 

    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;

    }

Note that although the selection is random, items in the chosen set will be in the same order they had in the original array. If the items are to be used one at a time in sequence then the ordering can make them partly predictable, so it may be necessary to shuffle the array before use.

注意,儘管選擇是隨機的,選中項也是按它們在原來數組上的次序排列的.如果每次按順序使用一個項則順序也可以部分的預測,所以可能需要在使用前洗牌數組.

Random Points in Space

空間隨機點

A random point in a cubic volume can be chosen by setting each component of a Vector3 to a value returned by Random.value:-

一個隨機點在立方體內可通過設置每個每個組件一個通過Random.value返回值的三維向量來選擇:

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

This gives a point inside a cube with sides one unit long. The cube can be scaled simply by multiplying the X, Y and Z components of the vector by the desired side lengths. If one of the axes is set to zero, the point will always lie within a single plane. For example, picking a random point on the “ground” is usually a matter of setting the X and Z components randomly and setting the Y component to zero.

這裏給出一個在立方體內的點.方塊可以通過乘以X,Y,Z組件所需邊長的向量縮放.如果其中一條軸設爲0,此點將總是在一個平面上.如在地面挑選一個隨機點通常是隨機設置X和Z組件而設置Y組件爲0.

When the volume is a sphere (ie, when you want a random point within a given radius from a point of origin), you can use Random.insideUnitSphere multiplied by the desired radius:-

當容器是一個球(即當你想要一個給定半徑的隨機點時),你可以使用Random.insideUnitSphere乘以所需半徑:

 var randWithinRadius = Random.insideUnitSphere * radius;

Note that if you set one of the resulting vector’s components to zero, you will not get a correct random point within a circle. Although the point is indeed random and lies within the right radius, the probability is heavily biased toward the edge of the circle and so points will be spread very unevenly. You should use Random.insideUnitCircle for this task instead:-

注意,如果你設置一個產生向量的分量爲0,你將不會獲得一個在一個圓內的正確的隨機點.儘管此點確實是隨機的且在正確的半徑內,但概率嚴重偏向圓的邊緣,所以分佈將非常不均勻.你應該使用Random.insideUnitCircle做這個工作:

 var randWithinCircle = Random.insideUnitCircle * radius;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章