프로젝트 이름은 BullettimeFPS라고 정했다. 심플한 FPS장르에 플레이어들이 제한된 게이지를 소모하여 월드의 시간을 느리게 할 수 있는 능력을 갖도록 하고 싶기 때문이고 (슈퍼 핫 같은 느낌), 이것이 일반적인 FPS 게임과 차별점이 될 것이다.

 

에픽 게임즈에서 제공하는 FirstPerson 템플릿을 사용하여 프로젝트를 시작하려 한다. 그렇기 때문에 우선 이 템플릿의 코드를 분석하는 것부터 시작하기로 했다. 6개의 소스 파일 (헤더포함하면 12개)이 기본적으로 생성된다.

 

BullettimeFPS

BullettimeFPSCharacter

BullettimeFPSGameMode

BullettimeFPSProjectile

TP_PickUpComponent

TP_WeaponComponent

 

BullettimeFPS

IMPLEMENT_PRIMARY_GAME_MODULE 매크로를 사용하여 primary 모듈을 등록 (FDefaultGameMoudleImpl)

 

여러 모듈을 사용할 경우 IMPLEMENT_GAME_MODULE 매크로를 사용하여 모듈들을 추가할 수 있고, 모듈들은 [게임명]\Source[모듈명] 디렉터리 아래에 들어가게 되는데 이 샘플 프로젝트는 primary 모듈만을 사용하기 때문에 Source 디렉터리만 존재한다.

 

게임 전용 모듈을 추가할 때는 모듈에 대한 .Build.cs 파일을 만들고, 이 모듈에 대한 레퍼런스를 게임의 Target.cs 파일에 추가하면 된다. 이렇게 하면 언리얼 빌드 툴이 자동으로 모듈을 발견하여 부가 게임 DLL 파일을 컴파일한다.

 

BullettimeFPSCharacter, BP_FirstPersonCharacter

ACharacter를 상속받는다.

블루프린트 BP_FirstPersonCharacter가 이 클래스를 상속받아 메시 설정 (블루프린트 에디터에서 설정해야 함)

SkeletalMeshComponent : 1인칭 시점에서 보일 팔

CameraComponent : Character에 기본적으로 달려있는 Capsule 컴포넌트에 SetupAttachment로 카메라 컴포넌트를 붙인다.

SetupPlayerInputComponent (Pawn의 인터페이스) : Project setting > Input 에 설정된 Binding과 동작을 매핑

Dynamic multicast 델리게이트가 선언되어 있다(FOnUseItem) : 아이템을 

 

BullettimeFPSGameMode

AGameModeBase를 상속받는다. (AGameMode는 AGameModeBase의 자식 클래스인데 멀티플레이어 슈팅게임 환경에는 AGameMode가 적합다고 한다. 그렇기 때문에 이후 AGameMode를 상속받도록 전환하겠다)

FClassFinder를 사용하여 BP_FirstPersonCharacter를 찾고, DefaultPawnClass 프로퍼티에 등록한다.

 

의문점

게임 Play 시 Spawn되는 액터들은 누가 생성해주는가?

outliner에 노랑색 텍스트로 표시되는 액터들은 게임 시작과 동시에 spawn된다.

 

액터 간 종속 관계를 조사해봤더니 이런 형태이다.

 

AGameModeBase의 생성자 부분 : 엔진이 초기화 되는 런타임 과정에서 GameModeBase의 생성자에 의해 CDO가 생성된다. 이후 변경되지 않는다.

 

UObject 인스턴스 생성 시 생성자 호출은 발생하지만, 생성자 코드가 사용되지 않고 모듈 로딩 중 초기화된 CDO 값이 스폰될 액터에 복사된다.

 

DefaultPawnClass, PlayerControllerClass .. 들이 전부 TSubclassOf 템플릿 자료형으로 정의되어 있는데, 왜 그런 것인지

찾아보았다.  

TSubClassOf는 UClass 타입의 안정성을 보장해 주는 템플릿 클래스라고 한다. (UClass* 대신에) TSubClassOf 템플릿을 사용하면 에디터에서 특정 클래스의 파생 클래스만 선택할 수 있도록 제한할 수 있다. 

 

리플렉션 (프로퍼티 시스템)

리플렉션은 C++에서 지원하지 않기 때문에 언리얼에서 자체적으로 지원하는 시스템이다.

프로그램이 실행 시간에 자기 자신(객체 정보)을 조사하는 기능 이라고 한다.

 

Unreal Build Tool (UBT)는 마킹된 헤더가 최소 하나 들어있는 모듈들을 기억하고, 그 헤더들 중 지난 컴파일 이후 업데이트 된 헤더가 있다면 UHT를 다시 실행한다. UBT는 또한 현재 프로젝트의 폴더 구조와 소스 파일들을 분석해 작업하는 플랫폼(윈도우, 맥)에 맞는 개발 도구 환경(윈도우는 Visual studio)을 자동으로 생성해준다.

 

헤더파일 상단에 #include "파일이름.generated.h"를 추가해주면 해당 헤더 파일에 리플렉션이 있는 유형으로 마킹한다.

이제 헤더 파일에 U로 시작하는 매크로(UCLASS, UFUNCTION, UPROPERTY 등) 를 사용하여 함수나 멤버 변수, 클래스를 리플렉션 시스템에 보이게 할 수 있다.

 

Unreal Header Tool (UHT)는 프로젝트 컴파일 이전에 리플렉션 시스템에 보이는 유형들을 수집한다. 

UHT는 언리얼 관련 클래스 메타데이터에 대한 C++ 헤더를 파싱하고 Intermediate 폴더에 .generated.h, .gen.cpp 와 같은 코드(메타 헤더 파일, 메타 소스 파일)를 생성해준다. 메타 정보들은 UClass라는 특별한 클래스를 통해 보관된다.

 

컴파일 단계에서는 개별 언리얼 오브젝트(UObject) 마다 UClass가 생성되고 (UClass의 인스턴스가 생성되는 것은 아님)

실행 초기의 런타임 과정에서는 하나의 언리얼 오브젝트마다 UClass 인스턴스와 CDO(Class Default Object) 인스턴스가 생성된다.

CDO는 클래스 생성자에 의해 생성된 후 변경되지 않는다. 이후 추가되는 인스턴스는 CDO를 통해 복제되어 생성된다.

 

이렇게 추가된 언리얼 오브젝트들은 에디터에서 편집할 수 있게 되고 런타임에서 관리할 수 있게 된다.

 

참조: 

https://www.youtube.com/watch?v=VpEe9DbcZIs 

 

https://blog.naver.com/destiny9720/220934112532

 

[1-5] 클래스 기본 객체 (Class Default Object)

안녕하세요 여러분~ 이번 강좌에서는 하나의 모듈에서 다른 모듈을 참조하는 기능을 구현해보겠습니다. 모...

blog.naver.com

 

BullettimeFPSProjectile (포물체)

총을 줍고 마우스 왼클릭을 했을 때 발사되는 포물체들에 적용되는 코드이다.

포물선의 움직임을 제어하는 ProjectileMovementComponent가 있다. 속도, 최대속도 등의 옵션을 설정할 수 있다.

Collision 컴포넌트를 가지고 있는데, 이 컴포넌트가 가지고 있는 델리게이트(OnComponentHit)에 이 클래스에서 만든 OnHit 메서드를 등록한다. OnHit 이벤트는 물리 시뮬레이션이 적용된 다른 액터와 충돌하면 그 액터에 힘을 가하고 자기 자신은 Destroy하도록 한다.

 

TP_PickUpComponent, TP_WeaponComponent, BP_Rifle

두 컴포넌트는 블루프린트 액터 (BP_Rifle)에 컴포넌트로 추가되어 있다.

게임 시작시 플레이어가 총을 들고 있는 것이 아니라 근처로 가서 주워야 하기 때문에 PickUpComponent가 붙었고, 

총을 주운 이후 좌클릭을 했을 때 발사체를 생성하고, 사운드 효과를 주기 위해 WeaponComponent가 붙었다.

 

앞서 설명한 클래스들은 액터를 상속받았기 때문에 클래스 이름에 접두사 A가 붙었지만, 이 클래스들은 컴포넌트를 상속받고 있기 때문에 (각각 USphereComponent와 UActorComponent를 상속받는다) 접두사 U가 붙는다.

 

PickUpComponent의 상위 클래스인 SphereComponent의 상위 클래스인 PrimitiveComponent에 정의된 OnComponentBeginOverlap 델리게이트에 OnSphereBeginOverlap라는 이름의 사용자 정의 함수를 등록시킨다.

OnSphereBeginOverlap에서는 OnPickUp 이라는 델리게이트를 BroadCast 시킨다.

OnPickUp 델리게이트는 ABullettimeFPSCharacter* 자료형의 인자를 하나 받는 함수를 등록할 수 있는데, 이 샘플에서는 BP_Rifle 블루프린트의 이벤트 그래프에서 TP_WeaponComponent의 AttachWeapon함수를 연결시킴으로써 등록한다.

 

일인칭 템플릿에 대한 공식 Docs

https://docs.unrealengine.com/5.0/ko/first-person-template-in-unreal-engine/

 

일인칭 템플릿

언리얼 엔진의 일인칭 템플릿에 대해 소개합니다.

docs.unrealengine.com

+ Recent posts