Actor 클래스에 컴포넌트 추가

 

컴포넌트(component) 란? - 일종의 부품 느낌

3D메시를 할당 해주기 위해서는 액터에 추가적인 컴포넌트(component)를 붙여줘야 한다.

루트 컴포넌트와 Scene Component

  • 모든 Actor는 **루트 컴포넌트 (Root Component)**를 가져야 합니다.
  • 루트 컴포넌트는 액터의 트랜스폼 (위치, 회전, 크기)을 정의하는 최상위 컴포넌트이며, 모든 하위 컴포넌트가 이를 기준으로 트랜스폼이 계산됩니다.
  • 보통 Scene Component를 루트 컴포넌트로 설정하여 액터의 트랜스폼을 관리하고, 그 아래에 다양한 컴포넌트를 계층적으로 붙입니다.
    • Scene Component는 모든 트랜스폼 속성만 가지는 비시각적인 컴포넌트입니다.
    • Scene Component는 직접적인 시각적 출력을 가지지 않지만, 다른 하위 컴포넌트들을 관리하는 기준점 역할을 할 수 있습니다.

Static Mesh Component란?

  • 애니메이션이나 스켈레탈 본 없이 (즉, 움직임이 없고 단순 이동·회전만 하는) 정적 (Static) 3D 모델을 그리는 컴포넌트입니다.
    • 환경 오브젝트 (건물, 바위), 아이템, 단순 기믹 오브젝트 등 “움직임이 단순하거나 없는” 오브젝트에 주로 적합합니다.
    • 3D 모델을 표현하고, 물리 충돌과 관련된 기능도 제공합니다.
#pragma once	// 동일 헤더가 프로젝트 곳곳에서 여러 번 포함되더라도 컴파일러가 한 번만 처리하게 함.

#include "CoreMinimal.h"	// 언리얼에서 가장 기본이 되는 헤더로, 엔진 전역 타입, 매크로, 함수등을 가져옴.
#include "GameFramework/Actor.h"	// AActor클래스 선언을 사용 가능하게 함.
#include "Item.generated.h"	// 리플렉션 시스템

UCLASS()	// 리플렉션 시스템 - 메크로
class SPARTAPROJRCT_API AItem : public AActor	// A~ 접두어를 붙여 Actor클래스라는 것을 알려줌
{
	GENERATED_BODY()	// 리플렉션 시스템
	
public:	
	// Sets default values for this actor's properties
	// 생성자
	AItem();	

protected:

	USceneComponent* SceneRoot;	// 루트 컴포넌트
	UStaticMeshComponent* StaticMeshComp;	// 스태틱 메시 컴포넌트
	
	// 엑터가 월드에 완전히 배치되고, 게임 플레이가 시작할 때 한 번 호출
	virtual void BeginPlay() override;	

public:	
	
	// 매 프레임 마다 자동으로 호출
	virtual void Tick(float DeltaTime) override;

};

// ============== cpp ===============

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


#include "Item.h"

// Sets default values
AItem::AItem()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;


	// 템플릿 형태의 CreateDefaultSubobject<타입>(컴포넌트 이름)
	SceneRoot = CreateDefaultSubobject<USceneComponent>(TEXT("SceneRoot"));
	SetRootComponent(SceneRoot);	// 루트 컴포넌트 지정

	StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
	StaticMeshComp->SetupAttachment(SceneRoot);	// SceneRoot 하위로 붙이기

	static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshAsset(TEXT("'/Game/Resources/Props/SM_Chair.SM_Chair'"));
	// 생성됐는지 예외처리
	if (MeshAsset.Succeeded())
	{
		// 위에서 경로로 가져온 스태틱메시를 액터에 설정
		StaticMeshComp->SetStaticMesh(MeshAsset.Object);	
	}

	static ConstructorHelpers::FObjectFinder<UMaterial> MaterialAsset(TEXT("'/Game/Resources/Materials/M_Metal_Gold.M_Metal_Gold'"));
	// 생성됐는지 예외처리
	if (MaterialAsset.Succeeded())
	{
		// 위에서 경로로 가져온 머터리얼을 액터에 설정
        // 머터리얼은 여러개를 가져올 수 있기에 파라미터의 0으로 번호 지정  
		StaticMeshComp->SetMaterial(0, MaterialAsset.Object);
	}
}

// Called when the game starts or when spawned
void AItem::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void AItem::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

1. 언리얼 엔진 액터 라이프 사이클 (Actor Life Cycle) 가이드

액터(Actor)의 생명 주기는 언리얼 엔진 프로그래밍의 핵심입니다. 올바른 시점에 코드를 배치해야 버그를 방지하고 성능을 최적화할 수 있습니다.

  • 초기화 시점 결정 (Initialization)
    • 생성자, PostInitializeComponents, BeginPlay 등이 호출되는 정확한 시점을 알아야 코드를 적재적소에 배치할 수 있습니다.
    • 예시: 컴포넌트 생성(CreateDefaultSubobject)은 생성자에서, 월드나 타 액터 참조는 BeginPlay에서 수행.
  • 성능 관리 (Performance)
    • Tick 함수는 매 프레임 호출되므로 비용이 큽니다.
    • 불필요한 액터의 Tick을 비활성화하거나, 이벤트 기반(Event-Driven) 로직으로 전환하여 최적화해야 합니다.
  • 안전한 리소스 정리 (Resource Cleanup)
    • 액터가 소멸될 때(EndPlay, Destroyed) 메모리 해제나 상태 저장을 수행해야 합니다.
    • 누락 시 메모리 누수(Memory Leak)나 크래시가 발생할 수 있습니다.

2. 라이프 사이클 진행 순서

생성 (Spawn)   >  초기화   >   월드 배치 (BeginPlay)   >   실행 (Tick)   >   제거 (EndPlay/Destroy)


3. 주요 라이프 사이클 함수 상세

  • 호출 시점: C++ 클래스 객체가 메모리에 생성될 때 단 한 번 호출됩니다.
  • 특징:
    • 아직 액터가 월드(World)에 등록되지 않은 상태입니다.
    • 다른 액터나 월드 관련 기능(GetWorld 등)을 호출하면 위험합니다.
  • 주요 용도:
    • CreateDefaultSubobject를 통한 컴포넌트 생성.
    • 기본 변수(Default Value) 값 설정.

3.2. PostInitializeComponents()

  • 호출 시점: 액터의 모든 컴포넌트가 생성 및 초기화된 직후 자동 호출됩니다.
  • 특징:
    • 생성자 호출 이후이며, 각 컴포넌트가 준비된 상태입니다.
  • 주요 용도:
    • 컴포넌트 간의 상호작용 설정 (예: A 컴포넌트가 B 컴포넌트를 참조).
    • 생성자에서 할당한 컴포넌트들의 의존성 설정.

3.3. BeginPlay()

  • 호출 시점:
    • 게임이 시작될 때 (Play In Editor 포함).
    • 실행 중인 게임에서 SpawnActor로 액터가 생성될 때.
  • 특징:
    • 액터가 월드에 완전히 배치되었으며, 다른 액터들과 상호작용이 가능합니다.
  • 주요 용도:
    • 다른 시스템(AI, GameMode, PlayerController)과의 연동 및 초기화.
    • 타이머(Timer) 시작, 델리게이트(Delegate) 바인딩.

3.4. Tick(float DeltaTime)

  • 호출 시점: 매 프레임마다 호출됩니다. (PrimaryActorTick.bCanEverTick = true 설정 필요)
  • 주요 용도:
    • 실시간 업데이트 로직 (캐릭터 이동, 물리 연산, 추적 등).
  • 주의 사항:
    • 성능에 직접적인 영향을 주므로, 가능하면 이벤트 기반으로 로직을 작성하여 Tick 사용을 최소화하는 것이 좋습니다.

4. 액터 종료 및 리소스 정리4.1. Destroyed()

  • 호출 시점: Destroy() 함수를 직접 호출하여 액터를 제거하기 직전.
  • 주의 사항 (중요):
    • 레벨 전환(Level Transition)이나 게임 종료 시에는 호출되지 않을 수 있습니다.
    • 따라서 모든 정리 로직을 이곳에만 의존하는 것은 위험합니다.
  • 권장 처리 항목:
    • 수동으로 할당한 메모리 해제 (new / delete).
    • 자동으로 해제되지 않는 자식 액터나 컴포넌트 정리.
    • 액터에 종속된 사운드, 파티클의 수동 종료.

4.2. EndPlay(const EEndPlayReason::Type EndPlayReason)

  • 호출 시점: 액터가 월드에서 제거되는 모든 상황 (파괴, 레벨 전환, 게임 종료 등).
  • 특징:
    • EEndPlayReason을 통해 종료 원인을 구분할 수 있습니다.
    • Destroyed()보다 호출 보장성이 높습니다.
  • 권장 처리 항목 (안전한 정리):
    • 타이머 해제: GetWorldTimerManager().ClearTimer(...)
    • 델리게이트/이벤트 바인딩 해제: 전역적 이벤트 등.
    • 데이터 저장: 게임 진행 상황, 인벤토리 등 중요 데이터 백업.
    • 남아있는 동적 할당 리소스의 최종 정리.
      • 액터 제거 시 호출 보장 여부에 따라 코드를 배치하는 것이 중요합니다.
      • 3.1. 생성자 (Constructor)
      • 일반적인 액터의 흐름은 다음과 같습니다:
      • 1. 라이프 사이클을 이해해야 하는 이유

+ Recent posts