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은 해당 프레임의 처리만 건너뛰는 구조다
'내배캠 TIL' 카테고리의 다른 글
| [내배캠 TIL 260129] Unreal Cast는 무엇이고 왜 필요한가 (0) | 2026.01.29 |
|---|---|
| [내배캠 TIL 260123] Unreal Engine Collision 정리 (0) | 2026.01.23 |
| [내배캠 TIL 260120] Unreal Pawn 클래스로 캐릭터 Move 구현 (0) | 2026.01.20 |
| [내배캠 TIL 260116] Unreal PlayerController 와 Input Mapping Context (0) | 2026.01.16 |
| [내배캠 TIL 260112] Unreal Timer를 활용한 액터 생성 (0) | 2026.01.13 |