본문 바로가기

게임 개발 공부/언리얼엔진

UE5 | C++개발학습 - 리플렉션 시스템

C++에서 단순하게 액터를 생성하면 언리얼 에디터에 액터를 배치할 수 있지만, 에디터에서 옵션을 수정하는건 아직 불가능하다.

그걸 가능하게 하기 위해선 리플렉션 시스템에 액터와 변수, 함수를 등록해주어야 한다.

 

 

1. 리플렉션 시스템(Reflection System)

 - 여러 매크로를 이용해 C++과 언리얼 에디터 간에서 상호적인 작업이 가능하도록 해주는 시스템

 

2. 매크로

 - 전처리기를 통해 매크로에 지정된 코드로 치환해주는 기능

 

3. 리플렉션 시스템 매크로 종류

 - 리플렉션 시스템엔 다양한 매크로 종류가 있으나 오늘은 액터 클래스에서 사용할 만한 매크로만 짚어보겠다.

  •   UCLASS() : 해당 클래스에서 리플렉션 시스템 작업을 하겠다는 것을 명시하는 매크로.
                          플래그 미기입 시 기본 속성플래그가 자동으로 입력된다. (Blueprintable, BlueprintType)
    -  주요 속성 플래그
      - Blueprintable : 블루프린트에서 클래스를 기반으로 새 블루프린트를 생성할 수 있음. 기본 활성화된 플래그.
      - NotBlueprintable : 블루프린트에서 클래스를 기반으로 새 블루프린트를 생성할 수 없도록 제한. 
      - BlueprintType : 블루프린트에서 변수를 만들거나 참조할 수 있음. 주로 UObject 기반 클래스에 사용
      - NotBlueprintType : 블루프린에서 변수를 만들거나 참조할 수 없음.

  • GENERATED_BODY() : UCLASS로 등록 후 리플렉션 데이터를 자동으로 생성하는 매크로
     
  • UPROPERTY() : 바로 다음 기입된 변수를 리플렉션 시스템에 등록시킨다. 플래그를 입력해줘야 에디터상에서
                                변수가 보여지거나 수정할 수 있다.
    - 주요 속성 플래그
      - VisibleAnywhere : 에디터에서 값을 볼 수 있지만 수정은 불가능
      - VisibleInstanceOnly : 인스턴스에서만 값을 볼 수 있음 (수정 불가)
      - VisibleDefaultsOnly : 클래스 디폴트에서만 값을 볼 수 있음 (수정 불가)
      - EditAnywhere : 에디터 어디서든 값을 수정할 수 있음
      - EditInstanceOnly : 인스턴스에서만 값을 수정 가능
      - EditDefaultsOnly : 클래스 디폴트에서만 값을 수정 가능
      - BlueprintReadWrite : 블루프린트에서 읽기/쓰기 모두 가능
      - BlueprintReadOnly : 블루프린트에서 읽기만 가능
      - BlueprintAssignable : 블루프린트에서 이벤트를 바인딩할 수 있음(주로 DECLARE_DYNAMIC_MULTICAST_DELEGATE와 함께 사용)
      - BlueprintCallable : 블루프린트에서 호출 가능(주로 함수 관련)
      - BlueprintAuthorityOnly : 서버에서만 블루프린트 호출 가능
    더보기
    DECLARE_DYNAMIC_MULTICAST_DELEGATE :
    여러개의 함수를 바인딩할 수 있으며 바인딩된 모든 함수들을 동시에 호출하는 기능을 제공
      - Category : 에디터에서 속성을 표시할 카테고리 지정 ( Category = "")

  • UFUNCTION() : 바로 다음 기입된 함수를 리플렉션 시스템에 등록시킨다. 플래그를 입력해줘야 에디터상에서
                                함수를 호출하거나 사용할 수 있다.
    - 주요 속성 플래그
      - BlueprintCallable : 블루프린트에서 이 함수를 호출할 수 있음
      - BlueprintPure : 블루프린트에서 이 함수의 값만 받을 수 있음
      - BlueprintImplementableEvent : C++에서 구현하지 않고 블루프린트에서 구현하는 함수. C++에서 호출 가능
      - Category = "" : 에디터상의 세부정보창에서 이 함수를 표시할 섹션을 정의
     
더보기

- 클래스 디폴트 : 클래스의 기본 형태. 컨텐츠 브라우저에 위치한다.
- 클래스 인스턴스 : 클래스 디폴트를 레벨에 배치하면 클래스의 인스턴스가 배치된다. 

 

4. 작성 방법 

//예시
UCLASS()
===클래스선언
{
GENERATED_BODY()

protacted:

UPROPETY(EditAnywhere, BlueprintReadWrite, Category = "Components")
int value;

UFUNCTION(BlueprintCallable, Category = "Actions")
void ResetActorPosition();
};

 

필요에 따라 작성하면 이런식으로 에디터에서 설정이 가능해진다.

 

 

5. 기타 배운 것들

언리얼의 회전축 명칭

- X : Roll

- Y : Pitch

- Z : Yaw

SetActorRotation() 값 입력 시  Y, Z, X 순서

 

짐벌 락(Gimbal Lock)

- 3축 회전의 약점. 축이 돌고 돌다 모두 겹쳐버리면 축값을 변경해도 한 축으로만 회전한다.

- 이를 보완하기 위한 쿼터니언이라는 방식이 존재한다.

 

월드 좌표과 로컬 좌표의 차이

- 월드 좌표는 월드 기준 액터 그 자체의 좌표. 로컬 좌표는 각 컴포넌트 기준의 개별 좌표

  자동회전을 구현할때 자전은 로컬, 공전은 월드를 사용하는게 적절하다.

 

Tick()
- 프레임마다 신호를 보낸다.
- 프레임이 각각 다른 환경에선 다른 결과값이 나온다.

DeltaTime
- Tick함수는 항상 Tick(float DaltaTime)으로 사용해야한다.
- Tick함수의 환경별 차이점을 보완하기 위해 프레임당 시간값을
 구해주는 엔진 자체의 인자.
- Tick함수에 기반한 트랜스폼 작업에선 항상 변화할 인자에
  DeltaTime을 곱해줘야한다. (프레임독립적)

FMath::IsNearlyZero(vari)
- 언리얼에서 제공해주는 기본함수
- 0에 아주 근접하면 0으로 계산하는 함수
- 부동소수는 정확히 떨어지는 값이기 어렵기 때문에
  미세한 차이는 무시해주는 기능

PrimaryActorTick.bCanEverTick = true;
-Tick을 켜주는 함수

스케일 지속변화
- 위치와 회전은 엔진에서 상대값으로 처리한다.
 그래서 Add를 사용하면 자연스레 현재값에 추가값을 더한다.

- 크기는 엔진에서 절대값으로 처리한다.  그래서 Add를 사용하면 Add값을 현재 크기값으로 덮어버린다.
  따라서 지속변화를 주려면 현재값을 직접 불러와서 Add값을 더한 후 입력해줘야한다.
- 절대값으로 처리하는 이유는 크기는 얼마가 더 커졌냐 보단 지금 크기가 얼마냐로 다루는게 더 직관적이기 때문이다.