임의로 선택된 아이템이나 값은 많은 게임에서 중요한 요소입니다. 이 섹션은 Unity의 내장 랜덤 함수를 사용하여 몇몇 공통적인 게임 메커니즘을 구현하는 방법을 보여줍니다.
배열의 항목를 임의적으로 선택하는 것은 0에서 배열의 최대 인덱스 값(해당 배열의 길이에서 1을 뺀 수) 사이에 한 정수를 임으로 선택하는 문제입니다.이는 내장 함수인 Random.Range을 사용하면 손쉽게 수행할 수 있습니다:-
var element = myArray[Random.Range(0, myArray.Length)];
주목할 것은 Random.Range가 첫 번째 매개변수(parameter)을 포함하지만 두 번째 매개변수도 제외하지 않는 범위에서 한 값을 반환하므로, 여기에 myArray.Length을 사용하면 올바른 결과를 제공한다는 것 입니다.
때때로, 사용자는 어떤 아이템이 다른 것보다 더 선택될 가능성이 높은 경우에도 임의로 아이템을 선택해야 할 필요가 있습니다. 예를 들면, NPC는 플레이어를 만났을 때 여러 다른 방식으로 반응할 것 입니다 :-
이러한 여러 결과를 시각적으로 나타내자면, 긴 종이 위에 각각이 차지하는 비율 만큼을 전체 길이에서 나누어 놓은 것과 같은 것을 상상 할 수 있습니다. 이 차지하는 비율은 선택되는 결과의 확률입니다. 여기서 선택을 한다는 것은 그 긴 종이 위에서 임의의 한 점을 선택하고(예를 들어 다트로) 그것이 어느 부분에 속하는 지를 보는 것과 같습니다.
스크립트에서, 이 긴 종이 줄은 실제로 각 아이템에 대한 다른 가능성을 가진 항목을 차례로 포함하는 부동수(float)의 배열입니다. 그 임의 점은 Random.value을 배열 안에 있는 모든 부동수(floats)와 곱하여 얻어집니다. 1까지 합할 필요는 없으며, 중요한 것은 다른 값들의 상대적인 크기입니다). 선택된 점이 배열의 어느 항목 속에 있는지 확인하려면, 이것은 첫 번째 항목의 값보다 작은지 우선 확인합니다. 만일 그렇다면, 첫 번째 항목이 선택된 항목입니다. 그렇지 않으면, 첫, 번째 항목의 값을 포인트 값에서 빼고 두 번째 항목을 비교하고, 이러한 과정을 올바른 항목을 찾을 때까지 반복합니다. 코드에서는, 이 작업이 다음과 같이 구현될 것 입니다:-
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; }
주목할 것은, 최종 반환 statement는 Random.value가 결과값으로 1을 반환할 수 있기 때문에 필요하다는 것입니다. 이 경우, 그 검색은 어디에서도 임의 포인트를 찾지 못할 것 입니다.
if (randomPoint < probs[i])
… 이하(less-than-or-equal) 테스트는 추가적은 return statement을 피할 수 있게 해 주지만, 그 가능성이 0인 경우에도 종종 한 항목을 선택할 수 있게 해 줍니다.
일반적인 게임 방법은 항목의 알려진 집합에서 선택하되 무작위 순서로 도착하게 하는 것 입니다. 예를 들면, 카드 한 벌은 일반적으로 예상되는 순서대로 빼지 않도록 섞입니다. 배열 내의 항목은, 각 항목을 찾아가 그 항목을 그 배열 내 무작위의 인덱스에 있는 항목과 교환하여 섞을 수 있습니다:-
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; } }
공통적인 작업은 한 집합에서 여러 항목을 임의적으로 선택하되 한 항목을 두 번 이상 선택하지 않는 것 입니다. 예를 들면, 여러 개의 NPC을 임의적인 증식 지점에 생성하기를 원할 수 있지만 각 점에서 오직 하나의 NPC만 생성할 수 있도록 해야 할 경우입니다. 이렇게 하려면 해당 항목들을 차례대로 반복하여, 각 반복 시에 그것이 선택한 집합에 추가되는지 아닌지에 대한 임의적 결정을 합니다. 각 항목의 방문 시, 그것이 선택 될 확률은 필요한 항목의 수를 아직 선택할 수 있는 항목의 수로 나눈 것과 같습니다.
예를 들어, 열 개의 증식 지점을 사용할 수 있지만 5개만 선택되어야 한다고 가정하면, 첫 번째 항목이 선택될 확률은 5/10 혹은 0.5입니다. 만일 이것이 선택되면, 두 번째 항목의 확률은 4/9 혹은 0.44입니다 (예: 4 항목이 필요하고, 9 개가 아직 선택할 수 있는 항목이므로). 하지만, 첫 번째 항목이 선택되지 않았다면, 두 번째 항목의 확률은 5/9 혹은 0.56 (5개가 아직 필요하고, 9개가 아직 선택할 수 있는 항목)이 됩니다. 이는 그 집합이 필요한 5개 항목을 모두 포함할 때 까지 계속됩니다. 이것을 코드에서 구현하면 다음과 같습니다:-
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; }
이 선택이 임의적이지만, 선택된 집합 내의 항목은 원래 배열 내 순서와 같다는 것을 주의합니다. 만일 그 항목이 차례대로 한 번에 한 개씩 사용된다면, 그 순서로 인해 일부 예측이 가능해지고, 그러므로 사용 전에 그 배열을 섞을 필요가 있을 것 입니다.
큐브 볼륨 내 임의 지점은 Vector3 의 각 컴포넌트를 Random.value가 반환한 값으로 설정하여 선택할 수 있습니다:-
var randVec = Vector3(Random.value, Random.value, Random.value);
이는 측면 길이가 1 단위인 큐브 내에 한 지점을 제공합니다. 그 큐브는 벡터의 X, Y, Z 컴포넌트를 원하는 측면 길이로 곱하여 측정할 수 있습니다. 만일 이 축 중 하나가 0이라면, 그 지점은 항상 하나의 면 내에 위치할 것 입니다. 예를 들어, "ground" 위에 임의의 지점을 선택하는 것은 일반적으로 X와 Z 컴포넌트를 임의로 설정하고 Y 컴포넌트를 0으로 설정하는 문제입니다.
반경 1을 갖는 구 안의 임의의 지점을 반환함. (읽기전용) 사용자는 Random.insideUnitSphere을 원하는 반경과 곱하여 사용할 수 있다.
var randWithinRadius = Random.insideUnitSphere * radius;
만일 사용자가 벡터 컴포넌트의 결과 값 중 하나를 0으로 설정한다면, 그 원 내에서 올바른 임의 점을 얻지 *못할* 것 입니다. 그 점이 비록 임의적으로 올바른 반경 내 있다 하더라고, 확률적으로 원의 가장자리 쪽으로 심하게 편향될 것이고 그 점들은 매우 불규칙적으로 퍼질 것 입니다. 이 작업에는 대신 Random.insideUnitCircle을 사용하여야 합니다:-
var randWithinCircle = Random.insideUnitCircle * radius;
//반경 0.2안의 랜덤위치 Vector2 randomPos = Random.insideUnitCircle * 0.2f;