오늘 언리얼 C++ 과제로 서로 다른 액터 클래스 2개를 구현하고,
UPROPERTY 리플렉션을 사용하여 Tick 기반으로 이동 및 회전 로직을 구현했다
MyActor01(MoveActor) - X축을 왕복으로 이동하는 액터
MyActor02(SpinActor) - Z축으로 회전하는 액터
블루프린트 자식 클래스 생성
Tick(float DeltaTime) 기반으로 Transform 변경
이동 로직, 회전 로직 구현
UPROPERTY로 통한 에디터에서 값 조정
// MyActor01.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyActor01.generated.h"
UCLASS()
class UNREALCPPPROJECT06_API AMyActor01 : public AActor
{
GENERATED_BODY()
public:
AMyActor01();
protected:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "MoveActor|Component")
USceneComponent* SceneRootComp; // RootComponent 생성
// StaticMeshComponent를 생성하고, 에디터에서 메시를 지정할 수 있도록 설정
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MoveActor|Component")
UStaticMeshComponent* StaticMeshComp;
virtual void BeginPlay() override;
virtual void Tick(float DeltaTime) override;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "MoveActor|Location")
FVector StartLocation; // 시작 지점
// 이동 방향, 속도, 왕복 범위 에디터 및 블루프린트에서 값 변경할 수 있게 설정
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MoveActor|Location")
float MoveDirection; // 이동 방향
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MoveActor|Location", meta = (ClampMin = "0.0"))
float LocationSpeed; // 이동 속도
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MoveActor|Location", meta = (ClampMin = "0.0"))
float MaxRange; // 최대 왕복 범위
UFUNCTION(BlueprintCallable, Category = "MoveActor|LocationFunction")
void MoveActor(float DeltaTime); // 이동 함수
UFUNCTION(BlueprintCallable, Category = "MoveActor|LocationFunction")
void CheckRange(); // 범위 체크 함수
};
// MyActor01.cpp
#include "MyActor01.h"
AMyActor01::AMyActor01()
{
// Tick 함수 사용
PrimaryActorTick.bCanEverTick = true;
// Scene Component 생성 및 RootComponent로 지정
SceneRootComp = CreateDefaultSubobject<USceneComponent>(TEXT("Scene Component"));
SetRootComponent(SceneRootComp);
// StaticMesh Component 생성 및 RootComponent에 부착
StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh Component"));
StaticMeshComp->SetupAttachment(SceneRootComp);
// 이동 기본값 설정
LocationSpeed = 300.0f; // 이동 속도
MaxRange = 2000.0f; // 왕복 범위
MoveDirection = 1.0f; // 이동 방향
}
void AMyActor01::BeginPlay()
{
Super::BeginPlay();
// 시작 위치 저장(왕복 기준 위치)
StartLocation = GetActorLocation();
}
void AMyActor01::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// 속도가 0이 아니면 실행
if (!FMath::IsNearlyZero(LocationSpeed))
{
MoveActor(DeltaTime);
CheckRange();
}
}
void AMyActor01::CheckRange() // 범위 체크 함수
{
// 현재 위치 가져오기
FVector RangeCurrentLocation = GetActorLocation();
// 시작 위치 기준 거리 계산
// FVector::Dist를 사용해 시작 위치와 현재 위치 사이의 거리를 계산
float Distance = FVector::Dist(StartLocation, RangeCurrentLocation);
// 최대 범위를 넘으면 방향 바꾸기
if (Distance >= MaxRange)
{
MoveDirection *= -1.0f;
}
}
void AMyActor01::MoveActor(float DeltaTime) // 이동 함수
{
// 현재 위치 가져오기
FVector MoveCurrentLocation = GetActorLocation();
// x축 방향으로 이동 (속도 * 방향 * DeltaTime)
MoveCurrentLocation.X += LocationSpeed * MoveDirection * DeltaTime;
// 계산한 위치 적용
SetActorLocation(MoveCurrentLocation);
}
// MyActor02.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyActor02.generated.h"
UCLASS()
class UNREALCPPPROJECT06_API AMyActor02 : public AActor
{
GENERATED_BODY()
public:
AMyActor02();
protected:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "MoveActor|Component")
USceneComponent* SceneRootComp; // RootComponent 생성
// StaticMeshComponent를 생성하고, 에디터에서 메시를 지정할 수 있도록 설정
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MoveActor|Component")
UStaticMeshComponent* StaticMeshComp;
virtual void BeginPlay() override;
virtual void Tick(float DeltaTime) override;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "MoveActor|Location")
FVector StartLocation; // 시작 지점
// 에디터 및 블루프린트에서 회전 속도 값 변경 가능하게 설정
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MoveActor|Rotation", meta = (ClampMin = "0.0"))
float RotationSpeed; // 회전 속도
UFUNCTION(BlueprintCallable, Category = "MoveActor|LocationFunction")
void SpinActor(float DeltaTime); // 회전 함수
};
// MyActor02.cpp
#include "MyActor02.h"
AMyActor02::AMyActor02()
{
// Tick 함수 사용
PrimaryActorTick.bCanEverTick = true;
// Scene Component 생성 및 RootComponent로 지정
SceneRootComp = CreateDefaultSubobject<USceneComponent>(TEXT("Scene Component"));
SetRootComponent(SceneRootComp);
// StaticMesh Component 생성 및 RootComponent에 부착
StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh Component"));
StaticMeshComp->SetupAttachment(SceneRootComp);
// 회전 기본값 설정
RotationSpeed = 45.0f; // 회전 속도
}
void AMyActor02::BeginPlay()
{
Super::BeginPlay();
// 시작 위치 저장
StartLocation = GetActorLocation();
}
void AMyActor02::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// 회전 속도가 0이 아니면 실행
if (!FMath::IsNearlyZero(RotationSpeed))
{
SpinActor(DeltaTime);
}
}
void AMyActor02::SpinActor(float DeltaTime) // 회전 함수
{
// Yaw(z축) 기준 회전 (회전 속도 * DeltaTime)
AddActorLocalRotation(FRotator(0.0f, RotationSpeed * DeltaTime, 0.0f));
}
언리얼 에디터에서 블루프린트 클래스를 열려고 하니,
Blueprint could not be loaded because it derives from an invalid class 오류가 떴다.
블루프린트 클래스를 생성하고 C++ 클래스의 이름을 변경하였는데 그게 원인 같아서 확인 해보니 이름을 변경해서 블루프린트 클래스가 부모 C++ 클래스를 찾지 못해서 뜨는 오류가 맞았고,
다시 연결 해보려고 부모 클래스 변경을 찾아봤지만 목록에 내가 만든 C++ 클래스가 없어서 그냥 기존 블루프린트 클래스를 삭제하고, C++ 클래스로 다시 상속받을 블루프린트 클래스를 생성해주어서 문제를 해결하였다.
처음에 아래 코드처럼 Tick에서 SetActorLocation을 사용하여 이동 로직을 구현했다.
SetActorLocation(FVector(LocationSpeed * DeltaTime, 0.0f, 0.0f));
실행해보니 제자리에서 순간이동을 해버려서 이게 뭐지 싶어가지고 확인을해봤더니,
SetActorLocation은 절대 좌표를 설정하는 함수였다.
그래서 현재 위치에 이동량을 더하는 방식으로 수정했더니 잘 작동이 되었다.
// 변수를 생성해서 현재 액터의 위치를 저장
FVector MoveCurrentLocation = GetActorLocation();
// 기존 위치 x축에 설정해놓은 속도와 DeltaTime을 곱한 값을 더해줌
MoveCurrentLocation.X += LocationSpeed * MoveDirection * DeltaTime;
// 계산된 위치를 액터에 적용
SetActorLocation(MoveCurrentLocation);
SetActorLocation은 이동이 아니라 위치 설정 함수이기 때문에,
이동을 구현할 때는 현재 위치를 기준으로 값을 더해줘야 한다.
이번 과제를 통해 Tick 함수와 DeltaTime, SetActorLocation의 동작 방식을 어느정도 이해 하였고,
특히 이동 로직을 구현할 때는 절대 좌표를 설정하는 것이 아니라,
현재 위치를 기준으로 값을 누적해야 한다는 점을 확실히 알게 되었다.
| Pawn 클래스 3D 캐릭터 만들기 (0) | 2026.04.14 |
|---|---|
| Unreal C++ 기초 5. GameMode와 Character 클래스를 활용해서 캐릭터 구현하기 (2) | 2026.04.09 |
| Unreal C++ 기초 4. 로그, 리플렉션, 함수, 리플렉션 (0) | 2026.04.07 |
| Unreal C++ 기초 3. 컴포넌트 멤버 변수 추가 및 메시, 머티리얼 할당 (1) | 2026.04.06 |
| Unreal C++ 기초 2. Migrate, 클래스 생성 및 삭제 (0) | 2026.04.06 |