현재 함께할 동료를 채용하고 있습니다.채용 공고 보기 →
개발일지공부아이디어
    • 8월
    • 7월
    • 6월
    • 5월
    • 4월
    • 3월
    • 2월
    • 1월
  • 29

    26. 4. 29.

  • 28

    26. 4. 28.

  • 27

    26. 4. 27.

  • 24

    26. 4. 24.

  • 23

    26. 4. 23.

  • 22

    26. 4. 22.

  • 21

    26. 4. 21.

  • 20

    26. 4. 20.

  • 17

    26. 4. 17.

  • 16

    26. 4. 16.

  • 15

    26. 4. 15.

  • 14

    26. 4. 14.

  • 10

    26. 4. 10.

  • 09

    26. 4. 9.

  • 08

    26. 4. 8.

로딩 중...

2026. 4. 27.

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);}

언리얼 퀴즈

다음 중 언리얼 오브젝트의 리플렉션과 관계없는 작업을 고르시오.

  1. 실행 시간(Runtime)에 객체 정보를 조회할 수 있다.
  2. 컴파일 시간(Compiletime)에 객체 정보를 조회할 수 있다.
    • StaticClass()로 가능
  3. 클래스 정보로부터 함수 정보를 얻어올 수 있다.
  4. 클래스 정보가 없는 언리얼 오브젝트도 있다.
    • 틀렸음. 언리얼 오브젝트는 무조건 클래스 정보가 있다
    • UCLASS() , UPROPERTY(), UFUNCTION() 등의 매크로로 해당하는 요소를 마킹하면 리플렉션 프로퍼티로 언리얼 엔진에 등록된다.
    • 리플렉션 프로퍼티가 아닌 요소들은 등록된 요소들과 혼합하여 사용할 수 있으나, 언리얼 엔진으로부터 관리 받지 못한다.
  5. 함수 이름과 인자 정보를 알면 실행 시간에 함수를 호출할 수 있다.

다음 중 언리얼 구조체에 대해 잘못 설명한 것을 고르시오.

  1. 접두사 U를 붙인다.
    • 언리얼 엔진의 구조체 이름은 F로 시작함.
    • 대부분 힙 메모리 할당(포인터 연산)없이 스택 데이터로 사용됨
    • NewObject() API를 사용할 수 없음
  2. GENERATED_BODY 매크로를 사용할 수 있다.
  3. 데이터만 관리하는 용도로 사용한다.
  4. UFUNCTION 함수를 선언할 수 없다.

  5. UPROPERTY 선언은 가능하다.

다음 중 언리얼 엔진의 가비지 컬렉터가 회수하는 오브젝트를 고르시오

  1. UPROPERTY로 선언한 언리얼 오브젝트 멤버 변수
    • 언리얼이 참조하므로 회수 안됨
  2. AddReferencedObject 함수에서 추가한 언리얼 오브젝트 멤버 변수
    • 사용자 정의 클래스지만 직접 FGCObject 상속 + AddReferencedObject 선언으로 참조 걸어줄 수 있음
  3. UPROPERTY로 선언한 TArray 함수가 관리하는 언리얼 오브젝트
    • TArray 내 요소 하나하나 모두 언리얼이 참조함
  4. NewObject로 생성했지만 UPROPERTY로 지정되지 않은 언리얼 오브젝트
  5. AddToRoot 함수를 사용해 루트셋으로 설정한 오브젝트
    • 루트셋은 GC가 회수하지 않음음

다음 중 언리얼 오브젝트 패키지가 직접 관리하고 에디터에서 보여지는 언리얼 오브젝트는?

  1. 서브 오브젝트(Subobject)
  2. 애셋(Asset)
  3. 클래스 기본 객체(Class Default Object)
  4. 아우터(Outer)
  5. 트랜지언트(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 기초 세팅
왼쪽 화살표오른쪽 화살표