Deff_Dev
[Unity/C#] 확률 구하기 본문
확률을 설정할 때, 모든 확률의 합은 반드시 100%가 되어야 한다.
하지만 직접 데이터 테이블을 수정하다 보면 이 조건을 지키지 못하는 경우가 생길 수 있다.
확률의 합이 100%보다 작거나 크면 안 되기 때문에, 합이 100%보다 작을 경우 부족한 수만큼 더해서 100%를 맞추고, 100%를 초과할 경우 초과된 만큼 빼주는 로직을 구현했다.
물론, 엑셀을 사용해 확률을 관리할 수도 있지만, 이번 프로젝트에서는 인스펙터를 통해 확률을 입력하기로 했기 때문에 이 기능을 추가하게 되었다.
확률을 표현하는 방법
int 자료형을 사용해 랜덤 값을 1부터 (1000, 10000 등) 사이에서 표현하는 방법
장점
- 성능: float 형변환이 필요 없기 때문에 성능이 약간 더 좋습니다.
- 구현 용이성: 구현하기가 상대적으로 쉽습니다.
단점
- 이해도: 랜덤 값을 돌리는 최대 숫자에 따라 1이 1%, 0.1%, 0.01% 등으로 변할 수 있어 처음 봤을 때 이해하기 어려울 수 있습니다.
float 자료형을 사용하여 확률을 표현하는 방법
장점
- 이해도: 확률을 직관적으로 이해할 수 있다. 예를 들어, 15.7%를 바로 입력할 수 있다.
단점
- 형 변환: float 형인 확률 값을 사용할 때, 이를 (10 * 표현하고자 하는 소수점 자릿수)로 곱한 후, int로 형변환해야 합니다. 이 후에 랜덤 값을 구하는 과정을 거쳐야 한다.
해당 프로젝트는 팀 프로젝트 이기 때문에 float 형을 사용하는 후자의 방법을 사용해봤고 소수점은 첫 번째 자리까지만 사용하는 것으로 정했다.
스크립트 작성
[Serializable]
public class StageSpawnPercent
{
public float[] spawnPercent = new float[3];
public void CalculatePercentage() // 합계가 100%가 되도록 계산해주는 함수
{
float perSum = 0f;
for (int i = 0; i < spawnPercent.Length; i++)
{
if (perSum < 100f)
{
if (perSum + spawnPercent[i] >= 100f) // 100퍼센트가 넘는다면
{
spawnPercent[i] = 100f- perSum; // 해당 퍼센트를 100퍼센트가 되도록 맞춰줌
perSum = 100f;
}
else
{
perSum += spawnPercent[i]; // 더해줌
}
}
else
{
spawnPercent[i] = 0; // 합이 100%가 넘을 떈 0으로 고정
}
}
if (perSum < 100f) // 100퍼가 안된다면 맨 마지막 확률이 나머지 퍼센트를 더해줌
{
spawnPercent[spawnPercent.Length - 1] += 100 - perSum;
spawnPercent[spawnPercent.Length - 1] = Mathf.Round(spawnPercent[spawnPercent.Length - 1] * 10) / 10;
}
}
}
위 클래스를 작성하고 Awake에서 해당 클래스의 CalculatePercentage 함수를 호출한다.
using UnityEngine;
namespace RandomEvent
{
public class RandomEventResult
{
public int GetArrRandomResult(float[] percent) // 퍼센트 배열이 존재할 때 호출
{
float random = GenerateRandomFloat (1f,100f);
float percentSum = 0;
int result = 0;
for (int i = 0; i < percent.Length; i++) // 확률 계산
{
percentSum += percent[i];
if (random <= percentSum)
{
result = i;
break;
}
}
return result; // 결과 값 리턴
}
public bool GetBoolRandomResult(float percent) // bool 값이 필요한 랜덤일 때, 호출
{
float random = GenerateRandomFloat (1f,100f);
return random <= percent ? true : false;
}
private float GenerateRandomFloat(float min, float max)
{
float randomValue = Random.Range(min, max);
float roundedValue = Mathf.Round(randomValue * 10f) / 10f; // 소수점 1 번째 자리로 반올림 해줌
return roundedValue;
}
}
}
랜덤 이벤트 클래스를 RandomEvent 이름 공간(namespace)로 구현한다.
using System.Collections.Generic;
using UnityEngine;
using RandomEvent;
public class EnemyDataManager : MonoBehaviour
{
[Header("# Enemy Spawn Percent ")]
[SerializeField] private StageSpawnPercent stageSpawnPercent;
private RandomEventResult randomEvent;
private void Awake()
{
randomEvent = new RandomEventResult();
for (int i = 0; i < stageSpawnPercent.Length; i++)
{
stageSpawnPercent[i].CalculatePercentage();
}
}
public int GetEnemyType()
{
int enemyType = randomEvent.GetArrRandomResult(stageSpawnPercent[spawnPercentLevel].spawnPercent);
return enemyType;
}
}
using RandomEvent를 작성한 뒤, RandomEventResult 클래스를 선언 및 초기화한다.
그리고 내가 구하고자하는 확률을 RandomEventResult에 저장된 함수들을 이용하여 구하면 된다.
이걸 구현해보고 느낀 점은 float 보다는 int가 더 구현하기 쉬운 것 같고, 굳이 float로 할 이유를 못 찼겠다.
같이 작업하는 팀원들과 협의하고 int로 진행한다면 큰 문제는 없을 것 같다고 생각한다.
'Unity(유니티) > 유니티 공부' 카테고리의 다른 글
[Unity/C#] 일반화 프로그래밍 (Generic) (0) | 2024.06.29 |
---|---|
[Unity/C#] AudioMixer를 이용한 볼륨 조절 (0) | 2024.06.26 |
[Unity/C#] AES 암호화 알고리즘 (0) | 2024.06.23 |
[Unity/C#] Json 저장 및 base-64를 이용한 암호화/복호화 (0) | 2024.06.22 |
[Unity/C#] HashSet를 이용한 중복 제거 (0) | 2024.06.21 |