ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Rollick 개발 일지] 02. 주변 건물 무작로 생성하기
    카테고리 없음 2023. 10. 21. 22:07

    지난 시간엔 스케이트 보드가 길을 끊김 없이 가는 기능을 구현하였다.

    하지만 이렇게만 구현한다면 주변 건물들이 계속 반복적으로만 나타나 플레이어가 단조로움을 느낄 수 있다.

    우선 랜덤적으로 배치할 건물들을 4개씩 묶어 총 7개의 프리팹을 제작하였다. 이 프리팹들을 도로의 주변에 랜덤적으로

    배치할 예정이다.

     

    생각한 로직은 이렇다.

    이 로직을 기반으로 작성한 코드는 아래와 같다.

    [System.Serializable]
    public class BuildingElement
    {
        public Transform building; // 빌딩 프리팹
        public float nextBuildingPosIdx; // 다음 빌딩과 떨어져야 하는 간격
    }
    
    public class BuildingInstallFunc : MonoBehaviour
    {
        public List<BuildingElement> buildingList = new List<BuildingElement>();
        private List<BuildingElement> _buildings = new List<BuildingElement>();
        private BuildingElement _saveBuilding = null;
    
        private float _positionValue;
    
        private Dictionary<Transform, List<Transform>> _loadData = new Dictionary<Transform, List<Transform>>();
    
        private void CombineBuilding(Transform load, Transform buildingTrans) // 도로에 배치된 건물 저장
        {
            if(!_loadData.ContainsKey(load))
            {
                List<Transform> buildingDatas = new List<Transform>();
                buildingDatas.Add(buildingTrans);
                _loadData.Add(load, buildingDatas);
                return;
            }
    
            _loadData[load].Add(buildingTrans);
        }
    
        public void ResetBuilding(Transform load) // 도로에 배치된 빌딩 초기화
        {
            if (!_loadData.ContainsKey(load)) return;
    
            foreach(Transform t in _loadData[load])
            {
                Destroy(t.gameObject); //PoolManager로 교체 예정
            }
            _loadData[load].Clear();
        }
    
        public void RandomBuild(Transform parent) // 도로에 건물 무작위로 배치
        {
            _saveBuilding = null;
            _positionValue = 0;
            _buildings.Clear();
            for (int i = 0; i < buildingList.Count; i++)
                _buildings.Add(buildingList[i]);
    
            for (int i = 0; i < 4; i++)
            {
                int idx = Random.Range(0, _buildings.Count);
                BuildingElement select = _buildings[idx];
    
                Transform selectTrm = Instantiate(select.building, parent);
                CombineBuilding(parent, selectTrm);
                if(_saveBuilding != null)
                {
                    _positionValue += _saveBuilding.nextBuildingPosIdx;
                    selectTrm.position += new Vector3(_positionValue, 0, 0);
                }
                if (_saveBuilding != null)
                    _buildings.Add(_saveBuilding);
                _saveBuilding = _buildings[idx];
                _buildings.RemoveAt(idx); // 다음 생성되는 빌딩이 똑같은 빌딩이 생성되선 안되니
                                          // 삭제처리 해주었다.
            }
        }
    }

    잘 동작하는 모습이다. 하지만 오른쪽 부분만 맵이 생성되며 도로와 도로 사이에 자투리 공간 또한 존재한다.

     

    자투리 공간은 도로 프리팹을 조금 손봐 손쉽게 해결할 수 있다. 하지만 왼쪽 부분에 생성될 건물들은 건물이 바라보는

    방향이 달라야 한다.

     

    오른쪽 건물 4개, 왼쪽 건물 4개를 배치하기 위해선 총 8번 반복을 해야 하고 for문의 int i를 2로 나누어 나머지가 0이면 

    왼쪽, 1이면 오른쪽으로 판단하기로 했다.

     

    public void RandomBuild(Transform parent) // 도로에 건물 무작위로 배치
        {
            _saveBuilding = null;
            _positionValue = new float[2] { 0, 0 };
            _buildings.Clear();
            _saveBuilding = new BuildingElement[2] { null, null };
    
            for (int i = 0; i < buildingList.Count; i++)
                _buildings.Add(buildingList[i]);
    
            for (int i = 0; i < 8; i++)
            {
                int divideRL = i % 2;
                int idx = Random.Range(0, _buildings.Count);
                BuildingElement select = _buildings[idx];
    
                Transform selectTrm = Instantiate(select.building, parent);
    
                if (_saveBuilding[divideRL] != null)
                {
                    _positionValue[divideRL] += _saveBuilding[divideRL].nextBuildingPosIdx;
    
                    _buildings.Add(_saveBuilding[divideRL]);
                }
                selectTrm.position += new Vector3(_positionValue[divideRL], 0, 31 * (divideRL));
    
                foreach (Transform child in selectTrm)
                {
                    child.rotation = Quaternion.Euler(0, 180 * (divideRL), 0);
                }
    
                _saveBuilding[divideRL] = _buildings[idx];
                _buildings.RemoveAt(idx);
                CombineBuilding(parent, selectTrm);
            }
    
        }

    완성된 메서드이다.

     

    잘 작동하는 모습이다.

    다음 포스팅에서 뵙겠습니다.

Designed by Tistory.