[Unreal] Unreal Engine C++ Day3 - Actor Transform과 Tick, DeltaTime 정리
오늘 진행한 내용
오늘은 언리얼 엔진 C++에서 액터의 위치, 회전, 크기를 코드로 변경하는 방법을 정리했다. 또한 게임이 실행되는 동안 매 프레임 호출되는 Tick() 함수와 프레임 독립적인 움직임을 만들기 위해 사용하는 DeltaTime에 대해 공부했다.
처음에는 액터를 한 번 배치하는 것과 매 프레임 움직이는 것의 차이가 조금 헷갈렸지만, BeginPlay()는 게임 시작 시 한 번 실행되는 초기 설정, Tick()은 게임 실행 중 계속 반복되는 업데이트라고 생각하니 이해하기 쉬웠다.
1. Actor Transform 변경 함수
언리얼에서 액터의 위치, 회전, 크기를 합쳐서 Transform이라고 한다. 액터의 Transform은 다음 함수들을 사용해 변경하거나 가져올 수 있다.
SetActorLocation(FVector NewLocation): 액터 위치 이동SetActorRotation(FRotator NewRotation): 액터 회전 변경SetActorScale3D(FVector NewScale): 액터 스케일 변경GetActorLocation(): 현재 위치 가져오기GetActorRotation(): 현재 회전값 가져오기GetActorScale3D(): 현재 스케일 가져오기SetActorTransform(FTransform NewTransform): 위치, 회전, 스케일을 한 번에 설정
여기서 주의할 점은 함수 이름이 SetActorLocation이라는 것이다. 처음 정리할 때 etActorLocation처럼 앞의 S가 빠질 수 있는데, 실제 코드에서는 반드시 SetActorLocation으로 작성해야 한다.
2. BeginPlay()에서 Transform 설정하기
BeginPlay()는 액터가 월드에 배치되고 초기화가 끝난 뒤 자동으로 호출되는 함수다. 이 함수 안에서 위치, 회전, 스케일을 설정하면 게임이 시작될 때 해당 Transform이 적용된다.
void AItem::BeginPlay()
{
Super::BeginPlay();
// (300, 200, 100) 위치로 이동
SetActorLocation(FVector(300.0f, 200.0f, 100.0f));
// Yaw 방향으로 45도 회전
SetActorRotation(FRotator(0.0f, 45.0f, 0.0f));
// 모든 축을 2배로 스케일
SetActorScale3D(FVector(2.0f));
}
FVector(300.0f, 200.0f, 100.0f)는 X, Y, Z 위치를 의미한다. FRotator(0.0f, 45.0f, 0.0f)는 Pitch, Yaw, Roll 회전값을 의미한다. 위 코드에서는 Yaw 값이 45이므로 좌우 방향으로 45도 회전하게 된다.
SetActorScale3D(FVector(2.0f))처럼 값을 하나만 넣으면 X, Y, Z 축이 모두 같은 값으로 설정된다. 즉, 모든 축이 2배 크기로 확대된다.
3. 숫자 뒤에 f가 붙는 이유
언리얼 C++ 코드에서 300.0f, 45.0f, 2.0f처럼 숫자 뒤에 f를 붙이는 경우가 많다. 이는 해당 숫자를 float 타입으로 사용하겠다는 의미다.
300.0 // double 타입
300.0f // float 타입
언리얼의 FVector, FRotator 등은 float 기반 값을 많이 사용하기 때문에 실수 값을 작성할 때 f를 붙여주는 습관을 들이면 좋다.
4. 에디터에서 Transform 확인하기
빌드 후 언리얼 에디터에서 플레이하면 코드로 설정한 Transform이 적용된다. Outliner에서 Item 액터를 선택한 뒤 Details 패널을 보면 Location, Rotation, Scale 값이 변경된 것을 확인할 수 있다.
즉, C++ 코드에서 설정한 값이 실제 에디터의 Transform 값과 연결되어 있다는 것을 확인할 수 있었다.
5. 게임 프레임 업데이트와 Tick
언리얼 엔진은 게임이 실행되는 동안 매 프레임 여러 작업을 수행한다.
- 렌더링(Rendering): 화면 그리기
- 물리 연산: 충돌, 중력, 마찰 등 물리 엔진 처리
- 오브젝트 업데이트: 게임 내 액터들의 상태 갱신
특정 액터가 매 프레임마다 수행해야 하는 로직이 있다면 언리얼 엔진은 그 액터의 Tick(float DeltaTime) 함수를 호출한다. 예를 들어 아이템이 계속 회전하거나, 캐릭터가 계속 이동하거나, 시간에 따라 상태가 변해야 한다면 Tick()을 사용할 수 있다.
6. Tick을 사용하기 위한 설정
액터에서 Tick()을 사용하려면 생성자에서 다음 설정을 해줘야 한다.
PrimaryActorTick.bCanEverTick = true;
bCanEverTick이 false라면 엔진은 성능 최적화를 위해 해당 액터의 Tick()을 호출하지 않는다.
하지만 모든 액터가 Tick을 사용할 필요는 없다. 매 프레임 호출되는 함수이기 때문에 불필요하게 사용하면 성능에 부담이 될 수 있다. 따라서 매 프레임 처리할 로직이 없다면 false로 두는 것이 좋다.
7. DeltaTime이란?
Tick(float DeltaTime)에서 DeltaTime은 직전 프레임부터 현재 프레임까지 걸린 시간이다. 단위는 초(second)다.
- 60 FPS 환경:
DeltaTime ≈ 1 / 60초 ≈ 0.0167초 - 120 FPS 환경:
DeltaTime ≈ 1 / 120초 ≈ 0.0083초
FPS가 높을수록 한 프레임에 걸리는 시간이 짧기 때문에 DeltaTime은 작아진다. 반대로 FPS가 낮을수록 한 프레임에 걸리는 시간이 길어져 DeltaTime은 커진다.
8. DeltaTime을 사용한 회전
아래 코드는 아이템 액터를 매 프레임 회전시키는 예시다.
void AItem::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
AddActorLocalRotation(FRotator(0.0f, RotationSpeed * DeltaTime, 0.0f));
}
여기서 RotationSpeed는 초당 회전 속도라고 볼 수 있다. RotationSpeed * DeltaTime을 사용하면 FPS가 달라져도 실제 시간 기준으로는 같은 속도로 회전하게 된다.
정확히 말하면 프레임마다 회전하는 양은 컴퓨터 성능이나 FPS에 따라 달라진다. 하지만 DeltaTime을 곱했기 때문에 1초 동안 회전하는 총량은 일정하게 유지된다.
9. DeltaTime을 사용해야 하는 이유
만약 단순히 매 프레임마다 X 좌표를 1씩 증가시키면 FPS가 높은 환경에서 더 빠르게 움직인다. 60 FPS에서는 1초에 60번 이동하고, 120 FPS에서는 1초에 120번 이동하기 때문이다.
// FPS에 따라 속도가 달라질 수 있는 방식
AddActorWorldOffset(FVector(1.0f, 0.0f, 0.0f));
이를 방지하려면 이동 속도에 DeltaTime을 곱해야 한다. 예를 들어 초당 100만큼 이동하고 싶다면 다음처럼 작성할 수 있다.
float MoveSpeed = 100.0f;
AddActorWorldOffset(FVector(MoveSpeed * DeltaTime, 0.0f, 0.0f));
이렇게 하면 FPS가 달라도 실제 시간 기준 이동 속도는 동일하게 유지된다.
- 60 FPS: 한 프레임당 약 1.67 이동, 60프레임 동안 총 100 이동
- 120 FPS: 한 프레임당 약 0.83 이동, 120프레임 동안 총 100 이동
오늘 헷갈렸던 점
처음에는 Tick()이 매 프레임 호출된다는 말 때문에 사용자 컴퓨터 사양에 따라 움직임이 무조건 달라진다고 생각했다. 하지만 DeltaTime을 곱하면 프레임마다 적용되는 값은 달라져도 초당 움직이는 양은 같게 만들 수 있다는 것을 알게 되었다.
또한 BeginPlay()와 Tick()의 역할 차이도 중요했다. BeginPlay()는 게임 시작 시 한 번 실행되는 초기 설정에 적합하고, Tick()은 게임이 실행되는 동안 계속 변해야 하는 로직에 적합하다.
오늘 배운 것
- 액터의 위치, 회전, 스케일을 Transform이라고 한다.
SetActorLocation(),SetActorRotation(),SetActorScale3D()로 액터 Transform을 변경할 수 있다.BeginPlay()는 액터가 게임에 들어온 뒤 한 번 호출된다.Tick()은 매 프레임 호출되는 함수다.PrimaryActorTick.bCanEverTick = true를 설정해야 Tick을 사용할 수 있다.DeltaTime은 직전 프레임부터 현재 프레임까지 걸린 시간이다.DeltaTime을 곱하면 FPS가 달라도 같은 속도로 움직이게 만들 수 있다.
느낀 점
오늘은 단순히 액터를 움직이는 코드처럼 보였지만, 실제로는 게임이 매 프레임 어떻게 실행되는지와 연결된 내용이었다. 특히 Tick()과 DeltaTime은 앞으로 이동, 회전, 애니메이션, 전투 효과 같은 기능을 만들 때 계속 사용하게 될 것 같다.
처음에는 DeltaTime이 왜 필요한지 잘 와닿지 않았는데, FPS가 높은 컴퓨터와 낮은 컴퓨터에서 같은 속도를 유지하기 위한 장치라고 생각하니 이해가 됐다. 게임 개발에서는 코드가 실행되는 횟수보다 실제 시간이 더 중요할 때가 많다는 것을 배웠다.
한 문장 요약
오늘은 언리얼 C++에서 액터의 Transform을 코드로 변경하는 방법과, Tick(), DeltaTime을 이용해 FPS와 상관없이 일정한 움직임을 만드는 방법을 배웠다.
'[Unreal Engine C++]' 카테고리의 다른 글
| [Unreal] Unreal Engine C++Day6 - 캐릭터 애니메이션 구현과 카메라 문제 해결 (0) | 2026.08.18 |
|---|---|
| [Unreal] Unreal Engine C++ Day5 - .generated.h와 리플렉션 매크로 이해하기 (0) | 2026.08.13 |
| [Unreal] Unreal Engine C++ Day4 - 회전·왕복 이동 플랫폼과 Blueprint 리플렉션 (0) | 2026.08.12 |
| [Unreal] Unreal Engine C++ Day2 - Item Actor 구조, 컴포넌트 연결, 생명주기 로그 정리 (0) | 2026.08.10 |
| [Unreal] Unreal Engine C++ Day1 - 프로젝트 구조와 빌드 방식, UObject와 Actor 이해하기 (0) | 2026.08.07 |