1. 값 타입 vs 참조 타입
// 값 타입 (Stack 또는 inline 저장)struct FABCharacterStat{ float MaxHP; float Attack; // 데이터가 직접 메모리에 저장됨};// 참조 타입 (Heap 저장, 포인터로 접근)class UABItemData : public UObject{ GENERATED_BODY() // UObject는 힙에 할당되고 포인터로 관리됨};2. 가비지 컬렉션과 UPROPERTY
class ARENABATTLE_API UABGameSingleton : public UObject{ // ❌ UPROPERTY 없으면 GC가 추적 못함 → 메모리 누수 또는 댕글링 포인터! TArray<UObject*> NotTracked; // ✅ UPROPERTY로 GC에게 "이 포인터들 추적해줘!" 알림 UPROPERTY() TArray<UObject*> Tracked; // ✅ 값 타입은 포인터가 아니므로 GC 추적 불필요 TArray<FABCharacterStat> Stats; // 구조체 자체가 배열에 복사됨};3. 실제 메모리 레이아웃
// 구조체 배열 - 연속된 메모리에 값이 직접 저장TArray<FABCharacterStat> Stats;// 메모리: [Stat1데이터][Stat2데이터][Stat3데이터]...// UObject 포인터 배열 - 포인터만 저장, 실제 객체는 힙 어딘가에TArray<UObject*> Items;// 메모리: [포인터1][포인터2][포인터3]...// ↓ ↓ ↓// [힙의객체1][힙의객체2][힙의객체3]4. 구조체가 안전한 이유
// 구조체는 복사되므로 소유권이 명확TArray<FABCharacterStat> Stats;Stats.Add(SomeStat); // 값이 복사됨, 원본이 사라져도 안전// UObject*는 포인터이므로 원본 객체가 삭제되면 위험TArray<UObject*> Items;Items.Add(SomeItem); // 포인터만 저장, 원본이 GC되면 댕글링 포인터 // → UPROPERTY로 GC에게 건드리지말라고 알려야 함캐릭터 스탯 시스템

NPC 초기화 시점과 스탯 설정 시점의 문제

SpawnActor()→ 곧바로 초기화 &BeginPlay()림SpawnActorDeferred()+FinishSpawning()→ 언리얼이 FinishSpawning 호출 전까지BeginPlay()호출을 미뤄줌
void AABStageGimmick::OnOpponentSpawn(){ const FVector SpawnLocation = GetActorLocation() + FVector::UpVector * 88.f; // 업벡터 안올려주면 땅에 박힌 채 생성 AActor* OpponentActor = GetWorld()->SpawnActor(OpponentClass, &SpawnLocation, &FRotator::ZeroRotator); AABCharacterNonPlayer* ABOpponentCharacter = Cast<AABCharacterNonPlayer>(OpponentActor); if (!ABOpponentCharacter) { // NPC 아닌 경우 삭제하고 종료 OpponentActor->Destroy(); return; } OpponentActor->OnDestroyed.AddDynamic(this, &AABStageGimmick::OnOpponentDestroyed);}void AABStageGimmick::OnOpponentSpawn(){ const FVector SpawnLocation = GetActorLocation() + FVector::UpVector * 88.f; // 업벡터 안올려주면 땅에 박힌 채 생성 const FTransform SpawnTransform(SpawnLocation); // 기본 회전값 ZeroRotator임 // Actor* OpponentActor = GetWorld()->SpawnActor(OpponentClass, &SpawnLocation, &FRotator::ZeroRotator); AABCharacterNonPlayer* ABOpponentCharacter = GetWorld()->SpawnActorDeferred<AABCharacterNonPlayer> (OpponentClass, SpawnTransform); if (!ABOpponentCharacter) { return; } ABOpponentCharacter->OnDestroyed.AddDynamic(this, &AABStageGimmick::OnOpponentDestroyed); ABOpponentCharacter->SetLevel(CurrentStageNum); ABOpponentCharacter->FinishSpawning(SpawnTransform);}언리얼 퀴즈
다음 중 언리얼 오브젝트의 리플렉션과 관계없는 작업을 고르시오.
- 실행 시간(Runtime)에 객체 정보를 조회할 수 있다.
- 컴파일 시간(Compiletime)에 객체 정보를 조회할 수 있다.
StaticClass()로 가능
- 클래스 정보로부터 함수 정보를 얻어올 수 있다.
- 클래스 정보가 없는 언리얼 오브젝트도 있다.
- 틀렸음. 언리얼 오브젝트는 무조건 클래스 정보가 있다
- UCLASS() , UPROPERTY(), UFUNCTION() 등의 매크로로 해당하는 요소를 마킹하면 리플렉션 프로퍼티로 언리얼 엔진에 등록된다.
- 리플렉션 프로퍼티가 아닌 요소들은 등록된 요소들과 혼합하여 사용할 수 있으나, 언리얼 엔진으로부터 관리 받지 못한다.
- 함수 이름과 인자 정보를 알면 실행 시간에 함수를 호출할 수 있다.
다음 중 언리얼 구조체에 대해 잘못 설명한 것을 고르시오.
- 접두사 U를 붙인다.
- 언리얼 엔진의 구조체 이름은 F로 시작함.
- 대부분 힙 메모리 할당(포인터 연산)없이 스택 데이터로 사용됨
NewObject()API를 사용할 수 없음
- GENERATED_BODY 매크로를 사용할 수 있다.
- 데이터만 관리하는 용도로 사용한다.
-
UFUNCTION 함수를 선언할 수 없다.
- UPROPERTY 선언은 가능하다.
다음 중 언리얼 엔진의 가비지 컬렉터가 회수하는 오브젝트를 고르시오
- UPROPERTY로 선언한 언리얼 오브젝트 멤버 변수
- 언리얼이 참조하므로 회수 안됨
- AddReferencedObject 함수에서 추가한 언리얼 오브젝트 멤버 변수
- 사용자 정의 클래스지만 직접 FGCObject 상속 + AddReferencedObject 선언으로 참조 걸어줄 수 있음
- UPROPERTY로 선언한 TArray 함수가 관리하는 언리얼 오브젝트
- TArray 내 요소 하나하나 모두 언리얼이 참조함
- NewObject로 생성했지만 UPROPERTY로 지정되지 않은 언리얼 오브젝트
- AddToRoot 함수를 사용해 루트셋으로 설정한 오브젝트
- 루트셋은 GC가 회수하지 않음음
다음 중 언리얼 오브젝트 패키지가 직접 관리하고 에디터에서 보여지는 언리얼 오브젝트는?
- 서브 오브젝트(Subobject)
- 애셋(Asset)
- 클래스 기본 객체(Class Default Object)
- 아우터(Outer)
- 트랜지언트(Transient)
- 직렬화에 포함시키지 않는다는 뜻(디스크에 저장하기 위해 직렬화함)
- 현재 체력 값의 경우 UPROPERTY의 이점(블루프린트 호환, 리플렉션 등)을 누리면서 디스크에 저장하고 싶지 않은 값이다.
11. 행동트리 모델의 이해
void AABAIController::RunAI(){ UBlackboardComponent* BlackboardPtr = Blackboard.Get(); if (UseBlackboard(BBAsset, BlackboardPtr)) // Blackboard.Get()은 rvalue ref(임시값)이므로 { bool Result = RunBehaviorTree(BTAsset); ensureAlways(Result); }}왜 UseBlackboard()에서 두번째 인자에 Blackboard.Get()을 바로 넘겨주지 못할까?
- 일단 Blackboard.Get()은 rvalue reference로 임시값임
- UseBlackboard() 함수를 까보면 내부에서 두번째 인자를 재설정하는 코드가 있음
bool AAIController::UseBlackboard(UBlackboardData* BlackboardAsset, UBlackboardComponent*& BlackboardComponent){ ... BlackboardComponent = Blackboard; return bSuccess}오늘 정리
- CharacterStat 컴포넌트 WeaponData에 부착
- CharacterBase EquipWeapon에서 무기의 ModifierStat을 캐릭터 스탯에 더해주기
- 커스텀 GameSingleton에서 캐릭터 스탯 data table 로드 및 분배
- StageGimmick, OnOpponentSpawn, RewardBoxes 생성을 Deferred시켜 레벨 초기화 이후에 BeginPlay 호출 순서보장(안그럼 레벨 1로 CurrentHp 설정됨)
.ini파일 활용해 NPC 메시 랜덤 선택(UCLASS(config=ArenaBattle), UPROPERTY(config))- AI 기초 세팅