[이득우 언리얼 C++] 2. 액터의 설계

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

    언리얼 컨텐츠의 구성요소

    월드

    언리얼 엔진의 가상 공간을 월드(world)라고 부른다. 월드에는 다음과 같은 요소가 제공된다.

    • 공간(Space) : 가상 세계를 구성하는 3차원의 영역을 의미. 트랜스폼(Transform) 구조체를 제공하며 단위는 cm이다.
    • 시간(Time) : 가상 공간에서 흐르는 시간 단위는 초 단위. 멈추거나 느리게 혹은 빠르게 속도를 조절할 수 있다.
    • 물리(Physics) : 월드 공간에 있는 오브젝트에 작용하는 물리적인 환경. 대표적으로 중력이 있다. 물리적 영향을 받기 위해서는 콜리전(Collision)정보가 있어야 한다.
    • 렌더링(Rendering) : 엔진이 제공하는 시각적인 기능. 빛과 머터리얼로 구성되며 물리기반 렌더링(PBR) 시스템을 제공한다.

    이외 월드의 기능을 확인하려면 세팅 > 월드 세팅 메뉴를 눌러 확인해보자

    액터

    액터(Actor)는 언리얼 엔진에서 콘텐츠를 구성하는 최소 단위의 물체(Object)이다. 액터들의 목록은 월드 아웃라이너 창에서 확인할 수 있으며, 선택한 액터의 속성은 디테일 창에서 확인할 수 있다. 액터는 다음과 같은 요소로 구성된다.

    • 이름 : 액터에 부여된 이름이다. 중복될 수있다.
    • 유형 : 액터의 역할을 의미한다. 프로그래밍 관점에선 액터 클래스 이름이다.
    • 트랜스폼 : 액터는 반드시 월드에 존재해야 하므로 액터는 항상 트랜스폼을 가지고 있다.
    • 프로퍼티 : 액터에 설정된 속성 값이다. 디테일 창에서 값을 수정 할 수 있다.
    • 게임로직 : 액터가 특정 상황에서 행동을 하는것을 의미한다. 블루프린트 또는 C++ 코드로 구현한다.

    레벨

    플레이어에게 주어지는 스테이지를 의미한다. 레벨은 월드에 배치된 액터들의 집합이다.

    컴포넌트

    액터의 주요 기능은 크게 세가지로 나눌 수 있다.

    • 시각적 기능 : 플레이어에게 보여지는 부분
    • 물리적 기능 : 액터의 이동과 액터간의 상호 동작 부분
    • 움직임 : 액터의 움직임

    액터를 설계할 때 각 기능을 규격화 하고 액터가 이들을 조합할 수 있도록 설계하였다. 이런 규격화된 기능을 컴포넌트(Component)라고 한다. 엔진에서 제공하는 주요 컴포넌트는 다음과 같다.

    • 스태틱메시 컴포넌트 (StaticMesh Component) : 애니메이션이 없는 모델링 애셋인 스태틱 메시를 사용하여 시각적 기능과 물리적 기능을 제공하는 모듈. 주로 배경 물체에 사용
    • 스켈레탈메시 컴포넌트 (SkeletalMesh Component) : 애니메이션 정보가 있는 모델링 애셋인 스켈레탈 메시를 사용해 시각적인 기능과 애니메이션, 그리고 캐릭터의 물리 기능을 제공하는 모듈. 주로 캐릭터에 사용
    • 콜리전 컴포넌트(Collision Component) : 구/박스/캡슐형태로 지정한 영역에 물리적인 기능을 설정하기 위해 제공하는 모듈, 시각적인 기능은 없다.
    • 카메라 컴포넌트(Camera Component) : 가상 세계에서 보여지는 현재 상황을 플레이어의 모니터 화면에 출력해주는 기능
    • 오디오 컴포넌트(Audio Component) : 가상 세계에서 소리를 발생시키는 데 사용하는 기능
    • 파티클 시스템 컴포넌트(Particle System Component) : 파티클 시스템으로 설계된 이펙트를 화면에 보여주기 위한 기능
    • 라이트 컴포넌트(Light Component) : 전구, 헤드라이트 등과 같은 물체에 광원 효과를 부여하는 기능
    • 무브먼트 컴포넌트(Movement Component) : 물체에 특정한 움직임을 부여하는 기능

    액터는 여러개의 컴포넌트를 가질수 있으며, 그 중 하나를 대표 컴포넌트로 지정해야한다 이를 루트 컴포넌트(Root Component)라고 한다.

    액터의 설계

    1장에서 생성한 Fountain 액터 클래스에 분수대를 만들어보자. 분수대 구조물과 물 두가지 요소로 구성될 것이다. Fountain.h 파일에 AFountain 클래스에서 UStaticMeshComponent* 의 변수 Body와 Water를 추가하였다. 그리고 변수 선언 위에 UPROPERTY 매크로를 지정하였다. UPROPERTY 매크로는 선언한 객체를 자동으로 관리하게 지정한다. UPROPERTY는 언리얼 오브젝트 객체에만 사용할 수 있다.

    • 클래스 선언 매크로: 클래스가 언리얼 오브젝트임을 선언하기 위함. UCLASS 매크로와 GENERATED_BODY 매크로를 선언한다.
    • 클래스 이름 접두사: 접두사는 크게 U와 A가 제공되는데 A는 액터 클래스이고, U는 액터가 아닌 클래스에 사용한다.
    • generated.h 헤더 파일: 소스 코드를 컴파일하기 이전에 언리얼 엔진은 언리얼 헤더 툴(Unreal Header Tool) 이라는 도구를 사용해 부가적인 정보를 별도의 파일에 생성된다. 해당 파일이 generated.h 파일이다. 언리얼 오브젝트 선언의 마지막 #include 구문에 이 헤더파일을 반드시 선언 해야 한다.
    • 외부 모듈에 공개 여부: 윈도우 DLL시스템은 DLL 내 클래스 정보를 외부에 공개할지 결정하는 _declspec(dllexport)라는 키워드를 제공한다. 언리얼 엔진에서 이 키워드를 사용하려면 모듈명_API라는 키워드를 선언 앞에 추가한다. 이 키워드가 없으면 다른 모듈에서 해당 객체에 접근할 수 없다.
    • CreateDefaultSubobject API함수를 통해 컴포넌트를 생성한다.
    • RootComponent를 Body로 Water를 Body의 자식 컴포넌트로 지정한다.

    에디터에서 컴파일을 하고 Fountain 액터를 레벨에 배치해보면 책과는 다르게 컴포넌트 목록에 Body만 존재한다.

    액터와 에디터 연동

    UPROPERTY 안에 VisibleAnyWhere 지정자를 추가해보자

    Body와 Water가 제대로 나온것을 확인 할 수 있다. 네이티브 컴포넌트는 트리구조까지 숨김 처리 되어있는 듯 하다. 또한 컴포넌트가 편집이 가능하게 되었다.

    이제 스태틱메시 컴포넌트에 스태틱메시 애셋을 지정하여 분수대를 표현해보자. Body와 Water에 애셋을 지정하였고 높이를 조정하여 분수대가 올바르게 보이도록 하였다.

    • 액터가 공중에 있을경우 End 키를 이용하여 바닥에 붙일 수 있다.
    • 액터 기능의 확장

    Water 컴포넌트의 Z축 위치를 수동으로 설정하지 않도록 코드에서 기본값을 설정해보자. Water 컴포넌트에 SetRelativeLocation함수를 사용하여 기본 위치값을 변경할 수 있다.

    다음으로 조명과 이펙트르 추가하였다. 조명은 UPointLightComponent 클래스를, 이펙트는 UParticleSystemComponent 클래스를 사용하였다.

    빌드 후 에디터에서 예제 이펙트를 적용하였고 분수대를 완성하였다

    객체 유형과 값 유형

    언리얼 오브젝트 클래스의 포인터는 대표적인 객체 유형이다. 그리고 언리얼 엔진이 제공하는 대표적인 값 유형은 다음과 같다.

    • 바이트 : uint8
    • 정수 : int32
    • 실수 : float
    • 문자열 : FString, FName
    • 구조체 : FVector, FRotator, FTransform

    값유형으로 멤버 변수를 선언하고 UPROPERTY를 지정하면 선언만으로도 기본값이 지정된다. 0의 초기값을 보장 받는다. 기존 객체 유형의 경우 VisibleAnywhere 를 사용해도 속성을 편집할수 있다. 엄밀히 말해서 객체를 선택할 수 있는것이지 객체자체를 편집할 수는 없다. 값유형의 경우 VisibleAnywhere로 지정하면 값을 수정할수 없는 상태로 보여진다. 데이터를 변경하려면 EditAnywhere 지정자를 사용하면 된다. 추가적으로 UPROPERTY 매크로 지정자 중 Category=분류명 을 추가하면 지정한 분류에서 속성값을 관리할 수 있다.

    애셋의 지정

    에디터에서 애셋을 지정하지 않고 C++코드에서 애셋이 자동으로 로딩되록 해보자. 스태틱메시 애셋을 우클릭하여 레퍼런스를 복사하거나 Ctrl+C로 복사하여 코드에 붙여넣기를 해보자

    StaticMesh'/Game/InfinityBladeGrassLands/Environments/Plains/Env_Plains_Ruins/StaticMesh/SM_Plains_Castle_Fountain_01.SM_Plains_Castle_Fountain_01'

    다음과 같은 규칙을 확인할 수 있다.

    {오브젝트타입}'{폴더명}/{파일명},{애셋명}'

    • 오브젝트 타입 : 애셋의 타입
    • 폴더명/파일명 : 물리적인 애셋의 경로 정보. 다른 애셋과 중복될 수 없는 유일한 값
    • 애셋명 : 에디터에서 보여지는 애셋의 이름. 중복될 수 있다.

    C++ 코드에서 애셋을 불러오기위해서는 ConstructorHelpers 클래스의 FObjectFinder를 사용하여 변수를 설정한다. 또한 애셋의 경로 정보는 게임도중 변경될 일이 없기 때문에 불필요한 지역변수를 생성하는것을 막기위해 static으로 선언한다.

    이제 에디터에 액터를 드래그해서 생성만 해도 자동으로 완성된 분수대가 배치됨을 확인할 수 있다.

    요약

    • C++ 코드에서 액터의 컴포넌트를 추가
    • 에디터에서 컴포넌트를 설정
    • C++ 코드에서 애셋을 지정
    반응형

    댓글

    Designed by JB FACTORY