[이득우 언리얼 C++] 13. 프로젝트의 설정과 무한 맵의 제작

    💻 Code : https://github.com/tedison7/ArenaBattle

    프로젝트의 정리와 모듈의 추가

    언리얼 소스코드는 오브젝트에 관련된 헤더들은 Classes 폴더를 사용하고, 외부에 공개하는 선언 파일은 Public 폴더에서, 외부에 공개하지 않는 파일은 Private 폴더에서 보관하고 있다. 이와같이 폴더 구조를 변경해보자. Source/ArenaBattle 폴더안에 Public, Private 폴더를 생성한다. 그리고 헤더파일(.h)은 Public으로, cpp파일은 Private 폴더오 옮겨 놓는다. 그리고 uproject 파일을 우클릭하여 Generate Visual Studio project files를 선택하여 프로젝트가 재생성될 수 있도록 하자. 컴파일을 하고 에디터를 실행해보면 콘텐츠 브라우저의 폴더 구성도 변경됨을 확인할 수 있다.

    언리얼 엔진은 주 게임 모듈(Primary Game Module)을 사용 하여 게임 프로젝트의 로직을 관리한다. 주 게임 모듈 외에 다른 모듈을 게임 프로젝트에 추가하고 로직을 분리해 관리할 수도 있다. 별도의 게임 모듈을 생성해서 두개의 모듈로 게임 프로젝트를 구성해보자.

    • 모듈 폴더와 빌드 설정 파일 : 모듈 폴더와 모듈명으로 된 Build.cs 파일
    • 모듈의 정의 파일: 모듈명으로 된 .cpp 파일

    예제 파일들 중에서 ArenaBattleSetting 폴더를 프로젝트에 복사하여 적용하였고, 프로젝트 파일을 재생성 하였다.

    추가한 모듈을 빌드하도록 ArenaBattle.Target.cs 파일과 ArenaBattleEditor.Target.cs 파일을 수정해야한다.

    그다음 빌드를 하여 새로운 dll 파일이 생성되었는지를 확인하고 언리얼 에디터가 로딩하도록 다음과 같이 수정해야한다.

    {
        "FileVersion": 3,
        "EngineAssociation": "4.27",
        "Category": "",
        "Description": "",
        "Modules": [
            {
                "Name": "ArenaBattleSetting",
                "Type": "Runtime",
                "LoadingPhase": "PreDefault"
            },
            {
                "Name": "ArenaBattle",
                "Type": "Runtime",
                "LoadingPhase": "Default",
                "AdditionalDependencies": [
                    "Engine",
                    "UMG",
                    "AIModule",
                    "ArenaBattleSetting"
                ]
            }
        ]
    }

    이후 에디터를 다시 실행하여 ArenaBattleSetting 모듈폴더에 ABCharacterSetting 항목이 있다.

    INI 설정과 애셋의 지연 로딩

    언리얼 엔진은 언리얼 오브젝트의 기본값을 유연하게 관리하도록 외부 INI 파일에서 기본 값을 지정하는 기능을 제공한다. 애셋은 경로 정보만 알면 프로그램에서 이를 참조해 로딩할 수 있다.

    DefaultArenaBattle.ini 파일을 읽어들여서 ABcharacterSetting의 CharacterAssets 값을 설정하게 된다. 예제 코드에있는 DefaultArenaBattle.ini 파일을 Config폴더로 복사하였다. ArenaBattle 모듈의 ABCharacter에서 ArenaBattleSetting 모듈의 ABCharacterSetting의 캐릭터 애셋 목록을 얻어오도록 코드를 작성해보자. 먼저 ArenaBattle.Build.cs 파일에서 Private폴더에서만 ArenaBattleSetting 모듈을 사용할 예정이기에 PrivateDependencyModule 항목을 추가한다.

    그리고 GetDefault 함수를 사용하여 애셋 목록이 불러와 지는지 로그로 출력해보자

    빌드후 실행해보면 설정값이 로딩되어 로그에 찍히는 것을 확인 할 수 있다.

    이제 로그 코드는 제거하고 NPC가 생성될때 랜덤하게 하나의 캐릭터 애셋을 로딩하도록 기능을 변경해보자. FStreamableManager라는 클래스로 비동기 로딩이 가능하다. 프로젝트에서 하나만 활성화 하는것이 좋기에 ABGameInstance 클래스에서 멤버 변수로 선언하자.

    컴파일후 플레이해보면 캐릭터 메시가 플레이 마다 랜덤으로 로딩되는 것을 확인할 수 있다. 그리고 예제에서 사용하는 StreamableManager는 UAssetManager 오브젝트에 이미 선언돼 있기때문에 Engine/AssetManager.h 파일을 포함하여 UAssetManager::GetStreamableManager() 함수로 대신 사용해도 된다.

    무한 맵의 생성

    레벨을 섹션 단위로 나누고 하나의 섹션을 클리어하면 새로운 섹션이 등장하는 무한맵 스테이지를 제작해보자.

    섹션 액터의 역할은

    • 섹션의 배경과 네 방향으로 캐릭터 입장을 통제하는 문을 제공한다.
    • 플레이어가 섹션에 진입하면 모든 문을 닫는다.
    • 문을 닫고 일정 시간 후에 섹션 중앙에서 NPC를 생성한다.
    • 문을 닫고 일정 시간 후에 아이템 상자를 섹션 내 랜덤한 위치에 생성한다.
    • 생성한 NPC가 죽으면 모든 문을 개방한다.
    • 통과한 문으로 이어지는 새로운 섹션을 생성한다.

    Actor를 상속받는 ABSection 클래스를 생성하자. 그리고 예제의 스태틱메시 애셋은 각 방향별로 출입문과 섹션을 붙일수 있도록 8개의 소켓이 부착되어있다. 소켓을 활용하여 철문을 부착해보자

    컴파일후 ABSection액터를 배치해보면 철문이 부착된 것을 확인할 수 있다.

    그리고 이번에는 ABCharacter만을 감지하는 ABTrigger라는 콜리전 프리셋을 추가한다.

    ABSection에 Box 컴포넌트를 생성하여 세션의 중앙과 각 철문에 부착하자. 책에 있는 예제 코드를 따라 작성하였다. 그리고 컴파일후 트리거 영역이 설정되어있음을 확인할 수 있다.

    이제 액터의 로직을 스테이트 머신으로 설계한다. 스테이트들의 기획은 다음과 같다.

    • 준비(Ready) 스테이트 : 액터의 시작 스테이트, 문을 열어놓고 대기하다가 중앙의 박스 트리거로 플레이어의 진입을 감지하면 전투 스테이트로 전환
    • 전투(Battle) 스테이트 : 문을 닫고 일정 시간이 지나면 NPC를 소환. 그리고 일정 시간이 지나면 랜덤한 위치에 아이템 상자도 생성. 모든 NPC가 죽으면 완료 스테이트로 전환
    • 완료(Complete) 스테이트 : 닫힌 문을 열고. 트리거 게이트로 플레이어를 감지하면 이동한 문 방향으로 새로운 섹션을 소환한다.

    그리고 기존 배경 액터 였던 SM_SQUARE 스태틱메시 액터를 제거하고 ABSection 액터로 대체한후 Step4 맵으로 새로 저장하자. 프로젝트 세팅에서 이를 기본맵으로 설정한다. 플레이를 해보면 모든 문이 열려있음을 확인할 수 있다.

    에디터 편집 상황에서도 확인 할수 있도록 OnConstruction 함수를 통해서 결과를 확인할수 있도록 하자.

    이제 문에 설치된 박스 컴포넌트에 태그를 설정하여 해당 문 방향에 띄울 다음 섹션 액터까지 생성하는 기능을 구현해 보자

    내비게이션 메시 시스템 설정

    이제 섹션의 스테이트 구현을 확인하고 NPC와 아이템 상자를 생성하는 기능을 추가한다.

    책과 동일하게 코드를 작성하고 설정을 하였으나 시작시 Section의 State가 Ready라서 다음 문으로 넘어가도 새로운 Section이 생기지 않는다. 문에 다가갔다가 다시 가운데로 들어오면 State가 Battle로 변경되면서 NPC와 ItemBox가 소환됨을 확인할 수 있었다.

    요약

    • 프로젝트 모듈 설정
    • 맵 단위인 섹터를 무한히 생성할수 있는 로직 구현
    • BoxCollision의 Overlapped 이벤트로 트리거 이벤트 발생
    • NPC와 ItemBox 생성 처리
    반응형

    댓글

    Designed by JB FACTORY