게임 개발/학습 일지

언리얼 C++ - Tick 함수로 Actor의 Transform 조정하기

이개 2026. 4. 11. 22:14

언리얼에서는 왜 물체 rotation에 Roll, Pitch, Yaw라는 용어를 사용할까?

👉 비행기 기준으로 3축 회전을 정의한 용어라서
👉 Roll / Pitch / Yaw라고 부름

✈️ 1️⃣ 어디서 나온 말이냐

항공공학에서 시작됨.

👉 비행기가 공중에서 움직일 때:

  • 좌우로 기울고
  • 위아래로 들리고
  • 방향을 바꾸고

👉 이걸 3가지 회전으로 정의한 것!

🎯 2️⃣ 각각 의미

🔹 Roll (롤)

👉 “좌우로 기울기”

  • 날개 기준 회전
  • 옆으로 눕는 느낌
왼쪽으로 기울기 / 오른쪽으로 기울기
 

🔹 Pitch (피치)

👉 “앞뒤로 들기”

  • 기수(코) 위/아래
위로 상승 / 아래로 하강
 

🔹 Yaw (요)

👉 “좌우 방향 회전”

  • 좌우로 방향 틀기
왼쪽으로 턴 / 오른쪽으로 턴

 

Transform 속성 이해하기

Actor와 Transform

  • Actor는 게임에 존재하는 모든 오브젝트를 의미
  • Transform은 액터의 3가지 속성
    • 위치(Location)
      • FVector(100.0f, 200.0f, 300.0f)라면 x축으로 100, y축으로 200, z축으로 300만큼 떨어진 위치
    • 회전(Rotation)
      • FRotator(Pitch, Yaw, Roll) 형태로 표현
        • Roll: 좌우로 기울어지는 회전(X축을 축으로 함)
        • Pitch: 앞뒤 방향으로 기울어지는 회전(Y축을 축으로 함)
        • Yaw: 좌우 방향 회전(z축을 축으로 하는 회전)
    • 크기(Scale)
      • FVector(2.0f, 2.0f, 2.0f)라면 x, y, z축 순으로 기본 크기의 2배를 의미하게 됨
      • 전부 같은 비율로 증가시키려면 FVector(2.0f)로 사용 가능

FTransform 자료형

언리얼 엔진에는 위치, 회전, 스케일을 하나로 묶은 구조체인 FTransform이 있다.

  • FTransform의 세 가지 요소
    • Translation: 위치를 표현하는 FVector
    • Rotation: 회전을 표현하는 FRotator
    • Scale3D: 스케일을 표현하는 FVector

액터를 배치하면 Detail에서 Transform 정보를 확인할 수 있다.

 

 

Transform 메서드

  • GetRelativeTransform(): 부모 기준의 상대 위치/회전/스케일을 가져옴
  • SetRelativeLocation(), SetRelativeRotation(): 부모 기준으로 자식의 위치/회전을 조정
  • SetActorLocation(FVector NewLocation) : 액터 위치 이동
  • SetActorRotation(FRotator NewRotation) : 액터 회전
  • SetActorScale3D(FVector NewScale) : 액터 스케일 변경
  • GetActorLocation() , GetActorRotation() , GetActorScale3D() : 현재 Transform 정보 가져오기 SetActorTransform(FTransform NewTransform) : 위치·회전·스케일을 한 번에 설정

 

코드 예시

void AItem::BeginPlay()
{
	Super::BeginPlay();
	SetActorLocation(FVector(300.f,200.f,100.f));
	SetActorRotation(FRotator(0.f,90.f,0.f)); // pitch, yaw, roll
	SetActorScale3D(FVector(2.0f, 2.0f, 2.0f)); // FVector(2.0f) 라고만 해도 됨

	FVector NewLocation(300.f, 200.f, 100.f);
	FRotator NewRotation(0.f, 90.f, 0.f);
	FVector NewScale(2.0f);
	FTransform NewTransform(NewRotation, NewLocation, NewScale);

	SetActorTransform(NewTransform); // 위쪽을 똑같이 구현한 것
}

 

 

 

Tick 함수와 프레임

언리얼 엔진은 게임 실행 중 매 프레임마다 여러 작업을 수행

  • 렌더링: 화면 그리기(일반적으로 1초에 60프레임, 120프레임 등
  • 물리 연산: 충돌/중력/마찰 등 물리 엔진 처리
  • 오브젝트 업데이트: 게임 내 액터들의 상태 갱신

특정 액터가 매 프레임마다 수행할 로직이 있다면, 언리얼 엔진은 그 액터의 Tick(float DeltaTime) 함수를 매 프레임 호출한다.

 

Tick 함수 활성화

Tick() 함수를 사용하려면, 생성자에서 설정해주어야한다.

PrimaryActorTick.bCanEverTick = true;

 

 

DeltaTime

  • Tick(float DeltaTime) 함수에서 DeltaTime은 직전 프레임부터 현재 프레임까지 걸린 시간이다.
    • 60FPS: DeltaTime은 1/60초, 즉 0.0167초 가량
    • 120FPS: DeltaTime은 1/120초, 즉 0.0083초 가량
  • 프레임 레이트가 높을수록 DeltaTime이 작아지고, 낮을수록 DeltaTime이 커진다.
  • FPS에 따라 게임 체감 속도가 달라지기 때문에, DeltaTime을 곱하여 평준화해주어야한다.
    • 초당 100만큼 이동하려면 100*DeltaTime을 매 프레임마다 더해줌
      • 60 FPS: 한 프레임당 1.67씩 이동, 60 프레임 곱하면 100
      • 120 FPS: 한 프레임당 0.83씩 이동, 120 프레임 곱하면 100

 

Tick과 DeltaTime을 활용한 회전 구현

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h" // 언리얼 엔진의 기본 타입
#include "GameFramework/Actor.h" // 액터에 대한 정보를 가지고 있는 헤더파일
#include "Item.generated.h" // 리플렉션 시스템에 관련한 헤더 파일

UCLASS() // 리플렉션 시스템에 등록해주는 키워드
class SPARTAPROJECT_API AItem : public AActor // A 접두어는 Actor계열이라는 의미이다. Object는 U, 구조체는 F, Enum은 E
{
	GENERATED_BODY() // UCLASS와 같은 역할의 매크로
	
public:	
	// Sets default values for this actor's properties
	AItem();

protected:
	USceneComponent* SceneRoot;
	UStaticMeshComponent* StaticMeshComp;

	float RotationSpeed;

	virtual void BeginPlay() override;
	virtual void Tick(float DeltaTime) override;
};
// Fill out your copyright notice in the Description page of Project Settings.
  
#include "Item.h"



// Sets default values
AItem::AItem()
{
	SceneRoot = CreateDefaultSubobject<USceneComponent>(TEXT("SceneRoot"));
	SetRootComponent(SceneRoot);

	StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
	StaticMeshComp->SetupAttachment(SceneRoot);


		static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshAsset(TEXT("/Game/Resources/Props/SM_Chair.SM_Chair"));
		if (MeshAsset.Succeeded())
		{
			StaticMeshComp->SetStaticMesh(MeshAsset.Object);
		}

		static ConstructorHelpers::FObjectFinder<UMaterialInterface> MaterialAsset(TEXT("/Game/Resources/Materials/M_Metal_Steel.M_Metal_Steel"));
		if (MaterialAsset.Succeeded())
		{
			StaticMeshComp->SetMaterial(0, MaterialAsset.Object);
		}

		PrimaryActorTick.bCanEverTick = true; // 사용을 안 한다면 false로 해놓기
		RotationSpeed = 90.0f;

}


void AItem::BeginPlay()
{
	Super::BeginPlay();
	SetActorLocation(FVector(300.f,200.f,100.f));
	SetActorRotation(FRotator(0.f, 90.f,0.f)); // pitch, yaw, roll
	SetActorScale3D(FVector(2.0f, 2.0f, 2.0f)); // FVector(2.0f) 라고만 해도 됨

	//FVector NewLocation(300.f, 200.f, 100.f);
	//FRotator NewRotation(0.f, 90.f, 0.f);
	//FVector NewScale(2.0f);
	//FTransform NewTransform(NewRotation, NewLocation, NewScale);

	//SetActorTransform(NewTransform);
}

void AItem::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	if (!FMath::IsNearlyZero(RotationSpeed)) // FMath::IsNearlyZero(float): float값의 오차를 보정하여 0에 근접한지 판단해주는 함수
	{
		AddActorLocalRotation(FRotator(0.0f, RotationSpeed * DeltaTime, 0.0f));
	}
}