내배캠 TIL

[내배캠 TIL 260121] UnrealEngine 블루프린트와 C++ 우선순위, 맵 저장 오류, 카메라 회전 직접 구현

xodn246 2026. 1. 21. 20:53

1. 블루프린트와 C++ 처리 우선순위

언리얼 엔진에서 C++과 블루프린트는 병렬 관계가 아니라 계층 구조를 가진다.
C++ 클래스는 기본값을 정의하는 역할을 하고, 블루프린트는 그 위에서 값을 덮어쓰는 구조다.

한 번이라도 블루프린트에서 값이 저장되면 이후 C++ 코드를 수정해도 블루프린트 값이 우선 적용된다.

대표적인 예시는 다음과 같다.

  • bUseControllerRotationYaw
  • SpringArm의 bUsePawnControlRotation
  • Camera 관련 옵션
  • CharacterMovement 설정

이 때문에 C++에서 값을 변경했는데 에디터를 재시작하면 이전 상태로 돌아온 것처럼 보이는 경우가 많다.
실제로는 블루프린트에 저장된 값이 다시 적용된 것이다.

해결 방법은 다음 중 하나다.

  • 블루프린트의 Details 패널에서 직접 값 수정
  • Reset to Default 사용
  • 블루프린트 삭제 후 재생성

2. 맵(.umap) 저장 오류의 원인

플레이는 정상적으로 되지만 맵 저장 시 다음과 같은 오류가 발생하는 경우가 있다.

Error saving 'M_MainLevel.umap'

이 현상의 대부분은 블루프린트 참조 문제에서 발생한다.

주요 원인

첫 번째는 깨진 블루프린트 참조다.
삭제되었거나 컴파일되지 않는 C++ 클래스를 부모로 가진 블루프린트, 또는 컴파일 에러가 남아 있는 블루프린트가 맵에 배치된 경우 저장에 실패한다.

두 번째는 컴포넌트 구조 변경이다.
C++에서 RootComponent 구조를 변경했지만 기존 블루프린트에 이전 컴포넌트 정보가 남아 있으면 DefaultSceneRoot 또는 Outer 참조 오류가 발생할 수 있다.

세 번째는 에디터 캐시 문제다.
Hot Reload를 반복하거나 빌드가 꼬인 상태에서 에디터를 오래 사용하면 저장 오류가 발생할 수 있다.

해결 방법 정리

  • 문제되는 블루프린트 열어서 컴파일 에러 확인
  • 블루프린트 Reparent 또는 재생성
  • 에디터 종료
  • Saved, Intermediate, Binaries 폴더 삭제
  • Visual Studio에서 클린 빌드
  • 에디터 재실행 후 다시 저장

플레이는 되는데 저장이 안 된다면 블루프린트 참조부터 의심하는 것이 가장 빠르다.


3. 카메라 회전을 직접 구현한 이유

언리얼에서는 다음과 같은 기본 회전 함수를 제공한다.

  • AddControllerYawInput
  • AddControllerPitchInput

하지만 Pawn 기반 구현이나 회전 로직을 직접 제어해야 하는 상황에서는 이 함수들을 사용하지 않고 직접 계산하는 방식이 필요하다.

이 방식은 다음과 같은 경우에 유용하다.

  • Pawn을 사용한 캐릭터 구현
  • 감도, 반전, 제한 로직을 직접 관리해야 하는 경우
  • 입력과 회전 구조를 정확히 이해하기 위한 학습 목적

4. 카메라 회전 직접 구현 방식

핵심은 Actor나 Camera를 직접 회전시키는 것이 아니라 Controller의 ControlRotation을 수정하는 것이다.

void APawn::Look(const FInputActionValue& Value)
{
	if (!Controller) return;

	FVector2D Input = Value.Get<FVector2D>();

	FRotator ControlRot = Controller->GetControlRotation();
	ControlRot.Yaw   += Input.X * Sensitivity;
	ControlRot.Pitch += Input.Y * Sensitivity;
	ControlRot.Pitch = FMath::Clamp(ControlRot.Pitch, -80.f, 80.f);

	Controller->SetControlRotation(ControlRot);
}

이 방식은 이동 방향, 에임, 카메라 회전을 일관되게 유지할 수 있다.


5. Look 입력과 DeltaTime

마우스 Look 입력에는 DeltaTime을 사용하지 않는다.
마우스 입력 값은 이미 프레임 간 이동량으로 보정된 값이기 때문이다.

반면 이동이나 자동 회전처럼 시간에 따라 누적되는 동작에는 반드시 DeltaTime을 사용해야 한다.

정리하면 다음과 같다.

  • 마우스 입력 기반 회전은 DeltaTime 불필요
  • 이동, 자동 회전, 보간 처리에는 DeltaTime 필요

6. IsNearlyZero와 Early Return

if (Input.IsNearlyZero()) return;

이 코드는 입력이 거의 없는 경우 해당 프레임의 로직을 즉시 종료하기 위한 처리다.

이 return은 캐릭터 상태를 변경하지 않는다.
단지 그 프레임의 이동 또는 회전 계산을 수행하지 않을 뿐이다.

이를 통해 다음과 같은 효과를 얻을 수 있다.

  • 불필요한 연산 제거
  • 미세한 입력 노이즈 방지
  • 코드 가독성 향상

7. 오늘 정리

  • 언리얼에서는 C++보다 블루프린트가 우선 적용된다
  • C++ 변경 사항이 적용되지 않으면 블루프린트 설정을 먼저 확인해야 한다
  • 맵 저장 오류는 대부분 블루프린트 참조 문제다
  • Pawn에서도 카메라 회전은 Controller 기준으로 구현해야 한다
  • Look 입력에는 DeltaTime을 사용하지 않는다
  • Early Return은 해당 프레임의 처리만 건너뛰는 구조다