unreal 공부

Virus·2025년 1월 21일
  1. Actor 클래스의 구조 이해하기
    언리얼 엔진에서 C++ 클래스를 생성하면, 헤더(.h)와 구현(.cpp) 파일이 한 쌍으로 만들어집니다.
    이 구조에서 어떤 역할을 하는지 자세히 배웠습니다.

1️⃣ 헤더(.h) 파일 주요 구성
cpp

#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Item.generated.h"
#pragma once: 헤더 파일이 중복 처리되지 않도록 설정.
#include "CoreMinimal.h": 언리얼 엔진의 기본 타입과 매크로를 포함.
#include "GameFramework/Actor.h": AActor를 상속받기 위해 필요.
UCLASS(): 클래스가 언리얼 리플렉션 시스템과 연동되도록 지정.
GENERATED_BODY(): 리플렉션 관련 코드를 자동 생성하는 매크로.
2️⃣ 클래스 선언부
cpp

UCLASS()
class SPARTAPROJECT_API AItem : public AActor
{
GENERATED_BODY()

public:
AItem(); // 생성자
protected:
virtual void BeginPlay() override; // 초기화 시 호출
virtual void Tick(float DeltaTime) override; // 매 프레임 호출
};
AItem 클래스: AActor를 상속받아 정의된 Actor 클래스.
Actor 라이프사이클 함수
BeginPlay(): 액터가 월드에 배치된 후 한 번 호출.
Tick(): 매 프레임마다 호출.
3️⃣ 구현(.cpp) 파일 주요 구성
cpp

#include "Item.h"

AItem::AItem()
{
PrimaryActorTick.bCanEverTick = true; // 매 프레임 업데이트 활성화
}

void AItem::BeginPlay()
{
Super::BeginPlay(); // 부모 클래스의 BeginPlay() 호출
}

void AItem::Tick(float DeltaTime)
{
Super::Tick(DeltaTime); // 부모 클래스의 Tick() 호출
}
PrimaryActorTick.bCanEverTick = true: 매 프레임 Tick() 함수가 호출되도록 설정.
Super::BeginPlay() / Super::Tick(): 부모 클래스의 기본 동작을 실행.

  1. Actor 클래스에 컴포넌트 추가하기
    컴포넌트를 통해 Actor의 시각적, 기능적 요소를 추가할 수 있습니다.

1️⃣ 컴포넌트의 역할
Scene Component: Actor의 위치, 회전, 크기 등 트랜스폼 정보를 관리.
Static Mesh Component: 고정된 3D 모델을 렌더링하고 물리적 충돌을 담당.
계층적 구조: Scene Component를 루트로 설정하고, Static Mesh Component를 연결(Attach)합니다.
2️⃣ 코드로 컴포넌트 추가
cpp

#include "Item.h"

AItem::AItem()
{
// 루트 컴포넌트 생성 및 설정
SceneRoot = CreateDefaultSubobject(TEXT("SceneRoot"));
SetRootComponent(SceneRoot);

// Static Mesh 컴포넌트 생성 및 Attach
StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
StaticMeshComp->SetupAttachment(SceneRoot);

}
CreateDefaultSubobject(): 컴포넌트를 생성하는 함수.
SetRootComponent(): Scene Component를 루트로 설정.
SetupAttachment(): Static Mesh를 Scene Root에 연결.

  1. Static Mesh 및 Material 설정하기
    Actor에 3D 모델과 머티리얼을 추가하는 과정을 코드로 구현했습니다.

1️⃣ Static Mesh와 Material의 역할
Static Mesh: Actor의 외형을 담당하는 3D 모델.
Material: 모델의 표면 질감, 색상, 반사율 등을 정의.
2️⃣ Static Mesh와 Material 설정 코드
cpp

AItem::AItem()
{
// Static Mesh 설정
static ConstructorHelpers::FObjectFinder MeshAsset(TEXT("/Game/Resources/Props/SM_Chair.SM_Chair"));
if (MeshAsset.Succeeded())
{
StaticMeshComp->SetStaticMesh(MeshAsset.Object);
}

// Material 설정
static ConstructorHelpers::FObjectFinder<UMaterial> MaterialAsset(TEXT("/Game/Resources/Materials/M_Metal_Gold.M_Metal_Gold"));
if (MaterialAsset.Succeeded())
{
    StaticMeshComp->SetMaterial(0, MaterialAsset.Object);
}

}
ConstructorHelpers::FObjectFinder: 에디터 내 리소스를 경로 기반으로 로드.
SetStaticMesh(): Static Mesh를 Actor에 적용.
SetMaterial(): Material을 Static Mesh에 적용.
리소스 경로는 우클릭 → Copy Reference를 사용해 가져옵니다.

  1. UE_LOG로 디버깅하기
    언리얼 엔진에서 로그를 출력하면 특정 함수가 호출되는 시점이나 변수의 상태를 확인할 수 있습니다.

1️⃣ UE_LOG 기본 사용법
cpp

UE_LOG(LogTemp, Warning, TEXT("My Item appears!!"));
LogTemp: 임시 로그 카테고리.
Warning: 로그 레벨(노란색). 그 외에도 Log, Display, Error 등이 있음.
TEXT(): 출력할 메시지를 지정.
2️⃣ 고유한 로그 카테고리 정의하기
프로젝트가 커질수록 LogTemp를 사용하는 것은 비효율적이므로, 고유한 로그 카테고리를 정의하는 것이 좋습니다.

cpp

// 헤더 파일 (.h)
DECLARE_LOG_CATEGORY_EXTERN(LogSparta, Warning, All);

// 구현 파일 (.cpp)
DEFINE_LOG_CATEGORY(LogSparta);

// 로그 출력
UE_LOG(LogSparta, Error, TEXT("My Log!!"));
DECLARE_LOG_CATEGORY_EXTERN: 헤더에서 카테고리 선언.
DEFINE_LOG_CATEGORY: .cpp 파일에서 카테고리를 정의.
이렇게 하면 LogSparta라는 카테고리를 통해 로그를 출력하고, 필요에 따라 특정 카테고리만 필터링할 수 있습니다.

  1. 언리얼 에디터에서 로그 확인하기
    1️⃣ Output Log 창 열기
    Window → Output Log를 클릭하면 하단에 로그 창이 열립니다.
    Play 버튼을 눌러 게임을 실행하면 작성한 로그 메시지가 표시됩니다.
    2️⃣ 로그 필터링
    Output Log 창의 Filters를 사용하면 특정 카테고리만 출력하도록 필터링할 수 있습니다.
    예: LogTemp나 LogSparta만 활성화해 필요한 메시지만 확인.

  2. Actor의 라이프 사이클 이해하기
    언리얼 엔진의 Actor는 생성 → 초기화 → 월드 배치 → 실행(Tick) → 제거 순으로 동작합니다.
    각 단계에서 호출되는 함수들을 이해하면 효율적으로 게임 로직을 작성할 수 있습니다.

1️⃣ 주요 라이프 사이클 함수
Constructor: Actor 객체가 메모리에 생성될 때 호출. 컴포넌트 생성 및 기본값 초기화에 사용.
PostInitializeComponents(): 모든 컴포넌트가 초기화된 후 호출. 컴포넌트 간 상호작용 초기화 가능.
BeginPlay(): Actor가 월드에 배치되고 게임 시작 시 호출. 다른 시스템과 상호작용 로직 작성.
Tick(float DeltaTime): 매 프레임 호출. 실시간 업데이트가 필요한 로직 작성.
EndPlay(const EEndPlayReason::Type EndPlayReason): Actor가 월드에서 사라질 때 호출. 자원 정리에 사용.
Destroyed(): Destroy() 호출 직전에 실행. 메모리 해제 및 최종 작업 처리.
2️⃣ 라이프 사이클 함수 구현 예시
cpp

void AItem::BeginPlay()
{
Super::BeginPlay();
UE_LOG(LogSparta, Warning, TEXT("%s BeginPlay"), *GetName());
}

void AItem::Destroyed()
{
UE_LOG(LogSparta, Warning, TEXT("%s Destroyed"), *GetName());
Super::Destroyed();
}

void AItem::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
UE_LOG(LogSparta, Warning, TEXT("%s EndPlay"), *GetName());
Super::EndPlay(EndPlayReason);
}
GetName(): 현재 Actor의 이름을 반환해 로그에 표시.
Tick 함수 주의: 매 프레임 호출되므로, 디버깅 시 제한적으로 사용.

  1. 배운 점과 느낀 점
    언리얼 엔진의 C++ 코드 구조는 헤더(.h)와 구현(.cpp)으로 나뉘며, 리플렉션 시스템과 연동된다는 점이 새로웠습니다.
    Actor의 기본적인 컴포넌트 연결 방법을 배우며, 언리얼 엔진의 강력한 모듈화 설계 방식을 이해할 수 있었습니다.
    Static Mesh와 Material을 코드로 연결해 Actor를 완성하는 과정에서 에셋 경로 설정의 중요성을 배웠습니다.
    UE_LOG 활용: 로그를 통해 함수 호출 순서와 변수 상태를 쉽게 확인할 수 있음.
    Actor 라이프 사이클: 각 함수의 호출 시점을 이해하면, 적절한 작업을 효율적으로 배치할 수 있음.
    로그 카테고리 관리: 고유한 카테고리를 사용하면 디버깅과 협업이 훨씬 편리.

0개의 댓글