해당 부분은 인게임의 맵이다.
이 맵은 세개의 섹션으로 나누어져 있다.
도로 1, 도로 2, 도로 3 이다.
도로 1의 특정한 지점을 플레이어가 지나치면 도로 1이 도로 3의 끝으로 가게 되는 구조다.
그렇게 도로3은 도로1이 되는 것이고 도로 1은 도로 3이 되는 식의 시스템이다.
public class EnvironmentManager : MonoBehaviour
{
[SerializeField]
private Transform vanTransform;
[SerializeField]
private Transform[] Sections;
[SerializeField]
private float moveOffSet = 60.0f;
[SerializeField]
private float standardOffSet = 10.0f;
private int sectionIndex = 0;
private bool moveTrigger = false;
// Update is called once per frame
void Update()
{
// 기준이 되는 Section
if(vanTransform != null && vanTransform.position.z >=
Sections[(sectionIndex + 1)%Sections.Length].position.z + standardOffSet)
{
moveTrigger = true;
}
if (moveTrigger)
{
// 이동하는 Section
Sections[sectionIndex % Sections.Length].position += new Vector3(0, 0, moveOffSet);
sectionIndex += 1;
moveTrigger = false;
}
}
}
하지만 그랬을 경우 별 문제가 없을지 고민 했는데 한 가지 좀 걸리는 것이 있다.
어쨋거나 맵 자체를 Transform 을 이용해서 이동을 하는 것인데 이러한 방식은 생각해야 할 것이 있다.
뭐냐면 자식 오브젝트가 많을 수록 성능 저하가 일어난다는 것이다.
Unity Asset Store에서 구한 Asset인데 맵 자체가 자식 오브젝트가 굉장히 많았다.
근데 해당 맵은 애니메이터의 자식 오브젝트 생략하는 방식을 사용하지도 못한다.
어떻게 해야 할까?
public class MeshCombiner : MonoBehaviour
{
public GameObject Parent;
public Material Material;
public bool DeactivateParentAfterMerge = true;
public bool DestroyParentAfterMerge = false;
[ContextMenu("Merge")]
public void MergeMeshes()
{
MeshFilter[] meshFilters = Parent.GetComponentsInChildren<MeshFilter>();
List<CombineInstance> combineList = new List<CombineInstance>();
for (int i = 0; i < meshFilters.Length; i++)
{
if (meshFilters[i].sharedMesh != null)
{
CombineInstance combineInstance = new CombineInstance
{
mesh = meshFilters[i].sharedMesh,
transform = meshFilters[i].transform.localToWorldMatrix
};
combineList.Add(combineInstance);
}
}
GameObject combinedObject = new GameObject("Combined Mesh");
combinedObject.AddComponent<MeshFilter>();
combinedObject.AddComponent<MeshRenderer>();
combinedObject.GetComponent<MeshFilter>().sharedMesh = new Mesh();
combinedObject.GetComponent<MeshFilter>().sharedMesh.CombineMeshes(combineList.ToArray());
combinedObject.GetComponent<MeshRenderer>().material = Material;
if (DeactivateParentAfterMerge)
{
Parent.SetActive(false);
}
if (DestroyParentAfterMerge)
{
Destroy(Parent);
}
}
}
해당 과정을 ContextMenu를 통해 Merge를 실행하는 것 외엔 이해를 잘 하지 못해서 서칭을 하며 공부해봤다.
원리를 간단하게 두줄로 정리하자면 이렇다.
자식 오브젝트들의 메쉬와 변환 정보를 수집하여 CombineInstance 리스트에 저장하고,
CombineMeshes()를 사용해 메쉬를 하나로 결합한 후 새로운 GameObject에 적용합니다.
즉 컴포넌트에 부모 오브젝트를 설정해주면 알아서 자식 오브젝트들을 합쳐주고 Transform 이동에 과부하가 생기지 않는다는 점을 알고 있으면 된다.
Rails의 자식오브젝트가 많으며 그 자식오브젝트들이 다 같은 Material을 사용하고 있어야 된다.
해당 부분은 섹션 총 세개로 이루어진 맵이니까 한 섹션마다 같은 머터리얼끼리 묶어줘서 Merge 해줬다.
Rails가 한 개의 오브젝트 Rail로 Merge 된 모습이다
이로 인해서 Transform 시 자식이 많아서 생기는 성능 저하를 우려 할 필요가 없게 된다.