1. Transform 속성 이해하기
1-1. 액터의 트랜스폼
1) 위치(Location) : FVector(100.0f, 200.0f, 300.0f) x축, y축, z축의 순서.
2) 회전(Rotation) : FRotation(Pitch, Yaw, Roll) y축, z축, x축의 순서.
- Pitch : 앞뒤 방향으로 기울어짐 (y축 회전)
- Roll : 좌우로 기울어짐 (x축 회전)
- Yaw : 좌우 방향 회전 (z축 회전)
3) 스케일(Scale) : FVector(X, Y, Z) 형태로 표현되며, 하나의 인자만 넣으면 3개의 인자가 같이 적용된다.
1-2. FTransfom
: 위치, 회전, 스케일을 하나로 묶어 효율적으로 관리하기 위한 구조체.
- FTransform의 세 가지 요소
- Translation : 위치를 표현한느 FVector
- Rotation : 회전을 표현하는 FRotator
- Scale3D : 스케일을 표현하는 FVector
FVector NewLocation(300.0f, 200.0f, 100.0f);
FRotator NewRotator(0.0f, 90.0f, 0.0f);
FVector NewScale(0.0f, 90.0f, 0.0f);
FTransform NewTransform(NewRotator, NewLocation, NewScale); // 회전 -> 위치 -> 크기 순서
SetActorTransform(NewTransform); // 트랜스폼 세 가지를 한꺼번에 관리하는 방법.
1-3. 좌표계의 개념
- 월드좌표계(World Space)
- 게임 전체 세계를 기준으로 한 절대적인 좌표계.
- SetActorLocation(), GetActorLocation() 처럼 액터 자체를 이동 회전 스케일 할 때 대부분 월드 좌표계를 기준으로 한다.
- 로컬좌표계(Local Space)
- 액터 자신이나 부모 액터 (또는 부모 컴포넌트)의 Transform을 기준으로 한 상대적인 좌표계.
- 계층 구조 (부모-자식 관계)가 있는 경우, 자식은 부모의 Transform에 종속되어 움직인다.
1-4. 부모-자식 컴포넌트 관계
- 액터에는 여러 컴포넌트가 붙을 수 있으며, 최상위에 있는 루트 컴포넌트를 기준으로 다른 컴포넌트들이 Attach관계를 맺을 수 있다.
- 부모 액터가 이동 회전 스케일되면 자식들은 상대 좌표값에 따라 함께 이동한다.
- 부모-자식 관계가 맺어져 있다면,
- GetRelativeTranform() : 부모 기준의 상대 위치, 회전, 스케일을 가져옴.
- SetRelativeLocation(), SetRelativeRotation() : 부모 기준으로 자식의 위치, 회전을 조정.
- 이처럼 로컬 좌표계를 적절히 활용하면, 여러 컴포넌트를 한꺼번에 움직이거나, 특정 컴포넌트만 부모 기준으로 움직이게 만들 수 있다.
2. C++ 코드로 Transform 다루기
2-1. Transform 조정 함수
- SetActorLocation(FVector NewLocation) : 액터 위치 이동
- SetActorRotation(FRotator NewRotation) : 액터 회전
- SetActorScale3D(FVector NesScale) : 액터 스케일 변경
- GetActorLocation(), GetActorRotation(), GetActorScale3D() : 현재 Transform정보 가져오기
- SetActorTransform(FTransform NewTransform) : 위치, 회전, 스케일을 한 번에 설정.
- SetActorScale3D(FVector(2.0f))와 같이 스케일 값을 통일하면, 모든 축 (x, y, z)이 같은 비율로 확대·축소된다.
void AItem::BeginPlay()
{
Super::BeginPlay();
SetActorScale3D(FVector(2.0f, 4.0f, 3.0f));
SetActorLocation(FVector(0.0f, 0.0f, 20.0f));
SetActorRotation(FRotator(2.0f, 1.0f, 1.5f));
}
이렇게 입력하면 게임이 시작될 때 액터의 Transform이 변경된다.
3. Tick 함수와 프레임 독립적인 로직 이해하기
3-1. 게임 프레임 업데이트와 Tick
- 언리얼 엔진은 게임 실행 중 매 프레임마다 여러 작업을 수행한다.
- 1) 렌더링 : 화면 그리기 (일반적으로 1초에 60프레임, 120프레임 등)
- 2) 물리 연산 : 충돌 중력 마찰 등 물리 엔진 처리
- 3) 오브젝트 업데이트 : 게임 내 액터들의 상태 갱신
- 특정 액터가 '매 프레임마다' 수행할 로직이 있다면, 언리얼 엔진은 그 액터의 Tick(float DeltaTime) 함수를 매 프레임 호출해준다.
3-2. Tick 함수 활성화하기
- Tick() 함수를 사용하려면, 아래와 같이 생성자에서 설정해야 한다.
PrimaryActorTick.bCanEverTick = true;
- bCanEverTick가 false면 엔진은 성능 최적화를 위해 해당 액터의 Tick을 호출하지 않는다.
- 불필요한 Tick 호출은 성능에 부담을 줄 수 있으므로, 사용하지 않는다면 false를 명시해주어 최적화 코드 명확성을 높인다.
3-3. DeltaTime
- Tick(float DeltaTime) 함수에서 DeltaTime은 '직전 프레임부터 현재 프레임까지 걸린 시간(초)'.
- 60 FPS 환경 : DeltaTime = 1/60초 = 0.0167초
- 120 FPS 환경 : DeltaTime = 1/120초 = 0.0083초
- 프레임 레이트가 높을수록 DeltaTime이 작아지고, 낮을수록 DeltaTime이 커진다.
3-4. DeltaTime을 활용한 프레임 독립적인 움직임
- 단순히 '매 프레임마다 X 좌표를 1씩 증가' 시키면, FPS가 높을수록 더 빨리 움직여 게임 체감 속도가 달라진다.
- 이를 방지하려면, DeltaTime을 곱해서 초 단위 기준으로 이동 회전을 계산해야 한다.
- 이렇게 하면 어느 FPS 환경에서도 동일한 실제 속도를 유지할 수 있다.
4. Tick 함수와 DeltaTime을 활용한 회전 구현하기
4-1. DeltaTime을 활용한 프레임 독립적인 움직임
헤더 파일
float RotationSpeed;
virtual void Tick(float DeltaTime) override;
// cpp파일
// 생성자에 추가
PrimaryActorTick.bCanEverTick = true; // Tick함수 활성화
RotationSpeed = 90.0f; // 회전속도 (1초에 90도씩 회전)
void AItem::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// RotationSpeed가 0이 아니라면 회전 처리
if (!FMath::IsNearlyZero(RotationSpeed))
{
// 초당 RotationSpeed만큼, 한 프레임당 (RotationSpeed * DeltaTime)만큼 회전
AddActorLocalRotation(FRotator(0.0f, RotationSpeed * DeltaTime, 0.0f));
}
- FMath::IsNearZero( ) : 부동소수점 비교에서 안전하게 0에 가까운지 확인해주는 함수.
- AddActorLocalRotation( ) : 액터의 로컬 기준으로 회전을 추가해주는 함수.
- 만약 월드 좌표 기준으로 회전하고 싶다면 AddActorWorldRotation().
'언리얼엔진5 공부' 카테고리의 다른 글
| 언리얼엔진 C++ 챕터2 - 1. Character_클래스를_활용한_캐릭터_구현하기 (2) | 2025.09.19 |
|---|---|
| 언리얼엔진 C++ 챕터1 - 5. C++ 클래스와 리플렉션 시스템 활용하기 (0) | 2025.09.18 |
| 언리얼엔진 C++ 챕터1 - 3. Actor의 라이프 사이클 이해하기 (2) | 2025.09.16 |
| 언리얼엔진 C++ 챕터1 - 2. Actor 클래에 컴포넌트 추가하기 (0) | 2025.09.15 |
| 언리얼엔진 C++ 챕터1 - 1. 액터 소스파일의 기본 구성 (0) | 2025.09.03 |