DECLARE_LOG_CATEGORY_EXTERN(로그명, 로그레벨, All);
- 로그 카테고리 선언, 반드시 .h 파일에 선언
- 로그명 : 사용할 로그 이름(직접 정의)
- 로그레벨 - Log : 일반 로그, Display : 출력용, Warning : 경고, Error : 위험
- ALL : 로그 출력 허용 범위
DEFINE_LOG_CATEGORY(로그명);
- .h 파일에 선언한 로그 카테고리 실제로 생성
- .h 파일에만 선언하고 .cpp 파일에 선언 안하면 컴파일 에러
UE_LOG(로그명, 로그레벨, TEXT("%s 내용"), *GetName());
- TEXT("%s 내용") : 내용 입력(반드시 문자열 유니코드 처리)
- *GetName() : 현재 객체명 출력
// Item.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Components/AudioComponent.h"
#include "Item.generated.h"
// 로그 카테고리 선언
DECLARE_LOG_CATEGORY_EXTERN(LogSparta, Warning, All);
UCLASS()
class SPARTAPROJECT_API AItem : public AActor
{
GENERATED_BODY()
public:
AItem();
protected:
virtual void BeginPlay() override;
}
// Item.cpp
#include "Item.h"
// 로그 카테고리 생성
DEFINE_LOG_CATEGORY(LogSparta);
AItem::AItem()
{
}
void AItem::BeginPlay()
{
Super::BeginPlay();
// 로그 카테고리 출력
UE_LOG(LogSparta, Log, TEXT("%s BeginPlay"), *GetName());
UE_LOG(LogSparta, Display, TEXT("%s BeginPlay"), *GetName());
UE_LOG(LogSparta, Warning, TEXT("%s BeginPlay"), *GetName());
UE_LOG(LogSparta, Error, TEXT("%s BeginPlay"), *GetName());
}
Visual Studio에서 빌드 및 실행 > 툴 바 Windows 클릭 > Output Log 클릭(활성화) > 게임 시작 >
Output Log 창에서 Filter 클릭 > Show All 체크 해제 > Filters 클릭 > LogSparta(로그카테고리명) 검색 후 체크 > 로그 확인
액터 라이프 사이클이란
액터는 생성 > 실행 > 제거 과정을 거치며, 각 단계마다 여러 함수가 호출이 됨
Constructor(생성자) > PostInitializeComponents > BeginPlay > Tick > Destroyed > EndPlay
Constructor(생성자) - 객체가 메모리에 생성될 때 딱 한번 호출
PostInitializeComponents - 모든 컴포넌트가 완성된 직 후 호출됨. 컴포넌트끼리 데이터 주고받기, 상호작용
BeginPlay - 게임시작 또는 배치(Spawn) 직후 호출, 가장 많이 쓰이는 함수
Tick - 매 프레임마다 호출, 이동 회전 물리 처리 및 실시간 업데이트
Destroyed - 액터가 삭제 되기 직전에 호출, 게임 종료 및 레벨 전환시 생략될 수 있음
EndPlay - 게임 종료 및 파괴(Destroyed), 레벨 전환시 호출
// Item.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Item.generated.h"
// 로그카테고리 선언
DECLARE_LOG_CATEGORY_EXTERN(LogSparta, Warning, All);
UCLASS()
class SPARTAPROJECT_API AItem : public AActor
{
GENERATED_BODY()
public:
AItem();
protected:
USceneComponent* SceneRoot;
UStaticMeshComponent* StaticMeshComp;
// 라이프 사이클 함수 선언
virtual void PostInitializeComponents() override;
virtual void BeginPlay() override;
virtual void Tick(float DeltaTime) override;
virtual void Destroyed() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
};
// Item.cpp
#include "Item.h"
// 로그 카테고리 생성
DEFINE_LOG_CATEGORY(LogSparta);
AItem::AItem()
{ // 생성자 로그 출력
UE_LOG(LogSparta, Warning, TEXT("%s Constructor"), *GetName());
}
void AItem::PostInitializeComponents()
{
Super::PostInitializeComponents();
//PostInitializeComponents 로그 출력
UE_LOG(LogSparta, Warning, TEXT("%s PostInitializeComponents"), *GetName());
}
void AItem::BeginPlay()
{
Super::BeginPlay();
// BeginPlay 로그 출력
UE_LOG(LogSparta, Warning, TEXT("%s BeginPlay"), *GetName());
}
void AItem::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// Tick 함수는 매 프레임마다 호출되므로
// 여기서 로그를 찍으면 방대한 양의 메시지가 쌓일 수 있음.
// 필요시 디버깅용 코드만 간단히 작성하거나, 별도 조건을 걸어 사용.
}
void AItem::Destroyed()
{
// Destroyed 로그 출력, 삭제 후에는 출력이 생략될 수 있으니 삭제 전 확인
UE_LOG(LogSparta, Warning, TEXT("%s Destroyed"), *GetName());
Super::Destroyed();
}
void AItem::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
// EndPlay 로그 확인
UE_LOG(LogSparta, Warning, TEXT("%s EndPlay"), *GetName());
Super::EndPlay(EndPlayReason);
}
언리얼 엔진 게임 내에 존재하는 모든 오브젝트를 의미하며,
건물, 캐릭터, 아이템 등 눈에 보이는 모든 것 = 액터
액터의 중요한 세가지 속성 위치(Location), 회전(Rotation), 크기(Scale)가 있으며,
x축(빨간색), y축(초록색), z축(파란색) 으로 표시됩니다.
위치(Location)
- 액터가 월드의 어느 지점에 있는지 나타냄
- FVector(100.0f, 200.0f, 300.0f) 라면
월드의 x축으로 100, y축으로 200, z축으로 300만큼 떨어진 위치를 의미합니다.
회전(Rotation)
- 액터의 방향, 각도를 나타냄
- Roll(x축), Pitch(y축), Yaw(z축)으로 표현합니다
크기(Scale)
- 액터의 크기 비율
- FVector(X, Y, Z) 형태로 표현되며, FVector(2.0f, 2.0f, 2.0f) 는 기본 크기의 2배를 의미합니다.
월드 좌표계
- 게임 내 전체 기준으로 한 절대 좌표계
- SetActorLocation(), GetActorLocation() 처럼 액터의 Transform을 변경하면 대부분 월드 좌표계를 기준으로 합니다.
로컬 좌표계
- 액터 자신이나 부모 액터(또는 부모 컴포넌트)의 Transform을 기준으로 한 상대 좌표계
- 계층 구조(부모 - 자식 관계)가 있는 경우, 자식은 부모의 Transform을 기준으로 움직임
액터는 여러 컴포넌트를 가질 수 있으며,
최상위 컴포넌트(루트 컴포넌트)를 기준으로 다른 컴포넌트들이 Attach(부착) 관계를 맺을수 있습니다.
부모 액터의 Transform이 변경되면 자식 액터는 상대 좌표값에 따라 함께 이동합니다.
부모 - 자식 관계가 맺어져 있다면,
GetRelativeTransform() : 부모 기준의 상대 위치·회전·스케일을 가져옴
SetRelativeLocation() , SetRelativeRotation() : 부모 기준으로 자식의 위치, 회전을 조정
할 수가 있습니다.
로컬 좌표계를 이용하면 여러 컴포넌트를 한번에 움직이거나 특정 컴포넌트만 부모 기준으로 움직이게 만들 수 있습니다.
Transform 조정 함수
SetActorLocation(FVector NewLocation) : 액터 위치 이동
SetActorRotation(FRotator NewRotation) : 액터 회전
SetActorScale3D(FVector NewScale) : 액터 크기 변경
GetActorLocation() , GetActorRotation() , GetActorScale3D() : 현재 Transform 정보 가져오기
SetActorTransform(FTransform NewTransform) : 위치·회전·스케일을 한 번에 설정
// Item.cpp
void AItem::BeginPlay()
{
Super::BeginPlay();
// 위치, 회전, 스케일 설정하기
// (300, 200, 100) 위치로 이동
SetActorLocation(FVector(300.0f, 200.0f, 100.0f));
// Yaw 방향(z축)으로 45도 회전
SetActorRotation(FRotator(0.0f, 45.0f, 0.0f));
// 모든 축을 2배로 스케일
SetActorScale3D(FVector(2.0f));
}
위치, 회전, 크기를 하나로 묶어서 관리하기 위한 구조체
Translation - 위치 FVector
Rotation - 회전 FRotator
Scale3D - 크기 FVector
// Item.cpp
void AItem::BeginPlay()
{
Super::BeginPlay();
FVector NewLocation(300.0f, 200.0f, 100.0f); // 위치
FRotator NewRotation(0.0f, 90.0f, 0.0f); // pitch Y축, yaw Z축, roll X축
FVector NewScale(2.0f); // 크기
FTransform NewTransform(NewRotation, NewLocation, NewScale);
SetActorTransform(NewTransform);
}
매 프레임마다 호출되는 함수
- 랜더링, 물리, 액터 업데이트가 매 프레임마다 실행됨
- 그중 액터 로직은 Tick()에서 처리
PrimaryActorTick.bCanEverTick = true; / true > tick 호출, false > tick 호출 안함
이전 프레임부터 현재 프레임까지 걸린 시간(초)
- 60FPS 약 0.0167초
- 120FPS 약 0.0083초
FPS가 높을수록 DeltaTime이 작아지고 낮을수록 DeltaTime이 커짐
어느 FPS에서도 동일한 실제 속도를 유지하기 위해서 사용
DeltaTime을 곱해서 초 단위 기준으로 이동 및 회전을 계산
공식 : 이동량 = 속도 × DeltaTime
ex) x += Speed * DeltaTime;
AddActorLocalRotation(FRotator(0.0f, 90.0f * DeltaTime, 0.0f));
Yaw(z축)을 틱당 90씩 회전 시키고 싶으면 위 코드처럼 하면됨
! - Not 연산자
FMath::IsNearlyZero - 값이 0에 가까우면 true
!FMath::IsNearlyZero - 값이 0이 아니면 true
// Item.h
// 회전 속도를 나타내는 변수 선언
float RotationSpeed;
// Item.cpp
AItem::AItem()
{
// Tick() 함수를 사용하기 위해 생성자에서 활성화
PrimaryActorTick.bCanEverTick = true;
// 기본 회전속도 90.0f 설정(1초에 90도 회전)
RotationSpeed = 90.0f;
}
// Item.cpp
void AItem::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// RotationSpeed의 값이 거의 0인지 체크
if (!FMath::IsNearlyZero(RotationSpeed))
{
// 액터를 로컬 좌표계 기준 Yaw(z축)으로 프레임마다 일정하게 회전시키기 위해
// RotationSpeed(90.0f) * Deltatime로 프레임당 약 1.5도씩 회전, 1초에 90도 회전
AddActorLocalRotation(FRotator(0.0f, RotationSpeed * DeltaTime, 0.0f));
}
}
C++ 클래스의 변수 및 함수 정보를 언리얼 엔진이 이해하는 데이터로 변환해서 Blueprint랑 언리얼 에디터에서 사용 가능하게 만드는 기능이며,
C++의 변수와 함수를 Blueprint에서 사용할 수 있게 하여 각 단점이 보완되며 효율적인 개발이 가능
| C++ | 뼈대(로직, 성능) |
| Blueprint | 조작(연출, 설정) |
| Reflection | 연결 |
장점
- 코드 수정 없이 값 조정 가능
- 바로 테스트 가능
- 비개발자도 값 수정 가능
- C++의 기능을 시각적으로 사용 가능
- 대규모 프로젝트 진행시 개발 효율과 협업 효과 극대화
단점
- 약간의 성능 비용
장점
- 빠르게 만들고 바로 테스트 가능
- 비개발자도 사용이 가능하며 UI, 연출, 이벤트 처리에 좋음
단점
- 노드가 많아지면 가독성이 떨어짐
- 성능이 C++보다 안좋음
- 복잡한 로직 구현이 힘듬
장점
- 성능이 좋고 복잡한 시스템 구현이 가능
- 엔진 깊은 부분까지 제어 가능
단점
- 수정 후 컴파일이 필요하며 과정이 오래걸림
- 비개발자가 접근하기 힘듬
- 테스트 반복이 번거로움
#include "Item.generated.h"
- 클래스의 리플레션 및 엔진 통합에 필요한 코드가 들어있음
- 리플렉션을 사용하기 위해서는 .h 파일에 아래 코드를 선언해야 하며 반드시 인클루드 마지막줄에 선언해야함
UCLASS()
- 해당 클래스를 언리얼 엔진의 리플렉션 시스템에 등록
- UCLASS()를 사용해야지만 블루프린트, 에디터에서 이 클래스를 인식하고 사용이 가능
GENERATED_BODY()
- 언리얼 코드 생성 도구가 사용하는 코드 삽입을 하는 역할
- 클래스 내부에 필요한 리플렉션 정보를 자동으로 생성해줌
// Item.h
#include "CoreMinimal.h"
#include "GameFrmework/Actor.h"
#include "Item.generated.h"
UCLASS()
class REFLTEST_API AItem : public AActor
{
GENERATED_BODY()
}
코드 작성 후 언리얼 에디터에서
콘텐츠 브라우저 > 블루프린트 클래스로 상속해줄 C++ 클래스 우클릭 > Create Blueprint class based on 클래스명 클릭 >
저장할 폴더 지정 및 이름 작성(BP_클래스명) > Create Class 클릭 > BP_클래스명 생성(부모 = C++ 클래스)
UCLASS에 옵션을 주지 않으면 블루프린트에서 상속, 변수로 참조가 가능한 형태로 등록
주요 옵션
- Blueprintable : 블루프린트에서 상속 가능한 클래스로 지정
- NotBlueprintable : 블루프린트에서 이 클래스를 상속할 수 없도록 지정
- BlueprintType : 블루프린트에서 변수나 참조로 사용할 수 있게 지정(상속용X)
지정자가 없을시 엔진은 변수 존재는 인식하지만, 에디터와 블루프린트에서는 보이지 않음
UPROPERTY(편집범위, Blueprint접근, Category, meta옵션)
VisibleAnywhere : 보기만 가능, 수정 X
EditAnywhere : 클래스 기본값, 인스턴스 모두에서 수정 가능
EditDefaultsOnly : 클래스 기본값만 수정 가능
EditInstanceOnly : 배치된 오브젝트(인스턴스)만 수정 가능
BlueprintReadWrite : 읽기 + 수정 가능
BlueprintReadOnly : 읽기만 가능
Category="Item|Components"
에디터의 Details 패널에서 폴더처럼 정리됨
meta=(ClampMin="0.0") / meta=(ClampMax="10.0") : 에디터에서 변수 입력 시 최소값, 최대값을 제한할 수 있습니다.
meta=(AllowPrivateAccess="true") : 해당 멤버가 private로 선언되어 있어도, 에디터나 Blueprint에서 접근할 수 있도록 허용해줌
// Item.h
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Item.generated.h"
UCLASS()
class REFLTEST_API AItem : public AActor
{
GENERATED_BODY()
public:
AItem();
protected:
// 보기만 가능, 블루프리트에서 읽기만 가능
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Item|Components")
USceneComponent* SceneRoot;
// 기본값 + 인스턴스 모두 수정 가능, 블루프리트에서 읽기 및 수정 가능
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item|Components")
UStaticMeshComponent* StaticMeshComp;
// 기본값 + 인스턴스 모두 수정 가능, 블루프리트에서 읽기 및 수정 가능
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item|Components")
UAudioComponent* AudioComp;
// 기본값만 수정 가능, 블루프리트에서 읽기만 가능
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Item|Properties")
float RotationSpeed;
};
지정자가 없을시 엔진은 함수 존재는 인식하지만, 블루프린트에서는 직접 호출할 수 없음
UFUNCTION(Blueprint관련지정자, Category)
BlueprintCallable : 블루프린트에서 실행(노드 호출)이 가능한 함수
(버튼 누르기, 이벤트 실행, 위치 초기화 같은 동작 함수에 사용)
BlueprintPure : 값을 반환하는 함수(Getter 역할) Exec 핀 없음
BlueprintImplementableEvent : C++에서 호출하면 블루프린트에서 구현된 로직이 실행되는 함수
(선언은 C++, 구현은 블루프린트에서 작성)
Category="Item|Actions"
블루프린트에서 함수 노드를 카테고리별로 정리
// Item.h
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Item.generated.h"
UCLASS()
class REFLTEST_API AItem : public AActor
{
GENERATED_BODY()
public:
AItem();
protected:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Item|Properties")
float RotationSpeed;
virtual void BeginPlay() override;
// 블루프린트에서 실행 가능
UFUNCTION(BlueprintCallable, Category="Item|Actions")
void ResetActorPosition();
// 블루프린트에서 값만 반환
UFUNCTION(BlueprintPure, Category = "Item|Properties")
float GetRotationSpeed() const;
// 함수 선언만, 구현은 블루프린트에서 작성
UFUNCTION(BlueprintImplementableEvent, Category = "Item|Event")
void OnItemPickedUP();
};
// Item.cpp
#include "Item.h"
AItem::AItem()
{
RotationSpeed = 90.0f;
}
void AItem::BeginPlay()
{
Super::BeginPlay();
// 블루프린트에서 구현한 함수를 C++에서 호출
OnItemPickedUP();
}
// BlueprintCallable 함수 구현
void AItem::ResetActorPosition()
{
// 액터의 위치를 (0, 0, 0)으로 되돌림
SetActorLocation(FVector::ZeroVector);
}
// BlueprintPure 함수 구현
float AItem::GetRotationSpeed() const
{
// RotationSpeed의 값을 반환
return RotationSpeed;
}
| Unreal C++ 기초 5. GameMode와 Character 클래스를 활용해서 캐릭터 구현하기 (2) | 2026.04.09 |
|---|---|
| 리플렉션을 활용한 회전발판과 움직이는 장애물 만들기 (1) | 2026.04.08 |
| Unreal C++ 기초 3. 컴포넌트 멤버 변수 추가 및 메시, 머티리얼 할당 (1) | 2026.04.06 |
| Unreal C++ 기초 2. Migrate, 클래스 생성 및 삭제 (0) | 2026.04.06 |
| Unreal C++ 기초 1. 설치 및 실행 (0) | 2026.04.05 |