내일배움캠프 44일차 6/18 TIL + Unity공부
개인 과제에 객체 지향적 코드 적용
오늘은 개인 과제를 하는데 객체 지향적으로 확장성이 용이하게 짜보았다. 급하게 하루 만에 만들었지만 그래도 나름 머리를 많이 써서 최종 프로젝트에도 적용할 수 있게 기반을 짜보았다.
1. Character 코드 설계
우선 Character
코드를 만들어서 모든 종류의 유닛의 기반을 만들었다. 여기에 CharacterStat
과 CharacterAction
으로 기능을 나눴다.
- CharacterStat: 체력, 공격력, 이동속도 등의 캐릭터의 속성들을 관리.
- 체력, 공격력, 이동속도 등의 속성도 따로 클래스를 만들고, 체력과 같이 채워지는 형식은 Max와 current 값이 있는 int값 클래스.
- 이동과 공격력 같이 얼마든지 변화 가능한 속성은 기본값, 추가값이 있는 float값 클래스로 따로 만듦.
- 속성의 get, set을 적극 활용하여 UI 업데이트도 용이하게 함.
- CharacterAction: 이동, 공격, 공격 받음 등의 행동을 관리.
- 이동, 공격, 피해받기를 인터페이스로 기능을 나누어 추가.
- 이동할 수 없는 캐릭터(건물 등), 피해를 받을 수 없는 물체, 공격할 수 없는 건물 등을 고려하여 기능을 분할.
2. Enemy와 Player 클래스 설계
- Enemy 클래스:
Character
클래스 상속.- 추가로 죽으면 주인공에게 줄 돈을 가지고 있음.
- Player 클래스:
Character
클래스 상속.- 경험치와 공격 시 애니메이션 변환 기능 추가.
- 애니메이션과 상태 변화를 만들 때 FSM 사용.
3. FSM(State Machine) 적용
- StateMachine 클래스: 상태를 변환해주는 역할.
- State 클래스: Idle, Moving, Attacking 3가지 클래스를
BaseState
기반으로 만듦.- 각각 State 시작 시, 실행 중, 종료 시 함수를 만들어 캐릭터가 자동으로 시작, 공격, 이동, 상태를 전환하며 행동하게 함.
- 새로운 State를 추가할 때도 편리하게 기반 코드가 완성됨.
4. Item 클래스 설계 고민
- 체력 회복, 공격력 증가 등의 단순한 기능을 인터페이스로 나누기에는 비효율적.
- 속성, 값 클래스를 아이템이 가지고 있다가 각 속성에 따라 값을 array로 저장하고 이를 받아오는 방식으로 간략화할 필요성.
5. 결론
이번 과제에서는 이전과 달리 확장성을 고려하여 코드를 작성함. 속도가 느리더라도 최대한 세분화하여 작성했으며, 결과적으로 기능 추가 시 시간이 절약됨. 이를 기반으로 최종 프로젝트에도 적용할 수 있을 것으로 기대됨.
이번 작업을 통해 객체 지향적 설계와 확장성을 고려한 코딩의 중요성을 깨닫게 되었다. 특히 코딩하면서 고민을 많이 했는데, 그 중 캐릭터 스탯은 처음에는 Stat
동적 생성
장점
- 씬 변화가 적어 충돌이 적다: 동적 생성 방식은 씬 간의 변화를 최소화하여 충돌 가능성을 줄입니다.
- Prefab 작업의 분업이 편리하다: Prefab을 통해 작업을 분리하면 팀원이 각자 맡은 부분을 독립적으로 작업할 수 있습니다.
- 빌드 용량 감소: 리소스나 UI를 Addressable로 관리하여 빌드 용량을 줄일 수 있습니다.
- 와이어 프레임 변형의 간단한 적용: 동적 생성 방식은 와이어 프레임상의 변형을 쉽게 적용할 수 있습니다.
단점
- 실행 전 화면 확인 불가: 동적 생성된 오브젝트는 실행하기 전까지 화면에서 확인할 수 없습니다.
- 프리팹 배치 변경의 불편함: 배치를 변경하려면 해당 프리팹을 찾아가서 수정해야 합니다.
목표
- 에셋 번들 및 어드레서블 사용: 에셋 번들과 어드레서블을 사용하여 빌드 용량 감소와 깃 충돌 최소화를 목표로 합니다.
구현 방법
- 프리팹 위치 지정
- 프리팹을 특정 구간에 생성하도록 범위를 지정합니다.
- 예시 코드:
GameObject newObject = Instantiate(prefab, new Vector3(Random.Range(minX, maxX), 0, Random.Range(minZ, maxZ)), Quaternion.identity);
- Additive 모드로 씬 로드
SceneManager
를 사용하여LoadScene
할 때 모드를 Additive로 설정하여 현재 씬에 추가적인 요소를 얹습니다.- 예시 코드:
SceneManager.LoadScene("AdditionalScene", LoadSceneMode.Additive);
- 오브젝트 배치 검사
- 오브젝트를
Instantiate
한 후, Ray로 위치 검사를 수행하여 배치가 가능한지 확인하고, 가능하지 않다면 가능한 자리를 찾아 배치합니다. - 예시 코드:
Ray ray = new Ray(position, Vector3.down); RaycastHit hit; if (Physics.Raycast(ray, out hit)) { // 위치 조정 로직 }
- 오브젝트를
- 맵 로드와 물체 생성
- 맵은 모든 물체가 존재할 기반이 되므로, 이를 다른 씬에 생성하고 Additive로 불러와 물체를 생성하면 충돌 가능성을 줄일 수 있습니다.
LoadSceneAsync
를 사용하여 맵 로드가 완료된 후 다음 작업을 진행합니다.- 예시 코드:
StartCoroutine(LoadYourAsyncScene()); IEnumerator LoadYourAsyncScene() { AsyncOperation asyncLoad = SceneManager.LoadSceneAsync("MapScene", LoadSceneMode.Additive); while (!asyncLoad.isDone) { yield return null; } // 다음 작업 }
- 데이터 소스
- 동적 생성 시 필요한 데이터는 CSV 파일이나 서버에서 받아옵니다.
위의 방식으로 동적 생성을 구현하면 씬 충돌을 최소화하고, Prefab 작업의 효율성을 높일 수 있습니다. 또한, 에셋 번들 및 어드레서블을 활용하여 빌드 용량을 줄이는 것도 가능합니다. 이를 통해 더욱 유연하고 확장성 있는 프로젝트를 구성할 수 있습니다.