odyssey

#22 odyssey 개발일지 : (또) 동적 지형생성

san10 2024. 2. 3. 20:13

동적으로 지형을 생성하는 건 이전에도 사실 만들었지만..

https://san10.tistory.com/26

 

#9 odyssey 개발일지 : 동적 지형생성과 오브젝트 풀링

(드디어) 중간고사가 끝나서 다시 스터디와 개발을 시작하려고 한다! 지형을 어떻게 만들지 생각해 봤는데... 미리 여러 패턴의 지형을 생성해놓고, 런타임중에 적당히 이어붙이려고 한다! 우선

san10.tistory.com

 

이때는 위치만 맞춰주기에 곡선이 연속적이지 않다는 문제가 있다.

 

그래서 저번에 만든 지형을 부드럽게 만들어주는 기능을 바탕으로

지형과 지형을 부드럽게 이어주는 지형을 계속 만들어주며

동적으로 지형이 생성되는 기능을 만들었다.

실행 결과

구현

//다음 지형 생성
TerrainType selectedTerrainType = (TerrainType)UnityEngine.Random.Range(0, System.Enum.GetValues(typeof(TerrainType)).Length);

Vector3 nextTerrainPos = previousTerrainEndPoint + Constants.Map.TerrainSpace;
GameObject nextTerrain= Instantiate(terrainDatas[selectedTerrainType], nextTerrainPos, Quaternion.identity);
TerrainData nextTerrainData = nextTerrain.transform.GetChild(0).GetComponent<TerrainData>();
Vector3 nextCP1ToWorld = nextTerrain.transform.GetChild(0).TransformPoint(nextTerrainData.cp1);
nextTerrain.transform.position += nextTerrain.transform.position - nextCP1ToWorld;

(이전에 구현했던 것과 비슷하게) enum에서 랜덤하게 지형하나 뽑고

이때 이전 지형의 끝점에서 다음 지형의 첫점까지 offset만큼 떨어진 위치에 지형을 생성한다.

 

//이어주는 지형 생성
TerrainData previousTerrainData = previousTerrain.GetComponent<TerrainData>();
Vector3 previousCP3ToWorld = previousTerrain.transform.TransformPoint(previousTerrainData.cp3);
Vector3 previousCP4ToWorld = previousTerrain.transform.TransformPoint(previousTerrainData.cp4);
nextCP1ToWorld = nextTerrain.transform.GetChild(0).TransformPoint(nextTerrainData.cp1);
Vector3 nextCP2ToWorld = nextTerrain.transform.GetChild(0).TransformPoint(nextTerrainData.cp2);

GameObject terrainConnector = bezierMeshGenerator.CreateBezierMesh(
    previousCP4ToWorld, 2*previousCP4ToWorld - previousCP3ToWorld,
    2*nextCP1ToWorld - nextCP2ToWorld, nextCP1ToWorld);

그리고 이전 지형과 새로 생성한 지형의 컨트롤 포인트를 받아온다.

컨트롤 포인트는 로컬이기 때문에 월드로 변환해주고,

그걸 바탕으로 이어주는 지형인 terrainConnector를 생성한다.

 

terrainQueue.Enqueue(terrainConnector);
terrainQueue.Enqueue(nextTerrain);

나중에 지형이 일정 개수 이상이되면 dequeue해서 지워주기 위해서

새로 생성한 지형과 이어주는 지형을 queue에 넣어둔다.

 

void FixedUpdate()
{
    time += Time.deltaTime;
    if (time >=3f)
    {
        if (terrainQueue.Count >= Constants.Map.TerrainMaxCount)
        {
            Destroy(terrainQueue.Dequeue());
            Destroy(terrainQueue.Dequeue());
        }
        TerrainGenerator();
        time = 0;
    }
}

그리고 위의 TerrainGenerator()를 일정 시간마다 돌려준다.

또한 큐에 넣어놨던 지형도 일정 개수 이상이 된다면 꺼내서 삭제하게 했다.

아마 시간으로 지형 생성을 하진 않을 것 같지만

일단 임시로 3초마다 실행되게 해줬다.

 

 

이전에는 오브젝트 풀링을 했었는데 이번엔 안할것 같다.

왜냐하면 이전에 프로파일러를 켜서 성능 측정을 해봤는데

한거나 안한거나 거의 차이가 없었다.

사실 엄청나게 오브젝트를 많이 생성하거나, 오브젝트가 엄청 큰게 아니라서

큰 의미가 없는것 같기도 하다

 

그래서 일단은 뺄 생각이고 나중에 최적화 이슈가 생기면 그때 고려해 볼 것 같다.