버섯은 죽은 나무 옆에서 생성될 수 있고 바위 근처엔 돌멩이가 생성될 수 있다.
이러한 부산물?을 생성하는 객체를 만들었다.
이외에도 바위, 나무와 같은 큰 자원 오브젝트들도 절차적으로 생성할 수 있는 알고리즘을 구상중이다.
부산물을 생성하기위한 ByproductCreator
컴포넌트를 작성했다.
벌목된 나무는 게임시간으로 1마다 주변 지름 2인 원 내부의 랜덤한 지점에 버섯을 생성할 수 있고, 최대 3개까지만 생성한다.
일정 시간마다 부산물을 생성하기 위한 시도를 하도록 작성하고 싶었다.
하지만 매 프레임 시도를 하게되면, 불필요한 Update 호출이 많아질 것 같아서 특정 시점에만 생성 시도를 하기로 했다.
코루틴을 이용해도 됐겠지만, 마침 우리 게임에 딱 맞는 이벤트가 있었다.
바로 DayCycle
클래스의 OnTimeUpdated
라는 이벤트다. 이 이벤트는 현실 시간으로 대략 10초마다 게임 시계의 초침이 1이 지나간다.
따라서 이 이벤트에 생성을 시도하는 메서드를 구독해주도록 했다.
private void OnEnable()
{
if (_manager == null)
_manager = Managers.Game.DayCycle;
_currentCreateCount = 0;
_manager.OnTimeUpdated += TryCreate;
}
private void OnDisable()
{
if (_manager != null)
_manager.OnTimeUpdated -= TryCreate;
}
1차적으로 일단 생성만 하게 구현했다.
아직 생성할 위치가 유효한 좌표인지 판단하는 로직이 없는데, 이것만 추가하면 이 컴포넌트의 작업은 끝날 것 같다.
public void TryCreate()
{
if (_distribution <= Random.value)
return;
Create();
}
// TODO: 생성 위치가 유효한지 확인해야함.
// 현재 문제점
// 1. 나무 속에 버섯이 생성될 가능성이 있음
// 2. 버섯 끼리 겹쳐서 생성될 가능성이 있음
// 3. 공중, 혹은 벽 속에 생성될 가능성이 있음
public void Create()
{
if (_currentCreateCount >= _maxCreateCount)
return;
Vector3 spawnPosition = Random.insideUnitCircle;
spawnPosition.Set(spawnPosition.x, 0, spawnPosition.y);
spawnPosition += transform.position;
Instantiate(_prefab, spawnPosition, Quaternion.identity);
_currentCreateCount++;
}
불필요한 Update 메서드 호출을 줄이기 위해 DayCycle
의 OnTimeUpdated
를 이용해 게임 시간 1마다 오브젝트의 생성 시도를 하도록 했는데, 나는 꽤 좋은 방법인 것 같다.
지금 자원 오브젝트의 재생성 시간도 매 프레임 Update 메서드에서 호출하며 값을 변경 중인데, 이를 DayCycle
로 바꾸면 불필요한 연산을 줄일 수 있을 것 같긴 하다.
아직 자원의 개수가 적지만 절차적 생성 방식을 도입하고 나면 이 자원 오브젝트의 개수도 많이 질 것으로 예상이 돼서, 이 방식을 도입하면 좋을 것 같다 !
결국 자원 오브젝트도 하나하나 배치하기보단 절차적 생성을 도입하는게 좋을 것 같다.
생성 알고리즘 같은 경우, 높이가 달라지는 경계선을 찾거나, 닫혀있는 언덕을 찾는 부분은 BFS를 이용해서 찾아낼 수 있을 것 같다.
문제는 열려있는 공간의 넓은 공동? 광장? 같은 지형을 어떻게 판별하느냐다.
(특히 중앙섬 같은 경우 y축 높이가 0인 부분은 다 열려있다.)
예상중인 방법으로는 특정 좌표에서 BFS를 시작해서 가장 먼저 벽에 닿게 된다면, 그 깊이(시작점에서의 거리)까지만 BFS를 하고 그 범위를 생성 범위로 지정하는 방법을 생각중이다.
이 경우, 시작점을 어떻게 정할 건지를 잘 설정해야할 것 같다.