카테고리 없음

Unreal 응용반 분반수업 4차 내용정리

view29579 2026. 9. 17. 20:19

 


1. ControlRotation 복습

PlayerController는 플레이어가 바라보거나 조준하고 있는 방향을 ControlRotation으로 가지고 있다.

bUseControllerRotationYaw

APawn에 있는 옵션이다.

true로 설정하면 Pawn의 Yaw가 Controller의 ControlRotation.Yaw를 따라간다.

ControlRotation.Yaw
        ↓
Character Actor Yaw

주로 캐릭터가 카메라 또는 조준 방향을 따라가야 하는 경우 사용한다.

예:

  • FPS
  • TPS 조준 모드
  • 캐릭터와 조준 방향을 일치시키는 방식

bUseControllerDesiredRotation

UCharacterMovementComponent의 옵션이다.

활성화하면 CharacterMovement가 Controller의 방향을 목표 회전 방향으로 사용한다.

이때 RotationRate를 이용해서 캐릭터가 즉시 회전하지 않고 점진적으로 회전한다.

ControlRotation
      ↓
목표 회전 방향
      ↓
RotationRate
      ↓
Character 회전

bOrientRotationToMovement

UCharacterMovementComponent의 옵션이다.

활성화하면 캐릭터가 Controller가 바라보는 방향이 아니라 이동 방향을 기준으로 회전한다.

이동 방향
   ↓
Character 회전

3인칭 일반 이동에서 자주 사용하는 방식이다.


RotationRate

CharacterMovementComponent가 캐릭터를 회전시키는 속도이다.

예:

MovementComponent->RotationRate = FRotator(0.0f, 240.0f, 0.0f);

Yaw 방향으로 초당 240도 회전하도록 설정할 수 있다.


2. SpringArm의 bUsePawnControlRotation

SpringArm이 Pawn의 Control Rotation을 카메라 방향에 사용할지 결정하는 옵션이다.

PlayerController
      ↓
ControlRotation
      ↓
SpringArm
      ↓
Camera

따라서 마우스를 움직였을 때 카메라가 Controller의 회전을 따라가게 만들 때 사용할 수 있다.


3. UObject와 Actor

UObject

UObject는 Unreal Object System의 기본이 되는 클래스이다.

일반 C++ 객체와 다르게 Unreal의 객체 관리 시스템을 사용할 수 있다.

일반적인 C++ 객체:

FMyData* Data = new FMyData();
delete Data;

UObject 계열:

UMyObject* MyObject = NewObject<UMyObject>(this);

UObject는 Unreal의 Garbage Collection 시스템과 연결되어 관리된다.


Outer

Outer는 UObject가 어떤 객체에 속해 있는지를 나타내는 관계이다.

NewObject<UMyObject>(this);

여기서 this는 새로 만들어지는 UObject의 Outer가 된다.

Outer는 UObject의 객체 계층과 소속 관계를 이해할 때 중요하다.


Actor

AActor는 UObject를 상속받은 클래스이다.

차이점은 Actor는 월드에 존재할 수 있는 객체라는 것이다.

Actor는 위치, 회전, 크기 등의 Transform을 가지고 월드에 배치되거나 Spawn될 수 있다.

GetWorld()->SpawnActor<AMyActor>();

Actor는 단순히 C++ 객체 하나를 생성하는 것이 아니라 Unreal의 월드와 연결되어야 하기 때문에 SpawnActor() 등을 통해 생성한다.


4. Actor의 생명주기

Actor는 대략 다음과 같은 흐름으로 동작한다.

Actor 생성
   ↓
Construction
   ↓
Component 초기화
   ↓
BeginPlay
   ↓
GamePlay
   ↓
EndPlay
   ↓
World에서 제거
   ↓
Garbage Collection

C++에서 작성한 기본 설정과 Blueprint에서 작성한 로직의 실행 순서도 고려해야 한다.

따라서 모든 로직을 단순히 같은 시점에 실행된다고 생각하면 예상과 다른 결과가 발생할 수 있다.

기본 생성자

기본 생성자에서는 주로

  • 기본값 설정
  • Component 생성

등을 작성한다.

Construction

에디터에서 Actor의 값이 변경되었을 때 갱신되는 과정에서 많이 사용된다.

게임 시작 후 실행해야 하는 로직은 일반적으로 BeginPlay()에서 처리한다.

PostInitializeComponents

Actor의 Component 초기화가 완료된 후 호출된다.


5. Destroy

Destroy()는 C++의 delete와 다르다.

Destroy();

이것은 Actor를 즉시 메모리에서 직접 삭제하는 것이 아니라 World에서 제거하는 과정을 시작하는 것이다.

이후 EndPlay 등의 과정이 진행되고 실제 UObject 메모리 정리는 Unreal의 Garbage Collection 시스템이 담당한다.

따라서 Actor에 대해 직접:

delete MyActor;

하는 방식은 사용하지 않는다.


6. UObjectPtr

UObject 계열 객체를 참조할 때 Unreal의 객체 관리 시스템과 함께 안전하게 사용하기 위해 TObjectPtr를 사용할 수 있다.

예:

UPROPERTY()
TObjectPtr<UMyObject> MyObject;

특히 Unreal의 UPROPERTY()와 함께 객체 참조를 관리할 때 중요하다.

객체가 유효한지 확인해야 하는 상황에서는 IsValid() 등의 방법을 사용할 수 있다.


7. Actor의 Owner

Actor에는 다른 Actor를 Owner로 지정할 수 있다.

Weapon->SetOwner(PlayerCharacter);

그러면 Weapon에서:

AActor* OwnerActor = GetOwner();

를 통해 자신의 Owner를 확인할 수 있다.

Owner가 없다면 nullptr이 반환될 수 있으므로 예외 처리가 필요하다.

if (!OwnerActor)
{
    return;
}

Owner에서 주의할 점

Owner는 C++에서 말하는 메모리 소유권과 같은 의미가 아니다.

또한 Attachment와도 다르다.

Owner
→ Gameplay / Network 관계

Attachment
→ Transform 부모-자식 관계

예를 들어 총을 캐릭터 손 Socket에 붙이는 것과 총의 Owner를 캐릭터로 지정하는 것은 서로 다른 개념이다.

총을 캐릭터 손에 Attach하면서 Owner도 캐릭터로 설정할 수 있지만, 둘은 각각 다른 목적을 가진다.

특히 Multiplayer에서는 Actor의 Owner 관계가 RPC, Replication 등의 동작과 관련되기 때문에 중요하다.


8. V키를 이용한 Control Mode 전환

V키를 눌렀을 때 카메라와 캐릭터의 컨트롤 방식을 변경하는 시스템을 만들었다.

컨트롤 모드를 Enum으로 구분한다.

UENUM(BlueprintType)
enum class EPlayerControlMode : uint8
{
    ThirdPerson UMETA(DisplayName = "Third Person"),
    FirstPerson UMETA(DisplayName = "First Person"),
    TopDown UMETA(DisplayName = "Top Down"),
    Shoulder UMETA(DisplayName = "Shoulder / Aim")
};

Enum을 사용하는 이유는 여러 모드를 명확하게 구분하고, 이후 모드가 추가되더라도 관리하기 쉽도록 하기 위해서이다.


9. ChangeControlMode와 ApplyControlMode

두 함수를 분리해서 사용했다.

void ChangeControlMode();

→ 다음에 어떤 모드로 변경할지 결정

void ApplyControlMode(
    EPlayerControlMode NewControlMode
);

→ 선택된 모드의 실제 설정을 적용

책임을 나누면 함수 하나가 너무 많은 역할을 담당하지 않게 된다.

컨트롤 모드 변경 흐름은 다음과 같다.

ThirdPerson
    ↓
FirstPerson
    ↓
TopDown
    ↓
Shoulder
    ↓
ThirdPerson

10. 컨트롤 모드별 설정

Third Person

Camera
→ SpringArm 사용
→ Controller Rotation 사용

Character
→ Controller Yaw 직접 사용 X
→ 이동 방향으로 회전

주요 설정:

bUseControllerRotationYaw = false;
bOrientRotationToMovement = true;
bUseControllerDesiredRotation = false;

First Person

Camera
→ Character 머리 위치

Character
→ Controller Yaw를 따라감

주요 설정:

bUseControllerRotationYaw = true;
bOrientRotationToMovement = false;
bUseControllerDesiredRotation = false;

Top Down

Camera
→ 높은 위치에서 내려다봄

Character
→ 이동 방향으로 회전

주요 설정:

bUseControllerRotationYaw = false;
bOrientRotationToMovement = true;
bUseControllerDesiredRotation = false;

Shoulder / Aim

Camera
→ Character 오른쪽 어깨 방향
→ Controller Rotation 사용

Character
→ Controller Yaw를 따라감

주요 설정:

bUseControllerRotationYaw = true;
bOrientRotationToMovement = false;
bUseControllerDesiredRotation = false;

11. 예외 처리의 중요성

C++ 코드를 작성할 때 정상적인 상황만 생각하지 않고 객체가 존재하지 않는 상황도 고려해야 한다.

예:

if (!MovementComponent || !CameraBoom || !FollowCamera)
{
    return;
}

이런 방어 코드를 추가하면 필요한 객체가 준비되지 않았을 때 바로 접근해서 문제가 발생하는 것을 막을 수 있다.

앞으로 AI에게 코드를 요청할 때도 예외 처리와 방어 코드가 필요한 부분을 함께 확인해 달라고 요청하는 습관을 가지는 것이 좋다.


12. 이번 주 복습 포인트

이번 주에는 다음 내용을 다시 확인했다.

  • 이동 구현
  • 마우스 회전
  • ControlRotation
  • PlayerController
  • bUseControllerRotationYaw
  • bUseControllerDesiredRotation
  • bOrientRotationToMovement
  • RotationRate
  • SpringArm::bUsePawnControlRotation
  • UObject와 Actor의 차이
  • UObject의 생명주기
  • Actor의 생명주기
  • Destroy()와 C++ delete의 차이
  • TObjectPtr
  • Actor Owner와 Attachment의 차이
  • Enum을 이용한 Control Mode 분리
  • Third Person / First Person / Top Down / Shoulder Mode
  • 함수의 책임 분리
  • C++ 방어 코드와 예외 처리
  • 기획서에 맞춰 컨트롤 모드를 수정하는 과정

느낀 점

오늘은 단순히 캐릭터를 움직이는 것에서 끝나는 것이 아니라, Controller → ControlRotation → Character / Movement → Camera가 어떻게 연결되는지 다시 정리할 수 있었다.

또한 UObject, Actor, Owner처럼 Unreal에서 자주 사용하지만 서로 헷갈리기 쉬운 개념들을 복습하면서, 단순히 코드를 따라 작성하는 것보다 각 객체와 기능이 어떤 역할을 담당하는지 이해하는 것이 중요하다는 점을 다시 확인했다.

웨이브 시스템에서는 웨이브가 끝났을 때 남아있는 악몽을 기준으로 침대 Stress를 증가시키고 HUD의 악몽 수를 초기화하는 기능까지 연결했다.