Action disabled: source

임의 게임플레이 항목(Random Gameplay Elements)의 추가

임의로 선택된 아이템이나 값은 많은 게임에서 중요한 요소입니다. 이 섹션은 Unity의 내장 랜덤 함수를 사용하여 몇몇 공통적인 게임 메커니즘을 구현하는 방법을 보여줍니다.

배열(Array)에 대한 임의 아이템의 선택

배열의 항목를 임의적으로 선택하는 것은 0에서 배열의 최대 인덱스 값(해당 배열의 길이에서 1을 뺀 수) 사이에 한 정수를 임으로 선택하는 문제입니다.이는 내장 함수인 Random.Range을 사용하면 손쉽게 수행할 수 있습니다:-

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

주목할 것은 Random.Range가 첫 번째 매개변수(parameter)을 포함하지만 두 번째 매개변수도 제외하지 않는 범위에서 한 값을 반환하므로, 여기에 myArray.Length을 사용하면 올바른 결과를 제공한다는 것 입니다.

상이한 가능성(Different Probabilities)을 가진 아이템의 선택

때때로, 사용자는 어떤 아이템이 다른 것보다 더 선택될 가능성이 높은 경우에도 임의로 아이템을 선택해야 할 필요가 있습니다. 예를 들면, NPC는 플레이어를 만났을 때 여러 다른 방식으로 반응할 것 입니다 :-

  • 50% 가능성은 다정한 인사
  • 25% 가능성은 도망침
  • 20% 가능성은 즉각 공격
  • 5% 가능성은 선물로 돈을 제의

이러한 여러 결과를 시각적으로 나타내자면, 긴 종이 위에 각각이 차지하는 비율 만큼을 전체 길이에서 나누어 놓은 것과 같은 것을 상상 할 수 있습니다. 이 차지하는 비율은 선택되는 결과의 확률입니다. 여기서 선택을 한다는 것은 그 긴 종이 위에서 임의의 한 점을 선택하고(예를 들어 다트로) 그것이 어느 부분에 속하는 지를 보는 것과 같습니다.

스크립트에서, 이 긴 종이 줄은 실제로 각 아이템에 대한 다른 가능성을 가진 항목을 차례로 포함하는 부동수(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인 경우에도 종종 한 항목을 선택할 수 있게 해 줍니다.

리스트 섞기(Shuffling a List)

일반적인 게임 방법은 항목의 알려진 집합에서 선택하되 무작위 순서로 도착하게 하는 것 입니다. 예를 들면, 카드 한 벌은 일반적으로 예상되는 순서대로 빼지 않도록 섞입니다. 배열 내의 항목은, 각 항목을 찾아가 그 항목을 그 배열 내 무작위의 인덱스에 있는 항목과 교환하여 섞을 수 있습니다:-

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

항목집합에서의 비 중복 선택(Choosing from a Set of Items Without Repetition)

공통적인 작업은 한 집합에서 여러 항목을 임의적으로 선택하되 한 항목을 두 번 이상 선택하지 않는 것 입니다. 예를 들면, 여러 개의 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;
}

이 선택이 임의적이지만, 선택된 집합 내의 항목은 원래 배열 내 순서와 같다는 것을 주의합니다. 만일 그 항목이 차례대로 한 번에 한 개씩 사용된다면, 그 순서로 인해 일부 예측이 가능해지고, 그러므로 사용 전에 그 배열을 섞을 필요가 있을 것 입니다.

공간 내 임의 지점(Random Points in Space)

큐브

큐브 볼륨 내 임의 지점은 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;

역링크