강의

멘토링

커뮤니티

Inflearn Community Q&A

toon88's profile image
toon88

asked

[Unity Level Up!] Quest & Achievement System Developed Modularly

전체적인 폴더구조? 질문이요!!

Written on

·

720

0

저도 모듈식,이벤트주도적 개발에 관심이있어서 질문드립니다!!.

퀘스트시스템뿐만아니라 전체적인 폴더구조를 어떻게하시는지 궁금해서요.!

강의 내용이랑은 관련이없지만 궁금해서 질문드립니다.!

 

다른분의 강의를보니 폴더를

Mnagers 

   -UIManager,GameManager,SoundManager,DataManager등등 Quest가있다면 QuestManager?

UI

Utills

Data

등등 이런식이루 나누던데 먼가 모듈식이랑은 동떨어져서보여서요.

어떤식으로 구성하시는지 궁금합니다.!(작업하셨던 프로젝트가 있으시면 전체적인 폴더구조? 예시 궁금합니다.! ㅠㅠ 실례가안되신다면!)

 

 

 

 

unity

Answer 1

0

Developer G님의 프로필 이미지
Developer G
Instructor

수강해주셔서 감사합니다.

폴더 구조는 개인 혹은 팀이 느끼는 편의에 따라 달라지는 부분이라 어떤 폴더 구조가 더 좋다 할 것은 없습니다.

저는 강의에서 하던 것과 똑같이 구조화를 할 때 대그룹 -> 소그룹 -> 모듈로 나누는 편이고, namespace를 작성하듯 폴더 구조를 만듭니다.(추후에 namespace 작성이 필요한 경우 폴더 구조 그대로 namespace를 작성하면 되기 때문에 그 부분에서 약간 편합니다.)

저같은 경우 말씀해주신 예시처럼 Manager라고해서 전부 Manager 폴더에 넣어버리면 같은 그룹의 스크립트인데도(ex. QuestSystem.cs, Quest.cs와 같은 Quest 그룹) 여러 곳으로 흩어져 한 눈에 보기가 힘들어지기 때문에 선호하지 않습니다.(이는 제가 선호하지 않는다는 것이지 이 방식이 틀렸다는게 아닙니다.)

예시는 아래와 같습니다.

Assets/
     Models(or Sprites)/
          3D 모델 혹은 Sprite 폴더들
     Sounds/
          각종 사운드 폴더들
     Plugins/
         에셋 스토어나 외부에서 받은 유틸 에셋들
     Resources(or Resources를 안쓸 경우 ScriptableObjects)/
          Quest/
                Quest Sceiptable Objects
                Task/
                     Task Scriptable Objects
          Ability/
                Ability Scriptable Objects
                AbilityEffect/
                      AbilityEffect Scriptable Objects
     Scenes/
          TitleScene
          LobbyScene
          BattleScene/
                WoodScene/
                      LargeWoodScene
                      SmallWoodScene
                VolcanoScene/
                      LargeVolcanoScene
                      SmallVolcanoScene
     Scripts/
          General/
                Entity.cs
                PlayerController.cs
                TouchSystem.cs
          Stats/
              Stats.cs
              Stat.cs
          StateMachine/
              StateMachine.cs
              State/
                   State.cs
                   EntityState/
                         StunState.cs
                         SleepState.cs
                          ...
                   TouchState/
                         SelectTargetState.cs
                         SelectAOEState.cs
                         ...
           Ability/
                AbilitySystem.cs
                Ability.cs
                AbilityEffect/
                      AbilityEffect.cs
                      AbilityEffectAction/
                            AbilityEffectAction.cs
                            ...
           QuestSystem/
                 QuestSystem.cs
                 Quest.cs
                 Task/
                      Task.cs
                      TaskAction/
                           TaskAction.cs
                           SimpleCount.cs
                           ...
                      TaskEvent/
                           TaskEvent.cs
                           ...
            SaveSystem/
                  SaveSystem.cs
                  SaveSystemSetting.cs
                  Editor/
                       SaveSystemWindow.cs
            UI/
                Quest/
                      QuestDetailView.cs
                      QuestListView.cs
                      QuestView.cs
                Ability/
                      AbilityDetailView.cs
                      AbilityTreeView.cs
                      AbilityToolTipView.cs
            Utility/
                 ObjectCopier.cs
                 DebugExtension.cs

다시 한번 말씀드리지만 제 방식이 답이 아닙니다. 제 방식을 본 다른 프로그래머 분중에는 폴더가 너무 많아서 난잡하고 느끼시는 분도 계실거고, 반대로 구조화 방식이 자기 취향이라고 하실 분도 계실겁니다. 정말 터무니없는 구조가 아니라면 본인과 팀이 편한게 최우선입니다.
   

toon88님의 프로필 이미지
toon88
Questioner

상세하게 설명해주셔서 감사합니다.!! 궁금한점이 몇개더있어서 질문드립니다..

여러기능에 쓰일수있는 인터페이스같은 파일들은 따로 두시나요?!

제가 레트로님의 책을보고 게임을만들면서 파일을 컴포넌트별로 나누는데 

예를들어 PlayerInput , PlayerMovement, PlayerHealth, PlayerShooter, 등 각기능을 두고 폴더구조를

Health/

    IDamageable인터페이스

     LivingEntitiy

     PlayerHealth

     EnemyHeatlh

Move/

    MoveBase

    PlayerMove

    EnemyMove

Input/

    InputBase

     PlayerInput

     InputUI => 클릭시 아이템이나 무기 사용, IUse인터페이스 호출

     InputManger

Item/

   IUse 인터페이스  => 모바일게임이라 버튼클릭시(InputUI에서) 호출  

   ItemBase, (IItem인터페이스 추가)

   HealItem 

Weapon/

  WeaponBase (IItem인터페이스추가) 

Buff/

   BuffBase

    Stun

//등등이런식으로 나누는중인데 파일만 많아져서 고민입니다.. 터무니없는구조인것인지.. 의견듣고싶습니다!!  

아니면. Player폴더를 만들어서 PlayerInput,PlayerShooter,PlayerHealth를 다묶어버려야하는지..

또한, Stun같은경우 생성시 하위객체에 자식으로 생성뒤, 

OnEnable()이되면 GetComponentInParent<InputBase>().enable = false 이런식으로 구현하고있는데  선생님같은경우 StunState 파일이보여서요. 어떤식으로 동작하는지 대충이라도알고싶습니다.!!!

 

**퀘스트시스템말고 다른강좌도 추가진행예정이신지또한 궁금합니다

Developer G님의 프로필 이미지
Developer G
Instructor

1.
저는 인터페이스를 안쓴지가 꽤 오래됐습니다.
보통 책이나 강좌에서 인터페이스가  좋은 설계에 필수적인 것처럼 표현되어 여러 루키 프로그래머들이 인터페이스에 집착하는 것을 종종 보는데요, 디버깅을 어렵게 만들고 불필요한 추상화로 성능을 저하시킨다고(가상 테이블의 크기 증가) 인터페이스에 부정적 의견을 가진 프로그래머도 많습니다.(대표적으로 포프님이 계실겁니다. https://www.youtube.com/watch?v=tL3sB6qaIoM)
저는 부정적 의견을 가진 프로그래머까지는 아니지만 인터페이스가 효용성을 발휘하는 곳은 한정적이라는 의견에 동의하기 때문에 특수한 경우가 아니면 잘 쓰지 않습니다. 이는 제가 일부로 인터페이스의 사용을 피한다는 것이 아닌 제 개발 철학상 특수한 경우가 아니면 필요성을 못 느낀다는 의미입니다.

수강생분께서는 InputUI에서 IUse 인터페이스를 호출한다고 하셨는데, 저였다면 IUse 인터페이스를 만들지 않고 event를 연결해서 사용할 수 있는 완전한 구조의 MonoBehaviour 스크립트를 만들었을 것입니다. 이는 수강생분의 개발 방식이 틀렸다는 것이 아니라 저는 위와 같은 방식으로 개발하기 때문에 인터페이스를 쓴지가 꽤 오래되었다는 것입니다.

만약 제가 인터페이스를 만들게된다면 윗 댓글로 말씀드린 대그룹 -> 소그룹 -> 모듈 구조에 맞춰서 지금 수강생분이 하신 것처럼 위치시킬 것 같습니다.

2.
나눠진 컴포넌트는 적절히 나눠진 것 같습니다. 다만 PlayerHealth와 EnemyHealth, PlayerMove와 EnemyMove는 이름만봐서는 같은 작업을 하는 컴포넌트들이기에 EntityHealth, EntityMove(or EntityMovement)로 합치는 것이 좋을 것 같습니다. 논리적으로 생각을해봐도 롤을 예로 들어 애쉬라는 챔피언은 내가 쓰면 Player가 되고 상대방이 쓰면 Enemy가 되는데 같은 역활의 컴포넌트를 적이냐 아니냐로 둘로 나누는 것은 그리 좋은 설계는 아닙니다.

General/
      
PlayerController(PlayerInput)
      Entity/
           LivingEntity,
           EntityMovement,
           EntityHealth
      Input/
          InputManager
          InputUI
Item/
   ItemBase
   HealthItem
   Weapon/
          WeaponBase
Buff/
   BuffBase
   Stun

아마 저였다면 이렇게 구조가 되었을 것 같습니다. 물론 앞서 말씀드렸듯이 이게 답이 아니고 그저 제 취향일뿐입니다. 수강생분의 구조도 문제가 없습니다. 다만 본인 스스로 자신의 구조가 마음에 안드신다면 여러 기준을 세워서 구조를 바꿔보며 내가 편한 구조를 찾아보는 것도 좋습니다. 

3.
제가 사용하는 방식은 StateMachine을 통한 상태 제어입니다.(FSM) StateMachine은 과거 인공지능 개발에 많이 쓰였는데요, 지금은 그 자리를 BehaviourTree에게 내어주고 애니메이션 제어(유니티 애니메이션에도 쓰이죠)나 캐릭터, 시스템의 상태 제어에 주로 쓰입니다. FSM은 제가 여기서 설명하기에 짧지 않은 분량이라 어떤 것인지 알 수 있을만한 링크들을 적어두겠습니다. 다만 아쉽게도 직설적으로 얘기하자면 각 링크의 예제와 설명이 그리 좋지 않습니다. 그냥 어떤 느낌인지 알아본다는 생각으로 보시는게 좋습니다.

https://luv-n-interest.tistory.com/778
https://welcomeheesuk.tistory.com/46
(FSM 관련 플러그인 추천해주는 글: https://boycoding.tistory.com/262)

어떤 식으로 동작하는지에 대해서 짧게 얘기드리자면,(FSM을 모르시면 이해가 힘드실겁니다)

Entity 내부에 계속 Update되고 있는 StateMachine이 있고, StateMachine은 State라는 클래스를 계속 Update하고 있습니다.
(Entity.Update => StateMachine.Update => State.Update)

처음 세팅은 DefaultState로 해놔서 DefaultState가 계속 Update 되고 있게 되는데,
(Entity.Update => StateMachine.Update => State(DefaultState).Update)

이때 다른 캐릭터가 "야 너 스턴 걸렸어(enum EntityStateMessage.InStun), 5초야(extraData=5f)"라고 메세지를 보내주면 DefaultState는 그 메시지를 받아서 (OnReceiveMessage)
"스턴 메세지네? 스턴 상태로 바꿔야지"하고 StateMachine이 Update하고 있는 State를 StunState로 바꿉니다.
(롤을 하시거나 아신다면 상대팀 엘리스가 고치를 날려서 내 챔피언이 스턴을 걸리는 상황을 생각하시면 됩니다.) 

StateMachine.ChangeState(InStunState)
(Entity.Update => StateMachine.Update => State(InStunState).Update)

이때 우리가 Start, Awake함수를 사용하는 것처럼 State도 변경될 때 이전 State의 Exit 함수와 바뀐 State의 Enter 함수를 실행시키는데, StunState의 Enter 함수에 캐릭터의 컨트롤러 같은 것들의 enable을 false로 바꿔주는 코드를 작성해놨다면 StunState로 바뀔 때 해당 코드들이 작동될겁니다.

의사 코드
StateMachine.ChangeState(newState):
      currentState.Exit(owner);
      currentState = newState;
      currentState.Enter(owner);

그리고나서 StunState의 Update를 통해서 5초 기다렸다가 다시 DefaultState로 변경을 합니다. StunState의 Exit 함수에 Enter 함수에서 껐던 enable들을 다시 켜주는 코드를 넣어놨다면 DefaultState로 바뀌면서 껐던 enable들이 다시 켜질겁니다.

말로만 짧게 설명할려니 제가 설명하고도 뭔 소리지인지 모르겠네요(...)
요약하자면 지금 수강생분이 만든 Stun 방식을 체계화 했다고 생각하시면 됩니다. 

4.
다음 강의는 언제 업로드할 지 미정이지만,  모듈식 스킬 시스템에 대한 강의를 준비하고 있습니다.
해당 강의는 가볍게 만들어본 이번 퀘스트 시스템과 달리 어느 정도 고수준의 다이나믹한 스킬을 만들 수 있는 스킬 시스템을 만드는 것을 목표로 합니다.
단순히 스킬을 만드는 것뿐만 아니라 캐릭터가 스킬 캐스팅, 차징 중 움직이지 못하게하거나 스턴, 슬립 같은 CC기를 통해 상대 캐릭터의 제어권을 뺐는 등 캐릭터의 상태를 스테이트 머신을 통해 제어하는 방법과 스킬과 애니메이션을 연동하는 방법 등을 배우게 될겁니다.
다이나믹한 스킬 시스템을 만드는건 상당히 어려운 일이고 캐릭터의 상태 제어, 애니메이션 제어가 들어가기 때문에 초급 강의였던 이번 강의와 달리 난이도가 상당히 있을 것입니다.

toon88님의 프로필 이미지
toon88
Questioner

친절하고 상세한 설명 감사합니다!! 감동받았습니다 ㅠㅠ! 

많은 도움이 되었습니다. 제가 너무 인터페이스나 기술을써야한다는 집착을 가진것같네요

스스로 개발을하면서 편한구조를 찾아봐야겠습니다! 마음같아선 모듈식으로 싹다해버리고싶은데 어렵네요. 

나중에 스킬시스템에 대한강의가 올라오면 바로보겠습니다! 빨리나왓으면 좋겠습니다!

toon88's profile image
toon88

asked

Ask a question