<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>view29579 님의 블로그</title>
    <link>https://view29579.tistory.com/</link>
    <description>view29579 님의 블로그 입니다.</description>
    <language>ko</language>
    <pubDate>Tue, 22 Sep 2026 04:21:43 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>view29579</managingEditor>
    <item>
      <title>Unreal 응용반 분반수업 4차 내용정리</title>
      <link>https://view29579.tistory.com/53</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. ControlRotation 복습&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PlayerController는 플레이어가 바라보거나 조준하고 있는 방향을 ControlRotation으로 가지고 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;bUseControllerRotationYaw&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;APawn에 있는 옵션이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;true로 설정하면 Pawn의 Yaw가 Controller의 ControlRotation.Yaw를 따라간다.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;ControlRotation.Yaw
        &amp;darr;
Character Actor Yaw
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주로 캐릭터가 카메라 또는 조준 방향을 따라가야 하는 경우 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FPS&lt;/li&gt;
&lt;li&gt;TPS 조준 모드&lt;/li&gt;
&lt;li&gt;캐릭터와 조준 방향을 일치시키는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;bUseControllerDesiredRotation&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UCharacterMovementComponent의 옵션이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;활성화하면 CharacterMovement가 Controller의 방향을 목표 회전 방향으로 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 RotationRate를 이용해서 캐릭터가 즉시 회전하지 않고 점진적으로 회전한다.&lt;/p&gt;
&lt;pre class=&quot;fortran&quot;&gt;&lt;code&gt;ControlRotation
      &amp;darr;
목표 회전 방향
      &amp;darr;
RotationRate
      &amp;darr;
Character 회전
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;bOrientRotationToMovement&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UCharacterMovementComponent의 옵션이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;활성화하면 캐릭터가 Controller가 바라보는 방향이 아니라 &lt;b&gt;이동 방향&lt;/b&gt;을 기준으로 회전한다.&lt;/p&gt;
&lt;pre class=&quot;fortran&quot;&gt;&lt;code&gt;이동 방향
   &amp;darr;
Character 회전
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3인칭 일반 이동에서 자주 사용하는 방식이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;RotationRate&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CharacterMovementComponent가 캐릭터를 회전시키는 속도이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;MovementComponent-&amp;gt;RotationRate = FRotator(0.0f, 240.0f, 0.0f);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Yaw 방향으로 초당 240도 회전하도록 설정할 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. SpringArm의 bUsePawnControlRotation&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SpringArm이 Pawn의 Control Rotation을 카메라 방향에 사용할지 결정하는 옵션이다.&lt;/p&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;PlayerController
      &amp;darr;
ControlRotation
      &amp;darr;
SpringArm
      &amp;darr;
Camera
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 마우스를 움직였을 때 카메라가 Controller의 회전을 따라가게 만들 때 사용할 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;3. UObject와 Actor&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;UObject&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UObject는 Unreal Object System의 기본이 되는 클래스이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 C++ 객체와 다르게 Unreal의 객체 관리 시스템을 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 C++ 객체:&lt;/p&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;FMyData* Data = new FMyData();
delete Data;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UObject 계열:&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;UMyObject* MyObject = NewObject&amp;lt;UMyObject&amp;gt;(this);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UObject는 Unreal의 Garbage Collection 시스템과 연결되어 관리된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Outer&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Outer는 UObject가 어떤 객체에 속해 있는지를 나타내는 관계이다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;NewObject&amp;lt;UMyObject&amp;gt;(this);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 this는 새로 만들어지는 UObject의 Outer가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Outer는 UObject의 객체 계층과 소속 관계를 이해할 때 중요하다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Actor&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AActor는 UObject를 상속받은 클래스이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;차이점은 Actor는 &lt;b&gt;월드에 존재할 수 있는 객체&lt;/b&gt;라는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Actor는 위치, 회전, 크기 등의 Transform을 가지고 월드에 배치되거나 Spawn될 수 있다.&lt;/p&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;GetWorld()-&amp;gt;SpawnActor&amp;lt;AMyActor&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Actor는 단순히 C++ 객체 하나를 생성하는 것이 아니라 Unreal의 월드와 연결되어야 하기 때문에 SpawnActor() 등을 통해 생성한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;4. Actor의 생명주기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Actor는 대략 다음과 같은 흐름으로 동작한다.&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;Actor 생성
   &amp;darr;
Construction
   &amp;darr;
Component 초기화
   &amp;darr;
BeginPlay
   &amp;darr;
GamePlay
   &amp;darr;
EndPlay
   &amp;darr;
World에서 제거
   &amp;darr;
Garbage Collection
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C++에서 작성한 기본 설정과 Blueprint에서 작성한 로직의 실행 순서도 고려해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 모든 로직을 단순히 같은 시점에 실행된다고 생각하면 예상과 다른 결과가 발생할 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기본 생성자&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 생성자에서는 주로&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본값 설정&lt;/li&gt;
&lt;li&gt;Component 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;등을 작성한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Construction&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에디터에서 Actor의 값이 변경되었을 때 갱신되는 과정에서 많이 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게임 시작 후 실행해야 하는 로직은 일반적으로 BeginPlay()에서 처리한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;PostInitializeComponents&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Actor의 Component 초기화가 완료된 후 호출된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;5. Destroy&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Destroy()는 C++의 delete와 다르다.&lt;/p&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;Destroy();
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 Actor를 즉시 메모리에서 직접 삭제하는 것이 아니라 &lt;b&gt;World에서 제거하는 과정을 시작하는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 EndPlay 등의 과정이 진행되고 실제 UObject 메모리 정리는 Unreal의 Garbage Collection 시스템이 담당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 Actor에 대해 직접:&lt;/p&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;delete MyActor;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하는 방식은 사용하지 않는다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;6. UObjectPtr&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UObject 계열 객체를 참조할 때 Unreal의 객체 관리 시스템과 함께 안전하게 사용하기 위해 TObjectPtr를 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;UPROPERTY()
TObjectPtr&amp;lt;UMyObject&amp;gt; MyObject;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 Unreal의 UPROPERTY()와 함께 객체 참조를 관리할 때 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체가 유효한지 확인해야 하는 상황에서는 IsValid() 등의 방법을 사용할 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;7. Actor의 Owner&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Actor에는 다른 Actor를 Owner로 지정할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;Weapon-&amp;gt;SetOwner(PlayerCharacter);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 Weapon에서:&lt;/p&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;AActor* OwnerActor = GetOwner();
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 통해 자신의 Owner를 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Owner가 없다면 nullptr이 반환될 수 있으므로 예외 처리가 필요하다.&lt;/p&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;if (!OwnerActor)
{
    return;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Owner에서 주의할 점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Owner는 C++에서 말하는 메모리 소유권과 같은 의미가 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 Attachment와도 다르다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Owner
&amp;rarr; Gameplay / Network 관계

Attachment
&amp;rarr; Transform 부모-자식 관계
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 총을 캐릭터 손 Socket에 붙이는 것과 총의 Owner를 캐릭터로 지정하는 것은 서로 다른 개념이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;총을 캐릭터 손에 Attach하면서 Owner도 캐릭터로 설정할 수 있지만, 둘은 각각 다른 목적을 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 Multiplayer에서는 Actor의 Owner 관계가 RPC, Replication 등의 동작과 관련되기 때문에 중요하다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;8. V키를 이용한 Control Mode 전환&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;V키를 눌렀을 때 카메라와 캐릭터의 컨트롤 방식을 변경하는 시스템을 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨트롤 모드를 Enum으로 구분한다.&lt;/p&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;UENUM(BlueprintType)
enum class EPlayerControlMode : uint8
{
    ThirdPerson UMETA(DisplayName = &quot;Third Person&quot;),
    FirstPerson UMETA(DisplayName = &quot;First Person&quot;),
    TopDown UMETA(DisplayName = &quot;Top Down&quot;),
    Shoulder UMETA(DisplayName = &quot;Shoulder / Aim&quot;)
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Enum을 사용하는 이유는 여러 모드를 명확하게 구분하고, 이후 모드가 추가되더라도 관리하기 쉽도록 하기 위해서이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;9. ChangeControlMode와 ApplyControlMode&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 함수를 분리해서 사용했다.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;void ChangeControlMode();
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 다음에 어떤 모드로 변경할지 결정&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;void ApplyControlMode(
    EPlayerControlMode NewControlMode
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 선택된 모드의 실제 설정을 적용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;책임을 나누면 함수 하나가 너무 많은 역할을 담당하지 않게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨트롤 모드 변경 흐름은 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;ThirdPerson
    &amp;darr;
FirstPerson
    &amp;darr;
TopDown
    &amp;darr;
Shoulder
    &amp;darr;
ThirdPerson
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;10. 컨트롤 모드별 설정&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Third Person&lt;/h2&gt;
&lt;pre class=&quot;fortran&quot;&gt;&lt;code&gt;Camera
&amp;rarr; SpringArm 사용
&amp;rarr; Controller Rotation 사용

Character
&amp;rarr; Controller Yaw 직접 사용 X
&amp;rarr; 이동 방향으로 회전
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주요 설정:&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;bUseControllerRotationYaw = false;
bOrientRotationToMovement = true;
bUseControllerDesiredRotation = false;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;First Person&lt;/h2&gt;
&lt;pre class=&quot;fortran&quot;&gt;&lt;code&gt;Camera
&amp;rarr; Character 머리 위치

Character
&amp;rarr; Controller Yaw를 따라감
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주요 설정:&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;bUseControllerRotationYaw = true;
bOrientRotationToMovement = false;
bUseControllerDesiredRotation = false;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Top Down&lt;/h2&gt;
&lt;pre class=&quot;fortran&quot;&gt;&lt;code&gt;Camera
&amp;rarr; 높은 위치에서 내려다봄

Character
&amp;rarr; 이동 방향으로 회전
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주요 설정:&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;bUseControllerRotationYaw = false;
bOrientRotationToMovement = true;
bUseControllerDesiredRotation = false;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Shoulder / Aim&lt;/h2&gt;
&lt;pre class=&quot;fortran&quot;&gt;&lt;code&gt;Camera
&amp;rarr; Character 오른쪽 어깨 방향
&amp;rarr; Controller Rotation 사용

Character
&amp;rarr; Controller Yaw를 따라감
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주요 설정:&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;bUseControllerRotationYaw = true;
bOrientRotationToMovement = false;
bUseControllerDesiredRotation = false;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;11. 예외 처리의 중요성&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C++ 코드를 작성할 때 정상적인 상황만 생각하지 않고 객체가 존재하지 않는 상황도 고려해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;pre class=&quot;coq&quot;&gt;&lt;code&gt;if (!MovementComponent || !CameraBoom || !FollowCamera)
{
    return;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 방어 코드를 추가하면 필요한 객체가 준비되지 않았을 때 바로 접근해서 문제가 발생하는 것을 막을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로 AI에게 코드를 요청할 때도 &lt;b&gt;예외 처리와 방어 코드가 필요한 부분을 함께 확인해 달라고 요청하는 습관&lt;/b&gt;을 가지는 것이 좋다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;12. 이번 주 복습 포인트&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주에는 다음 내용을 다시 확인했다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이동 구현&lt;/li&gt;
&lt;li&gt;마우스 회전&lt;/li&gt;
&lt;li&gt;ControlRotation&lt;/li&gt;
&lt;li&gt;PlayerController&lt;/li&gt;
&lt;li&gt;bUseControllerRotationYaw&lt;/li&gt;
&lt;li&gt;bUseControllerDesiredRotation&lt;/li&gt;
&lt;li&gt;bOrientRotationToMovement&lt;/li&gt;
&lt;li&gt;RotationRate&lt;/li&gt;
&lt;li&gt;SpringArm::bUsePawnControlRotation&lt;/li&gt;
&lt;li&gt;UObject와 Actor의 차이&lt;/li&gt;
&lt;li&gt;UObject의 생명주기&lt;/li&gt;
&lt;li&gt;Actor의 생명주기&lt;/li&gt;
&lt;li&gt;Destroy()와 C++ delete의 차이&lt;/li&gt;
&lt;li&gt;TObjectPtr&lt;/li&gt;
&lt;li&gt;Actor Owner와 Attachment의 차이&lt;/li&gt;
&lt;li&gt;Enum을 이용한 Control Mode 분리&lt;/li&gt;
&lt;li&gt;Third Person / First Person / Top Down / Shoulder Mode&lt;/li&gt;
&lt;li&gt;함수의 책임 분리&lt;/li&gt;
&lt;li&gt;C++ 방어 코드와 예외 처리&lt;/li&gt;
&lt;li&gt;기획서에 맞춰 컨트롤 모드를 수정하는 과정&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;느낀 점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 단순히 캐릭터를 움직이는 것에서 끝나는 것이 아니라, &lt;b&gt;Controller &amp;rarr; ControlRotation &amp;rarr; Character / Movement &amp;rarr; Camera&lt;/b&gt;가 어떻게 연결되는지 다시 정리할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 UObject, Actor, Owner처럼 Unreal에서 자주 사용하지만 서로 헷갈리기 쉬운 개념들을 복습하면서, 단순히 코드를 따라 작성하는 것보다 &lt;b&gt;각 객체와 기능이 어떤 역할을 담당하는지 이해하는 것이 중요하다는 점&lt;/b&gt;을 다시 확인했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웨이브 시스템에서는 웨이브가 끝났을 때 남아있는 악몽을 기준으로 침대 Stress를 증가시키고 HUD의 악몽 수를 초기화하는 기능까지 연결했다.&lt;/p&gt;</description>
      <author>view29579</author>
      <guid isPermaLink="true">https://view29579.tistory.com/53</guid>
      <comments>https://view29579.tistory.com/53#entry53comment</comments>
      <pubDate>Thu, 17 Sep 2026 20:19:58 +0900</pubDate>
    </item>
    <item>
      <title>TIL-2nd. 팀프로젝트 DreamProtector (8/21)WaveManager 웨이브 종료 처리 및 4차 분반수업 내용 정리</title>
      <link>https://view29579.tistory.com/52</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;오늘은 기존에 구현해둔 &lt;/span&gt;&lt;span&gt;WaveManager&lt;/span&gt;&lt;span&gt;에 &lt;/span&gt;&lt;b&gt;&lt;span&gt;웨이브 종료 시 남아있는 악몽을 침대에 데미지로 반영하고, HUD의 악몽 수를 초기화하는 기능​&lt;/span&gt;&lt;/b&gt;&lt;span&gt;을 추가했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기존 웨이브 시스템은 &lt;/span&gt;&lt;span&gt;CurrentMonsterCount&lt;/span&gt;&lt;span&gt;와 &lt;/span&gt;&lt;span&gt;KilledMonsterCount&lt;/span&gt;&lt;span&gt;를 이용해서 현재 웨이브의 남은 악몽 수를 계산하고 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;const int32 RemainingCount =
    FMath::Max(CurrentMonsterCount - KilledMonsterCount, 0);&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;RemainingCount&lt;/span&gt;&lt;span&gt;를 계산한 이유&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;현재 웨이브의 전체 악몽 수에서 처치한 악몽 수를 빼면 남아있는 악몽 수를 알 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;fix&quot;&gt;&lt;code&gt;전체 악몽 수 - 처치한 악몽 수 = 남은 악몽 수&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어 45마리가 스폰되고 30마리를 처치했다면:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;basic&quot;&gt;&lt;code&gt;45 - 30 = 15&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 남은 악몽은 15마리이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 &lt;/span&gt;&lt;span&gt;FMath::Max()&lt;/span&gt;&lt;span&gt;를 사용한 이유는 계산 결과가 음수가 되는 것을 방지하기 위해서이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;FMath::Max(CurrentMonsterCount - KilledMonsterCount, 0);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;결과가 0보다 작아지더라도 최소값을 0으로 유지한다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;2. 웨이브 종료 시 침대에 Stress 적용&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;웨이브 제한시간이 끝났을 때 호출되는 함수인 &lt;/span&gt;&lt;span&gt;OnWaveTimeExpired()&lt;/span&gt;&lt;span&gt;에서 남은 악몽 수를 확인하도록 했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;const int32 RemainingCount =
    FMath::Max(CurrentMonsterCount - KilledMonsterCount, 0);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그리고 남아있는 악몽 1마리당 침대 Stress를 &lt;/span&gt;&lt;b&gt;&lt;span&gt;10&lt;/span&gt;&lt;/b&gt;&lt;span&gt; 증가시키도록 했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;erlang&quot;&gt;&lt;code&gt;if (Bed &amp;amp;&amp;amp; RemainingCount &amp;gt; 0)
{
    Bed-&amp;gt;IncreaseStress(RemainingCount * 10);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;RemainingCount * 10&lt;/span&gt;&lt;span&gt;을 사용하는 이유&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기획상 웨이브가 종료되었을 때 살아남은 악몽이 침대를 공격하는 것으로 처리하기 위해서이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;악몽 1마리당 Stress 10이므로:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;남은 악몽 1마리 &amp;rarr; Stress +10
남은 악몽 5마리 &amp;rarr; Stress +50
남은 악몽 10마리 &amp;rarr; Stress +100&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 남은 악몽 수에 10을 곱해서 한 번에 침대에 전달했다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;3. &lt;/span&gt;&lt;span&gt;Bed-&amp;gt;IncreaseStress()&lt;/span&gt;&lt;span&gt;를 사용한 이유&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;침대에는 이미 &lt;/span&gt;&lt;span&gt;IncreaseStress()&lt;/span&gt;&lt;span&gt; 함수가 구현되어 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;void ABed::IncreaseStress(int32 Amount)
{
    CurrentStress += Amount;

    CurrentStress =
        FMath::Clamp(CurrentStress, 0, MaxStress);

    OnStressChganged.Broadcast(
        CurrentStress,
        MaxStress
    );

    OnBedAttacked.Broadcast();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;WaveManager에서 침대의 Stress 값을 직접 변경하지 않고 기존 함수를 호출했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;xl&quot;&gt;&lt;code&gt;Bed-&amp;gt;IncreaseStress(RemainingCount * 10);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게 한 이유는 &lt;/span&gt;&lt;b&gt;&lt;span&gt;침대의 Stress 처리를 Bed 클래스가 담당하도록 하기 위해서&lt;/span&gt;&lt;/b&gt;&lt;span&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;WaveManager가 직접:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;xl&quot;&gt;&lt;code&gt;Bed-&amp;gt;CurrentStress += ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;처럼 처리하게 되면 WaveManager가 침대 내부의 Stress 시스템까지 알아야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;반면 &lt;/span&gt;&lt;span&gt;IncreaseStress()&lt;/span&gt;&lt;span&gt;를 사용하면 WaveManager는&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&quot;침대의 Stress를 이만큼 증가시켜줘.&quot;&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;라고 요청만 하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;실제 Stress 증가, 최대값 제한, HUD 알림, 침대 공격 알림은 &lt;/span&gt;&lt;span&gt;ABed&lt;/span&gt;&lt;span&gt;가 담당한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉 역할을 나누었다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;WaveManager
&amp;rarr; 남은 악몽 수 계산
&amp;rarr; 침대에 증가량 전달

Bed
&amp;rarr; Stress 증가
&amp;rarr; 최대 Stress 제한
&amp;rarr; Stress 변경 알림
&amp;rarr; 침대 공격 알림&lt;/code&gt;&lt;/pre&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;4. &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; 방어 코드를 추가한 이유&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;침대 객체가 연결되지 않은 상태에서 바로:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;xl&quot;&gt;&lt;code&gt;Bed-&amp;gt;IncreaseStress(...);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;를 호출하면 문제가 발생할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그래서 다음과 같이 방어 코드를 작성했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;erlang&quot;&gt;&lt;code&gt;if (Bed &amp;amp;&amp;amp; RemainingCount &amp;gt; 0)
{
    Bed-&amp;gt;IncreaseStress(RemainingCount * 10);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 두 가지를 확인한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Bed
&amp;rarr; 침대 객체가 존재하는가?

RemainingCount &amp;gt; 0
&amp;rarr; 실제로 남아있는 악몽이 있는가?&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;둘 다 만족할 때만 침대 Stress를 증가시킨다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번 작업을 통해 &lt;/span&gt;&lt;b&gt;&lt;span&gt;C++에서 객체를 사용하기 전에 유효한지 확인하는 방어 코드가 중요하다&lt;/span&gt;&lt;/b&gt;&lt;span&gt;는 것도 다시 확인했다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;5. 웨이브 종료 후 HUD 악몽 수 초기화&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기존에는 웨이브가 끝나도 HUD에 이전 웨이브의 숫자가 남아있었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;basic&quot;&gt;&lt;code&gt;15 / 45&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;상태에서 웨이브가 종료되어 대기시간으로 들어가도 숫자가 그대로 표시될 수 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그래서 웨이브 종료 시:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;OnMonsterCountChanged.Broadcast(
    0,
    0
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;을 호출하도록 했다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;Broadcast()&lt;/span&gt;&lt;span&gt;를 사용한 이유&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;OnMonsterCountChanged&lt;/span&gt;&lt;span&gt;는 몬스터 수가 변경되었을 때 HUD 등 다른 시스템에 알려주는 Delegate이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 WaveManager가 HUD를 직접 찾아서 텍스트를 변경하는 대신:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;WaveManager
    &amp;darr;
OnMonsterCountChanged.Broadcast()
    &amp;darr;
HUD
    &amp;darr;
악몽 숫자 변경&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;방식으로 연결했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;웨이브 종료 시 &lt;/span&gt;&lt;span&gt;0, 0&lt;/span&gt;&lt;span&gt;을 전달하면 대기시간 동안:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;basic&quot;&gt;&lt;code&gt;00 / 00&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;으로 표시할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 두 번째 값까지 0으로 전달한 이유는 단순히 남은 악몽 수만 0으로 만드는 것이 아니라 &lt;/span&gt;&lt;b&gt;&lt;span&gt;대기시간 동안 전체 악몽 수도 표시하지 않도록 하기 위해서&lt;/span&gt;&lt;/b&gt;&lt;span&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;6. 전체 흐름&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;최종적으로 웨이브 제한시간이 끝나면 다음 순서로 처리된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;OnWaveTimeExpired()
        &amp;darr;
현재 웨이브의 전체 악몽 수 확인
        &amp;darr;
처치한 악몽 수 확인
        &amp;darr;
RemainingCount 계산
        &amp;darr;
남은 악몽 &amp;times; 10
        &amp;darr;
Bed-&amp;gt;IncreaseStress()
        &amp;darr;
침대 Stress 증가
        &amp;darr;
OnMonsterCountChanged.Broadcast(0, 0)
        &amp;darr;
HUD &amp;rarr; 00 / 00
        &amp;darr;
대기시간
        &amp;darr;
다음 웨이브 시작
        &amp;darr;
새로운 몬스터 수 표시&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어 Stage 2에서 45마리가 등장하고 32마리를 처치한 상태로 웨이브가 끝났다면:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;45 - 32 = 13마리 생존

13 &amp;times; 10 = Stress +130

HUD &amp;rarr; 00 / 00&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;침대의 &lt;/span&gt;&lt;span&gt;MaxStress&lt;/span&gt;&lt;span&gt;가 100이므로 실제 Stress는 &lt;/span&gt;&lt;span&gt;ABed::IncreaseStress()&lt;/span&gt;&lt;span&gt; 내부의 &lt;/span&gt;&lt;span&gt;FMath::Clamp()&lt;/span&gt;&lt;span&gt;에 의해 최대 100까지만 증가한다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;7. 이번 작업에서 중요했던 점&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번 작업에서는 새로운 시스템을 크게 만드는 것보다 &lt;/span&gt;&lt;b&gt;&lt;span&gt;기존에 만들어둔 시스템을 연결하는 방식&lt;/span&gt;&lt;/b&gt;&lt;span&gt;으로 구현했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;WaveManager
&amp;rarr; 웨이브와 몬스터 수 관리

Bed
&amp;rarr; Stress 관리

HUD
&amp;rarr; Delegate를 통해 몬스터 수 표시&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;각 클래스가 자신의 역할을 담당하도록 유지하면서 필요한 부분만 연결했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;특히 WaveManager에서 침대의 Stress 내부 값을 직접 수정하지 않고 &lt;/span&gt;&lt;span&gt;IncreaseStress()&lt;/span&gt;&lt;span&gt;를 호출한 것이 중요한 부분이었다.&lt;/span&gt;&lt;/p&gt;</description>
      <author>view29579</author>
      <guid isPermaLink="true">https://view29579.tistory.com/52</guid>
      <comments>https://view29579.tistory.com/52#entry52comment</comments>
      <pubDate>Thu, 17 Sep 2026 20:16:23 +0900</pubDate>
    </item>
    <item>
      <title>TIL-2nd. 팀프로젝트 DreamProtector (7/21) SpawnVolume / WaveManager 수</title>
      <link>https://view29579.tistory.com/51</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;1. SpawnVolume과 WaveManager의 역할 확인&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;현재 프로젝트에서는 &lt;/span&gt;&lt;span&gt;ASpawnVolume&lt;/span&gt;&lt;span&gt;이 몬스터를 직접 생성하는 것이 아니라, &lt;/span&gt;&lt;b&gt;&lt;span&gt;스폰 영역 안의 랜덤한 위치를 반환하는 역할&lt;/span&gt;&lt;/b&gt;&lt;span&gt;을 담당하고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;php&quot;&gt;&lt;code&gt;FVector ASpawnVolume::GetRandomSpawnLocation() const
{
    const FVector Origin = SpawnBox-&amp;gt;GetComponentLocation();
    const FVector Extent = SpawnBox-&amp;gt;GetScaledBoxExtent();

    return Origin + FVector(
        FMath::FRandRange(-Extent.X, Extent.X),
        FMath::FRandRange(-Extent.Y, Extent.Y),
        FMath::FRandRange(-Extent.Z, Extent.Z)
    );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;실제 몬스터 생성은 &lt;/span&gt;&lt;span&gt;AWaveManager::SpawnCurrentWave()&lt;/span&gt;&lt;span&gt;에서 담당하고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;const FVector SpawnLocation = SpawnVolume-&amp;gt;GetRandomSpawnLocation();

GetWorld()-&amp;gt;SpawnActor&amp;lt;AActor&amp;gt;(
    MonsterData.MonsterClass,
    SpawnLocation,
    FRotator::ZeroRotator
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 &lt;/span&gt;&lt;b&gt;&lt;span&gt;스폰되는 몬스터의 개별 이동속도를 설정하는 기능은 SpawnVolume보다 WaveManager에서 처리하는 것이 적절하다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;2. 같은 종류의 몬스터도 개체마다 다른 이동속도 적용&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하나의 몬스터 BP를 여러 번 스폰하면서 각각 다른 이동속도를 적용하기로 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어 같은 &lt;/span&gt;&lt;span&gt;BP_Melee&lt;/span&gt;&lt;span&gt;를 스폰하더라도:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Melee 1 &amp;rarr; 215
Melee 2 &amp;rarr; 387
Melee 3 &amp;rarr; 452
Melee 4 &amp;rarr; 301&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;처럼 개체마다 다른 이동속도를 가질 수 있도록 구현했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기존에는:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;GetWorld()-&amp;gt;SpawnActor&amp;lt;AActor&amp;gt;(
    MonsterData.MonsterClass,
    SpawnLocation,
    FRotator::ZeroRotator
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;형태로 생성했지만, 생성된 몬스터를 &lt;/span&gt;&lt;span&gt;ABaseMonster*&lt;/span&gt;&lt;span&gt;로 받아서 속도를 설정하도록 변경했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;ABaseMonster* SpawnedMonster = GetWorld()-&amp;gt;SpawnActor&amp;lt;ABaseMonster&amp;gt;(
    MonsterData.MonsterClass,
    SpawnLocation,
    FRotator::ZeroRotator
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그리고 &lt;/span&gt;&lt;span&gt;ABaseMonster&lt;/span&gt;&lt;span&gt;에 이동속도를 변경하는 함수를 추가했다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;BaseMonster.h&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;void SetMoveSpeed(float NewSpeed);&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;BaseMonster.cpp&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;void ABaseMonster::SetMoveSpeed(float NewSpeed)
{
    MoveSpeed = NewSpeed;

    if (GetCharacterMovement())
    {
        GetCharacterMovement()-&amp;gt;MaxWalkSpeed = MoveSpeed;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이후 &lt;/span&gt;&lt;span&gt;WaveManager&lt;/span&gt;&lt;span&gt;에서 스폰될 때마다 랜덤한 속도를 적용했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;erlang&quot;&gt;&lt;code&gt;if (SpawnedMonster)
{
    SpawnedMonster-&amp;gt;SetMoveSpeed(
        FMath::FRandRange(200.0f, 500.0f)
    );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이를 통해 &lt;/span&gt;&lt;b&gt;&lt;span&gt;같은 몬스터 클래스라도 생성된 각각의 몬스터가 200~500 사이의 랜덤한 이동속도&lt;/span&gt;&lt;/b&gt;&lt;span&gt;를 가지도록 했다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;3. MoveSpeed와 MaxWalkSpeed의 차이 확인&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;처음에는 &lt;/span&gt;&lt;span&gt;MoveSpeed&lt;/span&gt;&lt;span&gt; 값을 랜덤하게 변경했는데도 실제 몬스터의 이동속도가 변하지 않는 문제가 발생했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ABaseMonster&lt;/span&gt;&lt;span&gt;의 생성자에서는 기본 이동속도를 다음과 같이 설정하고 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;MoveSpeed = 300.0f;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또한 &lt;/span&gt;&lt;span&gt;BeginPlay()&lt;/span&gt;&lt;span&gt;에서 &lt;/span&gt;&lt;span&gt;MoveSpeed&lt;/span&gt;&lt;span&gt;를 실제 캐릭터 이동속도에 적용하고 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;void ABaseMonster::BeginPlay()
{
    Super::BeginPlay();

    CurrentHealth = MaxHealth;

    if (GetCharacterMovement())
    {
        GetCharacterMovement()-&amp;gt;MaxWalkSpeed = MoveSpeed;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;문제는 실행 순서였다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;몬스터 생성
&amp;darr;
생성자에서 MoveSpeed = 300
&amp;darr;
BeginPlay()
&amp;darr;
MaxWalkSpeed = 300
&amp;darr;
WaveManager에서 MoveSpeed를 랜덤값으로 변경&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 &lt;/span&gt;&lt;span&gt;WaveManager&lt;/span&gt;&lt;span&gt;에서 &lt;/span&gt;&lt;span&gt;MoveSpeed&lt;/span&gt;&lt;span&gt;만 변경하면 &lt;/span&gt;&lt;span&gt;CharacterMovementComponent&lt;/span&gt;&lt;span&gt;의 &lt;/span&gt;&lt;span&gt;MaxWalkSpeed&lt;/span&gt;&lt;span&gt;는 이미 300으로 설정된 상태였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 문제를 해결하기 위해 &lt;/span&gt;&lt;span&gt;SetMoveSpeed()&lt;/span&gt;&lt;span&gt;에서 &lt;/span&gt;&lt;b&gt;&lt;span&gt;스탯 변수와 실제 이동속도를 동시에 변경&lt;/span&gt;&lt;/b&gt;&lt;span&gt;하도록 했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;void ABaseMonster::SetMoveSpeed(float NewSpeed)
{
    MoveSpeed = NewSpeed;

    if (GetCharacterMovement())
    {
        GetCharacterMovement()-&amp;gt;MaxWalkSpeed = MoveSpeed;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이를 통해 스폰 이후 변경된 랜덤 속도가 실제 이동속도에도 적용되도록 했다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;4. 랜덤 이동속도 적용 여부 디버깅&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;실제로 랜덤값이 적용되고 있는지 확인하기 위해 로그를 추가했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;UE_LOG(
    LogTemp,
    Warning,
    TEXT(&quot;AFTER RANDOM Speed: %f&quot;),
    SpawnedMonster-&amp;gt;MoveSpeed
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;처음에는 &lt;/span&gt;&lt;span&gt;300&lt;/span&gt;&lt;span&gt;만 출력되는 것으로 확인하여 원인을 추적했지만, 이후 확인 결과 &lt;/span&gt;&lt;b&gt;&lt;span&gt;실제로는 랜덤한 값이 정상적으로 들어가고 있는 것을 확인했다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 문제의 원인은 랜덤값 생성이나 &lt;/span&gt;&lt;span&gt;WaveManager&lt;/span&gt;&lt;span&gt;의 스폰 로직이 아니라, &lt;/span&gt;&lt;b&gt;&lt;span&gt;MoveSpeed&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span&gt;가 실제 이동 시스템의 &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span&gt;MaxWalkSpeed&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span&gt;에 적용되는 시점&lt;/span&gt;&lt;/b&gt;&lt;span&gt;에 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;5. WaveManager의 웨이브 스폰 구조 확인&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;현재 &lt;/span&gt;&lt;span&gt;WaveManager&lt;/span&gt;&lt;span&gt;는 DataTable의 &lt;/span&gt;&lt;span&gt;FWaveData&lt;/span&gt;&lt;span&gt;를 이용해 웨이브 정보를 관리한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;FWaveMonsterData&lt;/span&gt;&lt;span&gt;에서는:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;UPROPERTY(EditAnywhere, BlueprintReadWrite)
TSubclassOf&amp;lt;AActor&amp;gt; MonsterClass;

UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 SpawnCount = 0;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;를 통해 몬스터 클래스와 스폰 개수를 관리한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그리고 &lt;/span&gt;&lt;span&gt;SpawnCurrentWave()&lt;/span&gt;&lt;span&gt;에서:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;for (const FWaveMonsterData&amp;amp; MonsterData : WaveData-&amp;gt;Monsters)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;를 통해 웨이브에 등록된 몬스터 종류를 확인하고,&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;matlab&quot;&gt;&lt;code&gt;for (int32 i = 0; i &amp;lt; MonsterData.SpawnCount; ++i)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;를 통해 설정된 개수만큼 반복해서 스폰한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또한:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;matlab&quot;&gt;&lt;code&gt;ASpawnVolume* SpawnVolume =
    SpawnVolumes[i % WaveData-&amp;gt;SpawnVolumeCount];&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;를 사용해 여러 SpawnVolume에 몬스터를 분배하고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이를 통해 현재 프로젝트의 &lt;/span&gt;&lt;b&gt;&lt;span&gt;DataTable &amp;rarr; WaveManager &amp;rarr; SpawnVolume &amp;rarr; Monster&lt;/span&gt;&lt;/b&gt;&lt;span&gt; 구조를 다시 확인할 수 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;Git 작업&lt;/span&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;6. GitHub Push 시 대용량 파일 오류 발생&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;GitHub에 Push하는 과정에서 다음 오류가 발생했다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;The push operation includes a file which exceeds GitHub's file size restriction of 100MB.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;원인을 확인한 결과, 배포받은 &lt;/span&gt;&lt;b&gt;&lt;span&gt;약 8GB 크기의 압축파일을 프로젝트 폴더에 삭제하지 않은 상태에서 Git 작업을 진행한 것&lt;/span&gt;&lt;/b&gt;&lt;span&gt;이 원인이었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;GitHub에는 일반 Git 저장소에서 개별 파일을 업로드할 때 100MB 제한이 있기 때문에 프로젝트에 불필요한 대용량 압축파일이 포함되지 않도록 주의해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;7. Git lock 파일 오류 확인&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이후 다음 오류도 발생했다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;A lock file already exists in the repository, which blocks this operation from completing.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Git 작업 중 생성된 &lt;/span&gt;&lt;span&gt;.git/index.lock&lt;/span&gt;&lt;span&gt; 파일을 확인하고 삭제했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 과정에서 &lt;/span&gt;&lt;b&gt;&lt;span&gt;대용량 파일 문제와 Git lock 문제는 서로 다른 문제&lt;/span&gt;&lt;/b&gt;&lt;span&gt;라는 것도 확인했다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;오늘 배운 점&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;SpawnVolume&lt;/span&gt;&lt;span&gt;은 스폰 위치를 제공하고, 실제 몬스터 생성은 &lt;/span&gt;&lt;span&gt;WaveManager&lt;/span&gt;&lt;span&gt;에서 담당한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;같은 몬스터 BP를 사용해도 &lt;/span&gt;&lt;b&gt;&lt;span&gt;생성된 개체마다 다른 스탯을 적용할 수 있다.&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;MoveSpeed&lt;/span&gt;&lt;span&gt; 같은 스탯 변수와 실제 이동에 사용되는 &lt;/span&gt;&lt;span&gt;MaxWalkSpeed&lt;/span&gt;&lt;span&gt;는 별개의 값이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;BeginPlay()&lt;/span&gt;&lt;span&gt;에서 &lt;/span&gt;&lt;span&gt;MoveSpeed&lt;/span&gt;&lt;span&gt;를 &lt;/span&gt;&lt;span&gt;MaxWalkSpeed&lt;/span&gt;&lt;span&gt;에 적용한 뒤 &lt;/span&gt;&lt;span&gt;MoveSpeed&lt;/span&gt;&lt;span&gt;만 변경하면 실제 이동속도에는 반영되지 않을 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;따라서 스폰 이후 이동속도를 변경할 때는 &lt;/span&gt;&lt;span&gt;MoveSpeed&lt;/span&gt;&lt;span&gt;와 &lt;/span&gt;&lt;span&gt;MaxWalkSpeed&lt;/span&gt;&lt;span&gt;를 함께 변경해야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;SetMoveSpeed()&lt;/span&gt;&lt;span&gt; 같은 함수를 만들어 스탯 변경과 실제 시스템 적용을 한 번에 처리하는 방법을 익혔다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;DataTable을 이용한 웨이브 구조에서 몬스터 종류와 스폰 개수를 관리하고, 실제 개체별 추가 설정은 &lt;/span&gt;&lt;span&gt;SpawnCurrentWave()&lt;/span&gt;&lt;span&gt;에서 처리할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;GitHub에 Push하기 전에 프로젝트 폴더에 대용량 압축파일이나 불필요한 파일이 포함되어 있지 않은지 확인해야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Git의 &lt;/span&gt;&lt;span&gt;index.lock&lt;/span&gt;&lt;span&gt;은 Git 작업을 막을 수 있는 잠금 파일이며, Git 프로세스가 종료된 것을 확인한 후 제거할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>view29579</author>
      <guid isPermaLink="true">https://view29579.tistory.com/51</guid>
      <comments>https://view29579.tistory.com/51#entry51comment</comments>
      <pubDate>Tue, 15 Sep 2026 20:55:41 +0900</pubDate>
    </item>
    <item>
      <title>TIL-2nd. 팀프로젝트 DreamProtector (6/21) WaveManager / SpawnVolume 웨이브 시스템 구현</title>
      <link>https://view29579.tistory.com/50</link>
      <description>&lt;h1&gt;&lt;span&gt;1. 오늘 구현한 것&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;오늘은 &lt;/span&gt;&lt;span&gt;WaveManager&lt;/span&gt;&lt;span&gt;를 중심으로 게임의 &lt;/span&gt;&lt;b&gt;&lt;span&gt;웨이브 시스템 기본 구조&lt;/span&gt;&lt;/b&gt;&lt;span&gt;를 구현했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;구현한 기능은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;SpawnVolume 구현&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;WaveData 구조체 구현&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;DataTable을 이용한 웨이브 데이터 관리&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;현재 웨이브 데이터 가져오기&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;웨이브별 몬스터 수 계산&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;몬스터 스폰&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;SpawnVolume을 이용한 랜덤 스폰 위치 지정&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;튜토리얼 30초 대기&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Wave별 제한시간 설정&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;웨이브 종료 후 45초 대기&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;다음 웨이브 자동 시작&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;최대 웨이브 이후 더 이상 웨이브가 진행되지 않도록 처리&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;빌드 오류 트러블슈팅&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;현재 기획은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구분몬스터 수SpawnVolume제한시간&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;Wave 1&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;30마리&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;2개&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;60초&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;Wave 2&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;45마리&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;3개&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;90초&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;Wave 3&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;60마리&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;4개&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;90초&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;튜토리얼은 30초이며, 웨이브 사이에는 45초의 대기시간을 둔다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;2. SpawnVolume&lt;/span&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;SpawnVolume의 역할&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;SpawnVolume은 &lt;/span&gt;&lt;b&gt;&lt;span&gt;몬스터를 실제로 관리하는 객체가 아니라, 몬스터가 스폰될 수 있는 위치를 제공하는 역할&lt;/span&gt;&lt;/b&gt;&lt;span&gt;을 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉,&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;SpawnVolume
&amp;rarr; &quot;이 영역 안에서 랜덤한 위치 하나 줘&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;라고 요청하면 랜덤한 위치를 반환한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;실제 어떤 몬스터를 몇 마리 스폰할지는 &lt;/span&gt;&lt;span&gt;WaveManager&lt;/span&gt;&lt;span&gt;가 담당한다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;SpawnVolume 생성자&lt;/span&gt;&lt;/h2&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;ASpawnVolume::ASpawnVolume()
{
    // 스폰 영역 박스 컴포 생성
    SpawnBox = CreateDefaultSubobject&amp;lt;UBoxComponent&amp;gt;(TEXT(&quot;SpawnBox&quot;));

    // 스폰볼륨 액터의 루트컴포를 스폰박스로 지정
    RootComponent = SpawnBox;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;코드 의미&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;CreateDefaultSubobject&amp;lt;UBoxComponent&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;를 이용해 &lt;/span&gt;&lt;span&gt;BoxComponent&lt;/span&gt;&lt;span&gt;를 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 박스가 실제로 &lt;/span&gt;&lt;b&gt;&lt;span&gt;몬스터가 랜덤하게 생성될 영역&lt;/span&gt;&lt;/b&gt;&lt;span&gt;이 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그리고&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;RootComponent = SpawnBox;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;를 통해 생성한 BoxComponent를 SpawnVolume Actor의 RootComponent로 지정한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 레벨에 &lt;/span&gt;&lt;span&gt;BP_SpawnVolume&lt;/span&gt;&lt;span&gt;을 배치하면 Box의 크기를 조절하여 스폰 영역을 지정할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;3. 랜덤 스폰 위치 만들기&lt;/span&gt;&lt;/h1&gt;
&lt;pre class=&quot;php&quot;&gt;&lt;code&gt;FVector ASpawnVolume::GetRandomSpawnLocation() const
{
    // SpawnBox의 월드 위치를 가져온다.
    const FVector Origin = SpawnBox-&amp;gt;GetComponentLocation();

    // SpawnBox의 실제 월드 크기(절반)를 가져온다.
    const FVector Extent = SpawnBox-&amp;gt;GetScaledBoxExtent();

    // Box 범위 안에서 X, Y, Z가 각각 랜덤인 위치를 반환한다.
    return Origin + FVector(
        FMath::FRandRange(-Extent.X, Extent.X),
        FMath::FRandRange(-Extent.Y, Extent.Y),
        FMath::FRandRange(-Extent.Z, Extent.Z)
    );
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;코드 의미&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;먼저 SpawnBox의 중심 위치를 가져온다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;const FVector Origin = SpawnBox-&amp;gt;GetComponentLocation();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그리고 Box의 크기를 가져온다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;const FVector Extent = SpawnBox-&amp;gt;GetScaledBoxExtent();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Extent&lt;/span&gt;&lt;span&gt;는 박스 전체 크기가 아니라 &lt;/span&gt;&lt;b&gt;&lt;span&gt;중심에서 각 방향으로 얼마나 떨어져 있는지&lt;/span&gt;&lt;/b&gt;&lt;span&gt;를 나타낸다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어 X 방향 범위가 &lt;/span&gt;&lt;span&gt;-500 ~ +500&lt;/span&gt;&lt;span&gt;이라면:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;sas&quot;&gt;&lt;code&gt;FMath::FRandRange(-Extent.X, Extent.X)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;를 이용해 그 사이의 랜덤한 값을 만든다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;X, Y, Z 각각에 랜덤값을 적용하기 때문에 최종적으로 &lt;/span&gt;&lt;b&gt;&lt;span&gt;SpawnBox 내부의 랜덤한 위치&lt;/span&gt;&lt;/b&gt;&lt;span&gt;를 반환한다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;4. WaveManager의 웨이브 데이터 구조&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;웨이브마다 필요한 정보를 DataTable에서 관리하기 위해 두 개의 구조체를 만들었다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;FWaveMonsterData&lt;/span&gt;&lt;/h2&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;USTRUCT(BlueprintType)
struct FWaveMonsterData
{
    GENERATED_BODY()

    // 스폰할 몬스터 클래스
    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    TSubclassOf&amp;lt;AActor&amp;gt; MonsterClass;

    // 해당 몬스터를 몇 마리 스폰할지
    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    int32 SpawnCount = 0;
};&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;의미&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하나의 몬스터 종류에 대한 정보를 담는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;MonsterClass = BP_Suicide
SpawnCount = 30&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이라고 설정하면&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;BP_Suicide를 30마리 스폰한다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;는 의미가 된다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;5. FWaveData&lt;/span&gt;&lt;/h1&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;USTRUCT(BlueprintType)
struct FWaveData : public FTableRowBase
{
    GENERATED_BODY()

    // 해당 웨이브에서 사용할 몬스터 목록
    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    TArray&amp;lt;FWaveMonsterData&amp;gt; Monsters;

    // 해당 웨이브에서 사용할 스폰볼륨 개수
    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    int32 SpawnVolumeCount = 0;

    // 해당 웨이브의 제한시간(초)
    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    float WaveTimeLimit = 60.0f;
};&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;의미&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;FWaveData&lt;/span&gt;&lt;span&gt;는 &lt;/span&gt;&lt;b&gt;&lt;span&gt;하나의 웨이브 전체에 대한 정보&lt;/span&gt;&lt;/b&gt;&lt;span&gt;를 담는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉 한 행이 하나의 웨이브가 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Wave1
 ├─ Monsters
 │   └─ BP_Suicide / 30
 ├─ SpawnVolumeCount = 2
 └─ WaveTimeLimit = 60&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;DataTable에서 이 데이터를 관리할 수 있도록&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;public FTableRowBase&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;를 상속했다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;6. WaveManager 변수&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;현재 WaveManager에서는 다음과 같은 변수를 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;protobuf&quot;&gt;&lt;code&gt;// 현재 진행 중인 웨이브 번호
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Wave&quot;)
int32 CurrentWave = 1;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;현재 몇 번째 웨이브인지 저장한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;처음에는 &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;이므로 Wave 1부터 시작한다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;pre class=&quot;protobuf&quot;&gt;&lt;code&gt;// 전체 웨이브 개수
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Wave&quot;)
int32 MaxWave = 3;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;전체 웨이브의 개수를 나타낸다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;현재 프로젝트에서는 총 3웨이브이므로 &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;pre class=&quot;protobuf&quot;&gt;&lt;code&gt;// 현재 웨이브에서 아직 처리해야 할 몬스터 수
// 웨이브 시작 시 해당 웨이브의 몬스터 수를 넣어줌
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Wave&quot;)
int32 CurrentMonsterCount = 0;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;현재 웨이브의 몬스터 수를 관리하기 위한 변수이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;현재는 웨이브 시스템 기본 구현 단계이며, 이후 몬스터 사망 처리와 연결할 예정이다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;7. SpawnVolume 배열&lt;/span&gt;&lt;/h1&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;// 웨이브에서 사용할 스폰볼륨 목록
// 레벨에 배치된 스폰볼륨들을 웨이브매니저가 참조
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Wave|Spawn&quot;)
TArray&amp;lt;TObjectPtr&amp;lt;class ASpawnVolume&amp;gt;&amp;gt; SpawnVolumes;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;의미&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;레벨에 배치된 여러 개의 SpawnVolume을 WaveManager가 가지고 있는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;SpawnVolumes[0] &amp;rarr; SpawnVolume 1
SpawnVolumes[1] &amp;rarr; SpawnVolume 2
SpawnVolumes[2] &amp;rarr; SpawnVolume 3
SpawnVolumes[3] &amp;rarr; SpawnVolume 4&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Wave 1에서 2개만 사용한다면 앞의 2개를 사용하고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Wave 3에서는 4개를 사용하도록 구성했다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;8. WaveDataTable&lt;/span&gt;&lt;/h1&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;// 웨이브 정보를 담고 있는 데이터테이블
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Wave|Data&quot;)
TObjectPtr&amp;lt;UDataTable&amp;gt; WaveDataTable;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;의미&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;DT_WaveData&lt;/span&gt;&lt;span&gt;를 WaveManager가 참조하기 위한 변수이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;실제 웨이브의 몬스터 수나 제한시간을 코드에 직접 적지 않고 DataTable에서 관리할 수 있게 했다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;9. 현재 웨이브 데이터 가져오기&lt;/span&gt;&lt;/h1&gt;
&lt;pre class=&quot;php&quot;&gt;&lt;code&gt;const FWaveData* AWaveManager::GetCurrentWaveData() const
{
    // 현재 웨이브 번호를 DataTable의 Row 이름으로 만든다.
    // 예: CurrentWave = 1 &amp;rarr; &quot;Wave1&quot;
    const FName RowName = FName(*FString::Printf(TEXT(&quot;Wave%d&quot;), CurrentWave));

    // DataTable에서 해당 Row를 찾아 반환한다.
    return WaveDataTable-&amp;gt;FindRow&amp;lt;FWaveData&amp;gt;(RowName, TEXT(&quot;GetCurrentWaveData&quot;));
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;동작 과정&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;현재 웨이브가 &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;이라면:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;CurrentWave = 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 값을 이용해&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;Wave1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이라는 Row 이름을 만든다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그리고 DataTable에서 해당 Row를 찾는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;CurrentWave = 1
        &amp;darr;
&quot;Wave1&quot;
        &amp;darr;
DT_WaveData에서 Wave1 검색
        &amp;darr;
Wave1 데이터 반환&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Wave 2라면 &lt;/span&gt;&lt;span&gt;&quot;Wave2&quot;&lt;/span&gt;&lt;span&gt;, Wave 3이라면 &lt;/span&gt;&lt;span&gt;&quot;Wave3&quot;&lt;/span&gt;&lt;span&gt;가 된다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;10. 현재 웨이브 몬스터 수 계산&lt;/span&gt;&lt;/h1&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;void AWaveManager::UpdateCurrentMonsterCount()
{
    // 현재 웨이브의 데이터를 가져온다.
    const FWaveData* WaveData = GetCurrentWaveData();

    // 웨이브 데이터가 없으면 종료
    if (!WaveData)
    {
        return;
    }

    // 현재 웨이브의 몬스터 수를 0부터 다시 계산
    CurrentMonsterCount = 0;

    // 몬스터 종류별 SpawnCount를 모두 더한다.
    for (const FWaveMonsterData&amp;amp; MonsterData : WaveData-&amp;gt;Monsters)
    {
        CurrentMonsterCount += MonsterData.SpawnCount;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;의미&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;DataTable에 몬스터 종류가 여러 개 들어갈 수 있기 때문에 &lt;/span&gt;&lt;span&gt;Monsters&lt;/span&gt;&lt;span&gt; 배열을 순회한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Melee      20
Suicide    10
Ranged     15&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;라면:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;basic&quot;&gt;&lt;code&gt;20 + 10 + 15 = 45&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;가 되어 &lt;/span&gt;&lt;span&gt;CurrentMonsterCount&lt;/span&gt;&lt;span&gt;는 45가 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;현재 프로젝트에서는 한 웨이브에 &lt;/span&gt;&lt;span&gt;BP_Suicide&lt;/span&gt;&lt;span&gt;만 넣었기 때문에:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Wave 1 &amp;rarr; 30
Wave 2 &amp;rarr; 45
Wave 3 &amp;rarr; 60&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 된다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;11. 몬스터 스폰&lt;/span&gt;&lt;/h1&gt;
&lt;pre class=&quot;php&quot;&gt;&lt;code&gt;void AWaveManager::SpawnCurrentWave()
{
    // 현재 웨이브 데이터를 가져온다.
    const FWaveData* WaveData = GetCurrentWaveData();

    // 웨이브 데이터가 없으면 종료
    if (!WaveData)
    {
        return;
    }

    // 현재 웨이브의 몬스터 종류를 하나씩 확인한다.
    for (const FWaveMonsterData&amp;amp; MonsterData : WaveData-&amp;gt;Monsters)
    {
        // 몬스터 클래스가 지정되지 않았으면 건너뛴다.
        if (!MonsterData.MonsterClass)
        {
            continue;
        }

        // 설정된 몬스터 수만큼 반복해서 스폰한다.
        for (int32 i = 0; i &amp;lt; MonsterData.SpawnCount; ++i)
        {
            // 사용할 SpawnVolume이 없으면 종료
            if (SpawnVolumes.Num() == 0)
            {
                return;
            }

            // 현재 웨이브에서 사용할 SpawnVolume에 몬스터를 골고루 분배한다.
            ASpawnVolume* SpawnVolume =
                SpawnVolumes[i % WaveData-&amp;gt;SpawnVolumeCount];

            // SpawnVolume이 없으면 해당 스폰을 건너뛴다.
            if (!SpawnVolume)
            {
                continue;
            }

            // SpawnVolume에서 랜덤한 스폰 위치를 가져온다.
            const FVector SpawnLocation =
                SpawnVolume-&amp;gt;GetRandomSpawnLocation();

            // 몬스터를 스폰한다.
            GetWorld()-&amp;gt;SpawnActor&amp;lt;AActor&amp;gt;(
                MonsterData.MonsterClass,
                SpawnLocation,
                FRotator::ZeroRotator
            );
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;핵심 구조&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;먼저 현재 웨이브 데이터를 가져온다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;const FWaveData* WaveData = GetCurrentWaveData();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그 다음 웨이브에 등록된 몬스터 종류를 확인한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;for (const FWaveMonsterData&amp;amp; MonsterData : WaveData-&amp;gt;Monsters)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그리고 &lt;/span&gt;&lt;span&gt;SpawnCount&lt;/span&gt;&lt;span&gt;만큼 반복하여 몬스터를 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;matlab&quot;&gt;&lt;code&gt;for (int32 i = 0; i &amp;lt; MonsterData.SpawnCount; ++i)&lt;/code&gt;&lt;/pre&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;SpawnVolume 분배&lt;/span&gt;&lt;/h2&gt;
&lt;pre class=&quot;matlab&quot;&gt;&lt;code&gt;SpawnVolumes[i % WaveData-&amp;gt;SpawnVolumeCount]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서는 &lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; 연산을 사용했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어 SpawnVolume이 2개이고 몬스터가 6마리라면:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;i = 0 &amp;rarr; Volume 0
i = 1 &amp;rarr; Volume 1
i = 2 &amp;rarr; Volume 0
i = 3 &amp;rarr; Volume 1
i = 4 &amp;rarr; Volume 0
i = 5 &amp;rarr; Volume 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 몬스터가 SpawnVolume에 &lt;/span&gt;&lt;b&gt;&lt;span&gt;순서대로 골고루 분배&lt;/span&gt;&lt;/b&gt;&lt;span&gt;된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;현재 설정에서는:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Wave 1
30마리 / 2개
&amp;rarr; 15마리씩

Wave 2
45마리 / 3개
&amp;rarr; 15마리씩

Wave 3
60마리 / 4개
&amp;rarr; 15마리씩&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 된다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;12. 웨이브 제한시간&lt;/span&gt;&lt;/h1&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;void AWaveManager::StartWaveTimer()
{
    // 현재 웨이브의 데이터 가져오기
    const FWaveData* WaveData = GetCurrentWaveData();

    // 웨이브 데이터가 없으면 종료
    if (!WaveData)
    {
        return;
    }

    // 현재 웨이브의 제한시간으로 타이머 시작
    GetWorldTimerManager().SetTimer(
        WaveTimerHandle,
        this,
        &amp;amp;AWaveManager::OnWaveTimeExpired,
        WaveData-&amp;gt;WaveTimeLimit,
        false
    );
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;의미&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;DataTable에 설정된 &lt;/span&gt;&lt;span&gt;WaveTimeLimit&lt;/span&gt;&lt;span&gt;을 이용해 타이머를 시작한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Wave 1:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;WaveTimeLimit = 60&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이면 60초 후&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;OnWaveTimeExpired()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;가 호출된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Wave 2와 Wave 3은 각각 90초로 설정했다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;13. 튜토리얼 30초 대기&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;처음에는 게임이 시작되자마자 몬스터가 스폰되었지만, 기획상 &lt;/span&gt;&lt;b&gt;&lt;span&gt;튜토리얼 30초 동안은 몬스터를 스폰하지 않도록 수정&lt;/span&gt;&lt;/b&gt;&lt;span&gt;했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;void AWaveManager::BeginPlay()
{
    Super::BeginPlay();

    UE_LOG(LogTemp, Warning, TEXT(&quot;===== WaveManager BeginPlay =====&quot;));

    UpdateCurrentMonsterCount();

    // 튜토리얼 30초 후 Wave 1 시작
    GetWorldTimerManager().SetTimer(
        TutorialTimerHandle,
        this,
        &amp;amp;AWaveManager::StartFirstWave,
        30.0f,
        false
    );
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;의미&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;게임 시작 시 &lt;/span&gt;&lt;span&gt;BeginPlay()&lt;/span&gt;&lt;span&gt;는 실행되지만 바로 몬스터를 스폰하지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;대신:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;게임 시작
 &amp;darr;
30초 대기
 &amp;darr;
StartFirstWave()
 &amp;darr;
Wave 1 스폰&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;의 흐름으로 변경했다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;14. Wave 1 시작&lt;/span&gt;&lt;/h1&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;void AWaveManager::StartFirstWave()
{
    UE_LOG(
        LogTemp,
        Warning,
        TEXT(&quot;===== WAVE 1 START =====&quot;)
    );

    // Wave 1 몬스터 스폰
    SpawnCurrentWave();

    // Wave 1 제한시간 시작
    StartWaveTimer();
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;의미&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;튜토리얼 30초가 끝나면 호출된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 두 가지를 실행한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;1. Wave 1 몬스터 스폰
2. Wave 1 제한시간 시작&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;실제 PIE 테스트에서&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;===== WaveManager BeginPlay =====
===== WAVE 1 START =====&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;로그가 확인되었고, 실제 몬스터가 스폰되는 것도 확인했다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;15. 웨이브 시간이 끝났을 때&lt;/span&gt;&lt;/h1&gt;
&lt;pre class=&quot;autohotkey&quot;&gt;&lt;code&gt;void AWaveManager::OnWaveTimeExpired()
{
    UE_LOG(
        LogTemp,
        Warning,
        TEXT(&quot;===== WAVE TIME EXPIRED ===== Wave: %d&quot;),
        CurrentWave
    );

    // 45초 후 다음 웨이브 시작
    GetWorldTimerManager().SetTimer(
        NextWaveTimerHandle,
        this,
        &amp;amp;AWaveManager::StartNextWave,
        45.0f,
        false
    );
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;의미&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;현재 웨이브의 제한시간이 끝나면 바로 다음 웨이브를 시작하지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;45초의 대기시간을 가진다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Wave 1
 &amp;darr;
60초
 &amp;darr;
WaveTimeExpired
 &amp;darr;
45초 대기
 &amp;darr;
Wave 2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 45초 대기는 &lt;/span&gt;&lt;span&gt;NextWaveTimerHandle&lt;/span&gt;&lt;span&gt;을 이용해 관리한다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;16. 다음 웨이브 시작&lt;/span&gt;&lt;/h1&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;void AWaveManager::StartNextWave()
{
    // 다음 웨이브 번호로 변경
    CurrentWave++;

    // 최대 웨이브를 넘으면 종료
    if (CurrentWave &amp;gt; MaxWave)
    {
        return;
    }

    UE_LOG(
        LogTemp,
        Warning,
        TEXT(&quot;===== WAVE %d START =====&quot;),
        CurrentWave
    );

    // 다음 웨이브 몬스터 스폰
    SpawnCurrentWave();

    // 다음 웨이브 제한시간 시작
    StartWaveTimer();
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;의미&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음 웨이브를 시작하기 전에:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;brainfuck&quot;&gt;&lt;code&gt;CurrentWave++;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;로 웨이브 번호를 증가시킨다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Wave 1 &amp;rarr; CurrentWave = 1

다음 웨이브
&amp;rarr; CurrentWave = 2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그 후 현재 웨이브 번호를 이용해 DataTable에서 &lt;/span&gt;&lt;span&gt;Wave2&lt;/span&gt;&lt;span&gt; 데이터를 가져오고 몬스터를 스폰한다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;최대 웨이브 제한&lt;/span&gt;&lt;/h2&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;if (CurrentWave &amp;gt; MaxWave)
{
    return;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;현재 &lt;/span&gt;&lt;span&gt;MaxWave = 3&lt;/span&gt;&lt;span&gt;이기 때문에:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Wave 1 &amp;rarr; 진행
Wave 2 &amp;rarr; 진행
Wave 3 &amp;rarr; 진행
Wave 4 &amp;rarr; 시작하지 않음&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 조건을 통해 3웨이브 이후 더 이상 새로운 웨이브가 생성되지 않도록 했다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;17. 타이머 핸들&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;WaveManager에서는 세 개의 타이머를 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;1c&quot;&gt;&lt;code&gt;// 현재 웨이브 제한시간을 관리하는 타이머
FTimerHandle WaveTimerHandle;

// 튜토리얼 종료까지 대기하는 타이머
FTimerHandle TutorialTimerHandle;

// 다음 웨이브 시작까지 대기하는 타이머
FTimerHandle NextWaveTimerHandle;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;각각의 역할은 다르다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;WaveTimerHandle
&amp;rarr; 현재 웨이브 제한시간

TutorialTimerHandle
&amp;rarr; 게임 시작 후 30초 대기

NextWaveTimerHandle
&amp;rarr; 웨이브 종료 후 45초 대기&lt;/code&gt;&lt;/pre&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;18. 현재까지 완성된 전체 흐름&lt;/span&gt;&lt;/h1&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;게임 시작
   &amp;darr;
WaveManager BeginPlay
   &amp;darr;
30초 튜토리얼
   &amp;darr;
StartFirstWave()
   &amp;darr;
Wave 1
30마리 / SpawnVolume 2개 / 60초
   &amp;darr;
시간 종료
   &amp;darr;
45초 대기
   &amp;darr;
Wave 2
45마리 / SpawnVolume 3개 / 90초
   &amp;darr;
시간 종료
   &amp;darr;
45초 대기
   &amp;darr;
Wave 3
60마리 / SpawnVolume 4개 / 90초
   &amp;darr;
Wave 3 종료
   &amp;darr;
더 이상 Wave 4 생성 X&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;실제 PIE에서도 다음 로그를 확인했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;===== WaveManager BeginPlay =====
===== WAVE 1 START =====
===== WAVE TIME EXPIRED ===== Wave: 1
===== WAVE 2 START =====&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 &lt;/span&gt;&lt;b&gt;&lt;span&gt;튜토리얼 &amp;rarr; Wave 1 &amp;rarr; 제한시간 &amp;rarr; 45초 대기 &amp;rarr; Wave 2&lt;/span&gt;&lt;/b&gt;&lt;span&gt;까지 실제 동작을 확인했다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;19. 기획 변경 &amp;mdash; 놓친 몬스터 처리&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;처음에는 웨이브 제한시간 안에 처치하지 못한 몬스터를 다음 웨이브에 추가하는 방식을 생각했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;Wave 1
30마리 스폰
25마리 처치
5마리 생존

&amp;darr;

Wave 2
45마리 + 생존 5마리
= 50마리&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만 기획이 변경되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;현재는 &lt;/span&gt;&lt;b&gt;&lt;span&gt;생존 몬스터를 다음 웨이브에 이월하지 않는다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;대신 놓친 몬스터 수를 계산하여 &lt;/span&gt;&lt;b&gt;&lt;span&gt;보호 대상의 스트레스 지수에 반영&lt;/span&gt;&lt;/b&gt;&lt;span&gt;한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;현재 예정된 수치는:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;몬스터 1마리 놓침
&amp;rarr; 스트레스 +10&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;30마리 중 25마리 처치
&amp;rarr; 5마리 놓침
&amp;rarr; 스트레스 +50&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 다음 웨이브는 항상 DataTable에 설정된 수량대로 시작한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Wave 1 &amp;rarr; 30
Wave 2 &amp;rarr; 45
Wave 3 &amp;rarr; 60&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 기능은 몬스터의 사망 처리와 연결해야 하기 때문에 &lt;/span&gt;&lt;b&gt;&lt;span&gt;현재는 구현을 보류&lt;/span&gt;&lt;/b&gt;&lt;span&gt;했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;특히 다른 팀원이 &lt;/span&gt;&lt;span&gt;BaseMonster&lt;/span&gt;&lt;span&gt;를 수정하고 있는 상황이라, 머지 충돌을 피하기 위해 해당 작업은 이후 진행하기로 했다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;20. 트러블슈팅 &amp;mdash; WeaponBase 관련 컴파일 오류&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;오늘 WaveManager 작업 과정에서 &lt;/span&gt;&lt;span&gt;WeaponBase.cpp&lt;/span&gt;&lt;span&gt;와 관련된 컴파일 오류가 발생했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;처음에는 최근 수정한 WaveManager 코드의 문제인지 확인했지만, 실제 오류가 &lt;/span&gt;&lt;span&gt;WeaponBase&lt;/span&gt;&lt;span&gt; 쪽에서 발생하는 것을 확인했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;오류 원인을 분리해서 확인하기 위해 Unity Build를 끄는 방법도 사용해 보았다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;bUseUnityBuild = false;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게 설정했을 때 해당 오류가 사라지는 것을 확인했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이를 통해 &lt;/span&gt;&lt;b&gt;&lt;span&gt;최근 작성한 코드만 무조건 원인이라고 생각하기보다 실제 빌드 로그에서 오류가 발생한 파일과 위치를 먼저 확인해야 한다&lt;/span&gt;&lt;/b&gt;&lt;span&gt;는 것을 다시 확인했다.&lt;/span&gt;&lt;/p&gt;</description>
      <author>view29579</author>
      <guid isPermaLink="true">https://view29579.tistory.com/50</guid>
      <comments>https://view29579.tistory.com/50#entry50comment</comments>
      <pubDate>Mon, 14 Sep 2026 19:52:54 +0900</pubDate>
    </item>
    <item>
      <title>TIL-2nd. 팀프로젝트 DreamProtector (2/21) 업무 재분배 및 몬스터 클래스 구현</title>
      <link>https://view29579.tistory.com/49</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;오늘 한 일&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한분이 이탈함에 따라 업무를 재조정했고, 그에 따라 몬스터 부분을 팀원분과 함께 진행하게 되었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1721&quot; data-origin-height=&quot;972&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s35xT/dJMb998NIX7/Yb6O78BQBSOSW7oQMKWpG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s35xT/dJMb998NIX7/Yb6O78BQBSOSW7oQMKWpG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s35xT/dJMb998NIX7/Yb6O78BQBSOSW7oQMKWpG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs35xT%2FdJMb998NIX7%2FYb6O78BQBSOSW7oQMKWpG1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1721&quot; height=&quot;972&quot; data-origin-width=&quot;1721&quot; data-origin-height=&quot;972&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1825&quot; data-origin-height=&quot;1209&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ttKUx/dJMcag7TWhw/9xNb6EPuJ8qRBMfQEhgE1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ttKUx/dJMcag7TWhw/9xNb6EPuJ8qRBMfQEhgE1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ttKUx/dJMcag7TWhw/9xNb6EPuJ8qRBMfQEhgE1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FttKUx%2FdJMcag7TWhw%2F9xNb6EPuJ8qRBMfQEhgE1K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1825&quot; height=&quot;1209&quot; data-origin-width=&quot;1825&quot; data-origin-height=&quot;1209&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 작업 진행 전 다이어그램으로 구조와 필요 기능을 정리해 보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;오늘은 몬스터의 공통 기능을 담당하는 &lt;/span&gt;&lt;span&gt;BaseMonster&lt;/span&gt;&lt;span&gt;를 만들고, 이를 상속받는 &lt;/span&gt;&lt;span&gt;Suicide&lt;/span&gt;&lt;span&gt; 몬스터의 기본 구조를 구현했다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;1. BaseMonster 클래스 구현&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;플레이어와 몬스터의 역할을 분리하면서, 몬스터마다 공통적으로 필요한 기능을 &lt;/span&gt;&lt;span&gt;BaseMonster&lt;/span&gt;&lt;span&gt;에서 관리하도록 구성했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;ACharacter
    &amp;darr;
ABaseMonster
    &amp;darr;
각종 몬스터&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;BaseMonster&lt;/span&gt;&lt;span&gt;에는 모든 몬스터가 공통적으로 사용할 수 있는 기능을 넣었다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;주요 스탯&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;MaxHealth&lt;/span&gt;&lt;span&gt; : 최대 체력&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;CurrentHealth&lt;/span&gt;&lt;span&gt; : 현재 체력&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;AttackDamage&lt;/span&gt;&lt;span&gt; : 공격력&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;AttackInterval&lt;/span&gt;&lt;span&gt; : 공격 간격&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;MoveSpeed&lt;/span&gt;&lt;span&gt; : 이동 속도&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Target&lt;/span&gt;&lt;span&gt; : 공격 및 추적 대상&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;생성자에서 기본값을 설정하고, &lt;/span&gt;&lt;span&gt;BeginPlay()&lt;/span&gt;&lt;span&gt;에서 현재 체력을 최대 체력으로 초기화했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;CurrentHealth = MaxHealth;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또한 &lt;/span&gt;&lt;span&gt;CharacterMovementComponent&lt;/span&gt;&lt;span&gt;의 &lt;/span&gt;&lt;span&gt;MaxWalkSpeed&lt;/span&gt;&lt;span&gt;에 &lt;/span&gt;&lt;span&gt;MoveSpeed&lt;/span&gt;&lt;span&gt;를 적용하여 몬스터의 이동 속도를 스탯과 연결했다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;2. 몬스터 공통 피격 및 사망 처리&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;몬스터가 데미지를 받았을 때의 공통 로직을 &lt;/span&gt;&lt;span&gt;TakeDamage()&lt;/span&gt;&lt;span&gt;에서 처리하도록 했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;CurrentHealth -= DamageAmount;

if (CurrentHealth &amp;lt;= 0.0f)
{
    Die();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이미 죽은 몬스터가 다시 데미지를 받는 것을 방지하기 위해 체력이 0 이하라면 바로 반환하도록 했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;if (CurrentHealth &amp;lt;= 0.0f) return;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;사망 시에는 이동을 정지시키고 충돌을 비활성화한 뒤 액터를 제거하도록 했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;GetCharacterMovement()-&amp;gt;DisableMovement();
SetActorEnableCollision(false);
Destroy();&lt;/code&gt;&lt;/pre&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;3. Attack을 공통 인터페이스로 분리&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;몬스터마다 공격 방식이 다르기 때문에 공격 자체를 &lt;/span&gt;&lt;span&gt;BaseMonster&lt;/span&gt;&lt;span&gt;에서 완전히 구현하지 않고 &lt;/span&gt;&lt;span&gt;Attack()&lt;/span&gt;&lt;span&gt;을 공통 인터페이스처럼 사용하도록 했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = &quot;Monster|Damage&quot;)
void Attack();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;BlueprintNativeEvent&lt;/span&gt;&lt;span&gt;를 사용하면 C++에서 기본 구현을 제공하면서 Blueprint에서도 해당 함수를 재정의할 수 있다는 점을 배웠다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;실제 C++ 구현은 &lt;/span&gt;&lt;span&gt;_Implementation()&lt;/span&gt;&lt;span&gt;으로 작성한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;void ABaseMonster::Attack_Implementation()
{
    // 기본 공격 로직
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;자식 몬스터에서는 자신의 공격 방식에 맞게 &lt;/span&gt;&lt;span&gt;Attack_Implementation()&lt;/span&gt;&lt;span&gt;을 재정의할 수 있도록 구성했다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;4. Suicide 몬스터 생성&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Suicide&lt;/span&gt;&lt;span&gt;는 &lt;/span&gt;&lt;span&gt;BaseMonster&lt;/span&gt;&lt;span&gt;를 부모 클래스로 가지는 자식 몬스터로 만들었다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;ABaseMonster
    &amp;darr;
ASuicide&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;자폭 몬스터는 일반 몬스터와 달리 플레이어에게 접근한 뒤 폭발하는 전용 공격 방식을 사용하기 때문에, 자폭에 필요한 기능은 &lt;/span&gt;&lt;span&gt;Suicide&lt;/span&gt;&lt;span&gt;에서 담당하도록 했다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;5. Suicide 전용 Collision 구현&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;자폭 범위를 감지하기 위해 &lt;/span&gt;&lt;span&gt;USphereComponent&lt;/span&gt;&lt;span&gt;를 추가했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = &quot;Suicide&quot;)
TObjectPtr&amp;lt;USphereComponent&amp;gt; ExplosionCollision;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;생성자에서 Sphere Collision을 생성하고 Root Component에 붙였다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;ExplosionCollision = CreateDefaultSubobject&amp;lt;USphereComponent&amp;gt;(
    TEXT(&quot;ExplosionCollision&quot;)
);

ExplosionCollision-&amp;gt;SetupAttachment(RootComponent);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;자폭 범위는 Sphere 형태로 설정하고, Pawn과 Overlap이 발생하도록 Collision 설정을 짜보았다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;xl&quot;&gt;&lt;code&gt;ExplosionCollision-&amp;gt;SetSphereRadius(150.0f);

ExplosionCollision-&amp;gt;SetCollisionEnabled(
    ECollisionEnabled::QueryOnly
);

ExplosionCollision-&amp;gt;SetCollisionResponseToAllChannels(
    ECR_Ignore
);

ExplosionCollision-&amp;gt;SetCollisionResponseToChannel(
    ECC_Pawn,
    ECR_Overlap
);

ExplosionCollision-&amp;gt;SetGenerateOverlapEvents(true);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이를 통해 몬스터의 기본 몸체 충돌과 별개로 &lt;/span&gt;&lt;b&gt;&lt;span&gt;자폭 전용 감지 범위&lt;/span&gt;&lt;/b&gt;&lt;span&gt;를 만들었다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;오늘 배운 점&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;1. 부모 클래스와 자식 클래스의 역할 분리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;모든 몬스터가 공통으로 사용하는 기능은 &lt;/span&gt;&lt;span&gt;BaseMonster&lt;/span&gt;&lt;span&gt;에서 관리하고, 몬스터마다 다른 공격 방식이나 특수 기능은 자식 클래스에서 구현하는 것이 좋다는 것을 다시금 인지했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;BaseMonster
 ├─ 체력
 ├─ 공격력
 ├─ 이동속도
 ├─ 피격
 ├─ 사망
 └─ Attack 인터페이스

Suicide
 ├─ 자폭 Collision
 └─ 자폭 공격 구현&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;2. Collision도 기능별로 분리할 수 있다&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ACharacter&lt;/span&gt;&lt;span&gt;에는 기본적으로 Capsule Collision이 존재하지만, 특정 기능을 위한 별도의 Collision Component를 추가할 수 있다는 것을 배웠다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번에는 몸체 충돌과 자폭 감지 범위를 분리했다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;3. C++과 Blueprint의 역할 분담&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번 구조에서는 C++에서 컴포넌트와 기본적인 구조를 만들고, 이후 Blueprint에서 &lt;/span&gt;&lt;span&gt;BeginOverlap&lt;/span&gt;&lt;span&gt; 이벤트를 이용해 실제 폭발 연출 및 게임플레이 로직을 연결하는 방식으로 진행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉,&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;C++
 &amp;darr;
ExplosionCollision 생성
 &amp;darr;
Blueprint
 &amp;darr;
BeginOverlap
 &amp;darr;
폭발 처리&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;와 같은 구조를 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;오늘의 한 줄 정리&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;몬스터의 공통 기능은 BaseMonster에 모으고, 각 몬스터만의 특수한 기능은 자식 클래스에서 확장하는 구조를 만들었다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;내일 할 것&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>view29579</author>
      <guid isPermaLink="true">https://view29579.tistory.com/49</guid>
      <comments>https://view29579.tistory.com/49#entry49comment</comments>
      <pubDate>Tue, 8 Sep 2026 20:08:24 +0900</pubDate>
    </item>
    <item>
      <title>TIL-2nd. 팀프로젝트 DreamProtector (1/21) 팀 회의 내용 및 이슈 해결</title>
      <link>https://view29579.tistory.com/48</link>
      <description>&lt;h2 data-end=&quot;263&quot; data-start=&quot;249&quot; data-section-id=&quot;tn12y7&quot; data-ke-size=&quot;size26&quot;&gt;1. 오늘 작업 내용&lt;/h2&gt;
&lt;p data-end=&quot;349&quot; data-start=&quot;265&quot; data-ke-size=&quot;size16&quot;&gt;이번 팀 프로젝트의 전체 게임 기획을 정리하고, 내가 담당하게 된 &lt;b&gt;Map / Spawn / WaveManager&lt;/b&gt; 파트의 구현 방향을 구체화했다.&lt;/p&gt;
&lt;p data-end=&quot;388&quot; data-start=&quot;351&quot; data-ke-size=&quot;size16&quot;&gt;게임의 전체적인 컨셉은 **「Dream Protector」**이다.&lt;/p&gt;
&lt;blockquote data-end=&quot;434&quot; data-start=&quot;390&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;434&quot; data-start=&quot;392&quot; data-ke-size=&quot;size16&quot;&gt;아이가 잠든 밤, 장난감이 깨어나 아이의 꿈을 지키고 악몽을 해결하는 게임.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;519&quot; data-start=&quot;436&quot; data-ke-size=&quot;size16&quot;&gt;현실에 나타난 악몽으로부터 아이를 보호하고, 이후 꿈속으로 직접 들어가 악몽의 근원을 제거하는 &lt;b&gt;싱글 플레이 TPS PVE 게임&lt;/b&gt;을 목표로 한다.&lt;/p&gt;
&lt;hr data-end=&quot;524&quot; data-start=&quot;521&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;540&quot; data-start=&quot;526&quot; data-section-id=&quot;13hf1u&quot;&gt;2. 게임의 핵심 컨셉&lt;/h1&gt;
&lt;p data-end=&quot;568&quot; data-start=&quot;542&quot; data-ke-size=&quot;size16&quot;&gt;게임은 크게 두 가지 플레이 경험으로 구성된다.&lt;/p&gt;
&lt;h3 data-end=&quot;589&quot; data-start=&quot;570&quot; data-section-id=&quot;ag5xxi&quot; data-ke-size=&quot;size23&quot;&gt;Stage 1 &amp;mdash; 아이의 방&lt;/h3&gt;
&lt;p data-end=&quot;618&quot; data-start=&quot;591&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;아이를 악몽으로부터 보호하는 디펜스 플레이&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;733&quot; data-start=&quot;620&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;635&quot; data-start=&quot;620&quot; data-section-id=&quot;17v72dp&quot;&gt;아이의 침대 주변을 방어&lt;/li&gt;
&lt;li data-end=&quot;652&quot; data-start=&quot;636&quot; data-section-id=&quot;9hajw0&quot;&gt;여러 방향에서 악몽이 등장&lt;/li&gt;
&lt;li data-end=&quot;681&quot; data-start=&quot;653&quot; data-section-id=&quot;1odpq7e&quot;&gt;웨이브가 진행될수록 SpawnVolume이 증가&lt;/li&gt;
&lt;li data-end=&quot;703&quot; data-start=&quot;682&quot; data-section-id=&quot;w32s20&quot;&gt;등장하는 몬스터의 종류와 수가 증가&lt;/li&gt;
&lt;li data-end=&quot;733&quot; data-start=&quot;704&quot; data-section-id=&quot;104u43g&quot;&gt;플레이어의 행동에 따라 아이의 Stress가 감소&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;795&quot; data-start=&quot;735&quot; data-ke-size=&quot;size16&quot;&gt;즉, 단순히 몬스터를 많이 잡는 것이 아니라 &lt;b&gt;아이를 보호하면서 전장을 관리하는 플레이&lt;/b&gt;를 목표로 한다.&lt;/p&gt;
&lt;h3 data-end=&quot;822&quot; data-start=&quot;797&quot; data-section-id=&quot;uifyj2&quot; data-ke-size=&quot;size23&quot;&gt;Stage 2 &amp;mdash; 꿈속 / 장난감의 성&lt;/h3&gt;
&lt;p data-end=&quot;850&quot; data-start=&quot;824&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;악몽의 근원을 직접 찾아 제거하는 섬멸전&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;972&quot; data-start=&quot;852&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;861&quot; data-start=&quot;852&quot; data-section-id=&quot;1q93wuk&quot;&gt;꿈속으로 진입&lt;/li&gt;
&lt;li data-end=&quot;879&quot; data-start=&quot;862&quot; data-section-id=&quot;b86gvs&quot;&gt;웨이브 단위로 몬스터와 전투&lt;/li&gt;
&lt;li data-end=&quot;907&quot; data-start=&quot;880&quot; data-section-id=&quot;1dns91x&quot;&gt;웨이브가 진행될수록 몬스터 종류와 스폰량 증가&lt;/li&gt;
&lt;li data-end=&quot;927&quot; data-start=&quot;908&quot; data-section-id=&quot;nuyot4&quot;&gt;마지막 웨이브에서는 보스전 진행&lt;/li&gt;
&lt;li data-end=&quot;943&quot; data-start=&quot;928&quot; data-section-id=&quot;mcyzz1&quot;&gt;플레이어가 사망하면 실패&lt;/li&gt;
&lt;li data-end=&quot;972&quot; data-start=&quot;944&quot; data-section-id=&quot;j1e9rx&quot;&gt;제한 시간 안에 모든 적을 처치하면 웨이브 성공&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;977&quot; data-start=&quot;974&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;991&quot; data-start=&quot;979&quot; data-section-id=&quot;1nx6uc6&quot;&gt;3. 게임의 차별성&lt;/h1&gt;
&lt;p data-end=&quot;1055&quot; data-start=&quot;993&quot; data-ke-size=&quot;size16&quot;&gt;이번 프로젝트에서 생각한 차별점은 &lt;b&gt;인간의 수면 주기인 REM 수면을 게임의 진행 구조에 활용하는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;1081&quot; data-start=&quot;1057&quot; data-ke-size=&quot;size16&quot;&gt;단순히 계속 전투가 이어지는 방식이 아니라,&lt;/p&gt;
&lt;p data-end=&quot;1127&quot; data-start=&quot;1083&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;REM 수면 &amp;rarr; 악몽 출현 &amp;rarr; 전투 &amp;rarr; 비 REM 상태 &amp;rarr; 탐색 / 준비&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1142&quot; data-start=&quot;1129&quot; data-ke-size=&quot;size16&quot;&gt;와 같은 흐름을 만든다.&lt;/p&gt;
&lt;p data-end=&quot;1186&quot; data-start=&quot;1144&quot; data-ke-size=&quot;size16&quot;&gt;REM 수면을 악몽이 등장하는 전투 시간으로 활용하고, 전투가 아닌 시간에는&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1219&quot; data-start=&quot;1188&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1194&quot; data-start=&quot;1188&quot; data-section-id=&quot;1ttn2x0&quot;&gt;맵 탐색&lt;/li&gt;
&lt;li data-end=&quot;1203&quot; data-start=&quot;1195&quot; data-section-id=&quot;j153bd&quot;&gt;아이템 루팅&lt;/li&gt;
&lt;li data-end=&quot;1208&quot; data-start=&quot;1204&quot; data-section-id=&quot;yikh45&quot;&gt;제작&lt;/li&gt;
&lt;li data-end=&quot;1219&quot; data-start=&quot;1209&quot; data-section-id=&quot;lwglt8&quot;&gt;다음 전투 준비&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1237&quot; data-start=&quot;1221&quot; data-ke-size=&quot;size16&quot;&gt;등을 할 수 있도록 설계한다.&lt;/p&gt;
&lt;p data-end=&quot;1301&quot; data-start=&quot;1239&quot; data-ke-size=&quot;size16&quot;&gt;이를 통해 전투만 반복하는 구조가 아니라 &lt;b&gt;전투와 준비가 반복되는 게임의 리듬&lt;/b&gt;을 만드는 것을 목표로 했다.&lt;/p&gt;
&lt;hr data-end=&quot;1306&quot; data-start=&quot;1303&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;1323&quot; data-start=&quot;1308&quot; data-section-id=&quot;q9fyr0&quot;&gt;4. Stage 1 규칙&lt;/h1&gt;
&lt;p data-end=&quot;1353&quot; data-start=&quot;1325&quot; data-ke-size=&quot;size16&quot;&gt;Stage 1은 아이의 방에서 진행되는 방어전이다.&lt;/p&gt;
&lt;p data-end=&quot;1392&quot; data-start=&quot;1355&quot; data-ke-size=&quot;size16&quot;&gt;아이의 침대 주변에는 일정한 거리를 기준으로 방어 구역을 설정한다.&lt;/p&gt;
&lt;p data-end=&quot;1432&quot; data-start=&quot;1394&quot; data-ke-size=&quot;size16&quot;&gt;특히 플레이어가 침대 바로 옆에서 계속 공격하는 것을 방지하기 위해,&lt;/p&gt;
&lt;blockquote data-end=&quot;1477&quot; data-start=&quot;1434&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1477&quot; data-start=&quot;1436&quot; data-ke-size=&quot;size16&quot;&gt;침대 주변 일정 거리 안에서 공격하면 아이의 Stress가 증가하도록 설계&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;1482&quot; data-start=&quot;1479&quot; data-ke-size=&quot;size16&quot;&gt;했다.&lt;/p&gt;
&lt;p data-end=&quot;1549&quot; data-start=&quot;1484&quot; data-ke-size=&quot;size16&quot;&gt;따라서 플레이어는 단순히 아이 근처에 붙어서 싸우는 것이 아니라 적의 접근을 막으면서 적절한 위치에서 전투해야 한다.&lt;/p&gt;
&lt;h3 data-end=&quot;1563&quot; data-start=&quot;1551&quot; data-section-id=&quot;2l8lr5&quot; data-ke-size=&quot;size23&quot;&gt;Spawn 구조&lt;/h3&gt;
&lt;p data-end=&quot;1632&quot; data-start=&quot;1565&quot; data-ke-size=&quot;size16&quot;&gt;맵의 여러 방향에 SpawnVolume을 배치하고 웨이브가 진행될수록 활성화되는 SpawnVolume의 수를 증가시킨다.&lt;/p&gt;
&lt;p data-end=&quot;1637&quot; data-start=&quot;1634&quot; data-ke-size=&quot;size16&quot;&gt;예시:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Wave 1
&amp;darr;
SpawnVolume 2개 활성화

Wave 2
&amp;darr;
SpawnVolume 3개 활성화

Wave 3
&amp;darr;
SpawnVolume 4개 활성화&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1780&quot; data-start=&quot;1738&quot; data-ke-size=&quot;size16&quot;&gt;또한 웨이브가 진행될수록 등장하는 몬스터의 종류도 증가시켜 난이도를 높인다.&lt;/p&gt;
&lt;h3 data-end=&quot;1791&quot; data-start=&quot;1782&quot; data-section-id=&quot;10iazfy&quot; data-ke-size=&quot;size23&quot;&gt;실패 조건&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1822&quot; data-start=&quot;1793&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1822&quot; data-start=&quot;1793&quot; data-section-id=&quot;1a7kr9c&quot;&gt;아이의 Stress가 한계치에 도달하면 게임 실패&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1833&quot; data-start=&quot;1824&quot; data-section-id=&quot;u8yc92&quot; data-ke-size=&quot;size23&quot;&gt;성공 조건&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1852&quot; data-start=&quot;1835&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1852&quot; data-start=&quot;1835&quot; data-section-id=&quot;c3gxwc&quot;&gt;모든 웨이브에서 아이를 보호&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1857&quot; data-start=&quot;1854&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;1874&quot; data-start=&quot;1859&quot; data-section-id=&quot;19n4232&quot;&gt;5. Stage 2 규칙&lt;/h1&gt;
&lt;p data-end=&quot;1912&quot; data-start=&quot;1876&quot; data-ke-size=&quot;size16&quot;&gt;Stage 2에서는 아이의 꿈속으로 들어가 악몽과 직접 전투한다.&lt;/p&gt;
&lt;p data-end=&quot;1954&quot; data-start=&quot;1914&quot; data-ke-size=&quot;size16&quot;&gt;Stage 1과 달리 &lt;b&gt;플레이어의 생존 자체가 중요한 요소&lt;/b&gt;가 된다.&lt;/p&gt;
&lt;h3 data-end=&quot;1966&quot; data-start=&quot;1956&quot; data-section-id=&quot;hk44q&quot; data-ke-size=&quot;size23&quot;&gt;웨이브 구조&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;Wave 1
&amp;darr;
기본 악몽 몬스터

Wave 2
&amp;darr;
강화된 몬스터 + 장난감 로봇 등

Wave 3
&amp;darr;
장난감 기사 + 대형 몬스터
&amp;darr;
Boss Battle&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2088&quot; data-start=&quot;2069&quot; data-ke-size=&quot;size16&quot;&gt;웨이브마다 제한된 시간이 존재하며,&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2090&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;제한 시간 안에 모든 몬스터를 처치하면 웨이브 성공&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2132&quot; data-start=&quot;2124&quot; data-ke-size=&quot;size16&quot;&gt;으로 설계했다.&lt;/p&gt;
&lt;hr data-end=&quot;2137&quot; data-start=&quot;2134&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;2165&quot; data-start=&quot;2139&quot; data-section-id=&quot;1rjbt6z&quot; data-ke-size=&quot;size26&quot;&gt;웨이브 성공 / 실패에 따른 보상과 패널티&lt;/h2&gt;
&lt;p data-end=&quot;2227&quot; data-start=&quot;2167&quot; data-ke-size=&quot;size16&quot;&gt;웨이브를 성공하면 중앙 맵 양쪽의 지역 문이 해금되고, 해당 지역에서 버프 아이템을 획득할 수 있도록 한다.&lt;/p&gt;
&lt;p data-end=&quot;2293&quot; data-start=&quot;2229&quot; data-ke-size=&quot;size16&quot;&gt;반대로 웨이브 처치에 실패하면 다음 웨이브에 추가로 처치해야 할 몬스터가 증가하는 등의 &lt;b&gt;디메리트&lt;/b&gt;를 부여한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;웨이브 성공
    &amp;darr;
지역 해금
    &amp;darr;
버프 획득
    &amp;darr;
다음 REM 전투

웨이브 실패
    &amp;darr;
다음 웨이브 디메리트
    &amp;darr;
난이도 증가&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2459&quot; data-start=&quot;2394&quot; data-ke-size=&quot;size16&quot;&gt;또한 다음 REM 주기가 시작되기 전에는 다음 전투 구역으로 이동할 수 없도록 하여 플레이어의 진행 속도를 통제한다.&lt;/p&gt;
&lt;hr data-end=&quot;2464&quot; data-start=&quot;2461&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;2479&quot; data-start=&quot;2466&quot; data-section-id=&quot;50oem7&quot;&gt;6. 내가 맡은 파트&lt;/h1&gt;
&lt;p data-end=&quot;2508&quot; data-start=&quot;2481&quot; data-ke-size=&quot;size16&quot;&gt;팀의 전체적인 파트 분배는 다음과 같이 진행했다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2651&quot; data-start=&quot;2510&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2523&quot; data-start=&quot;2510&quot; data-section-id=&quot;1pqgpo5&quot;&gt;GameManager&lt;/li&gt;
&lt;li data-end=&quot;2535&quot; data-start=&quot;2524&quot; data-section-id=&quot;k6e06f&quot;&gt;UIManager&lt;/li&gt;
&lt;li data-end=&quot;2563&quot; data-start=&quot;2536&quot; data-section-id=&quot;1vxz3cf&quot;&gt;Character / WeaponManager&lt;/li&gt;
&lt;li data-end=&quot;2589&quot; data-start=&quot;2564&quot; data-section-id=&quot;1mm4ufy&quot;&gt;Monster / CombatManager&lt;/li&gt;
&lt;li data-end=&quot;2629&quot; data-start=&quot;2590&quot; data-section-id=&quot;180yoj4&quot;&gt;&lt;b&gt;Map / Spawn / WaveManager &amp;larr; 내가 담당&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2637&quot; data-start=&quot;2630&quot; data-section-id=&quot;178hctn&quot;&gt;Story&lt;/li&gt;
&lt;li data-end=&quot;2651&quot; data-start=&quot;2638&quot; data-section-id=&quot;q894lq&quot;&gt;ItemManager&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2686&quot; data-start=&quot;2653&quot; data-ke-size=&quot;size16&quot;&gt;내가 담당한 부분에서는 크게 다음 세 가지를 구현하게 된다.&lt;/p&gt;
&lt;h3 data-end=&quot;2695&quot; data-start=&quot;2688&quot; data-section-id=&quot;1xxfg1m&quot; data-ke-size=&quot;size23&quot;&gt;Map&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2750&quot; data-start=&quot;2697&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2706&quot; data-start=&quot;2697&quot; data-section-id=&quot;r478ug&quot;&gt;전투 맵 구성&lt;/li&gt;
&lt;li data-end=&quot;2720&quot; data-start=&quot;2707&quot; data-section-id=&quot;adoa1e&quot;&gt;Spawn 위치 구성&lt;/li&gt;
&lt;li data-end=&quot;2736&quot; data-start=&quot;2721&quot; data-section-id=&quot;4v8479&quot;&gt;플레이어 이동 동선 구성&lt;/li&gt;
&lt;li data-end=&quot;2750&quot; data-start=&quot;2737&quot; data-section-id=&quot;188gqp&quot;&gt;주요 전투 구역 배치&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;2761&quot; data-start=&quot;2752&quot; data-section-id=&quot;77fo59&quot; data-ke-size=&quot;size23&quot;&gt;Spawn&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2832&quot; data-start=&quot;2763&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2779&quot; data-start=&quot;2763&quot; data-section-id=&quot;11z7ur7&quot;&gt;SpawnVolume 배치&lt;/li&gt;
&lt;li data-end=&quot;2793&quot; data-start=&quot;2780&quot; data-section-id=&quot;adnvc3&quot;&gt;Spawn 위치 관리&lt;/li&gt;
&lt;li data-end=&quot;2809&quot; data-start=&quot;2794&quot; data-section-id=&quot;e8vc24&quot;&gt;몬스터 생성 위치 랜덤화&lt;/li&gt;
&lt;li data-end=&quot;2832&quot; data-start=&quot;2810&quot; data-section-id=&quot;pgi61i&quot;&gt;웨이브별 SpawnVolume 활성화&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;2842&quot; data-start=&quot;2834&quot; data-section-id=&quot;ynlkg3&quot; data-ke-size=&quot;size23&quot;&gt;Wave&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2930&quot; data-start=&quot;2844&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2857&quot; data-start=&quot;2844&quot; data-section-id=&quot;1m4e9oz&quot;&gt;웨이브 시작 / 종료&lt;/li&gt;
&lt;li data-end=&quot;2871&quot; data-start=&quot;2858&quot; data-section-id=&quot;rkkux&quot;&gt;웨이브별 몬스터 구성&lt;/li&gt;
&lt;li data-end=&quot;2890&quot; data-start=&quot;2872&quot; data-section-id=&quot;dpn4ai&quot;&gt;웨이브별 Spawn 수량 관리&lt;/li&gt;
&lt;li data-end=&quot;2901&quot; data-start=&quot;2891&quot; data-section-id=&quot;10s71r0&quot;&gt;제한 시간 관리&lt;/li&gt;
&lt;li data-end=&quot;2918&quot; data-start=&quot;2902&quot; data-section-id=&quot;ncqnbf&quot;&gt;웨이브 성공 / 실패 처리&lt;/li&gt;
&lt;li data-end=&quot;2930&quot; data-start=&quot;2919&quot; data-section-id=&quot;czqpgd&quot;&gt;다음 웨이브 진행&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;2935&quot; data-start=&quot;2932&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;2954&quot; data-start=&quot;2937&quot; data-section-id=&quot;8288lc&quot;&gt;7. Spawn 시스템 설계&lt;/h1&gt;
&lt;p data-end=&quot;2996&quot; data-start=&quot;2956&quot; data-ke-size=&quot;size16&quot;&gt;Spawn 시스템은 SpawnVolume을 중심으로 구성할 예정이다.&lt;/p&gt;
&lt;p data-end=&quot;3014&quot; data-start=&quot;2998&quot; data-ke-size=&quot;size16&quot;&gt;기본적인 흐름은 다음과 같다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;Wave 시작
    &amp;darr;
SpawnVolume 위치 선택
    &amp;darr;
랜덤 Spawn 위치 생성
    &amp;darr;
지정된 수량만큼 Enemy 생성
    &amp;darr;
모든 Enemy 처치 확인
    &amp;darr;
Wave 종료
    &amp;darr;
다음 Wave 시작&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3189&quot; data-start=&quot;3158&quot; data-ke-size=&quot;size16&quot;&gt;이를 위해 사용할 클래스로는 다음과 같이 생각하고 있다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;ASpawnVolume
AWaveManager
AEnemy
AIController
AI Behavior Tree&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3339&quot; data-start=&quot;3267&quot; data-ke-size=&quot;size16&quot;&gt;SpawnVolume은 단순히 적을 생성하는 것뿐만 아니라 &lt;b&gt;어떤 위치에서 적을 생성할 것인지 관리하는 역할&lt;/b&gt;을 담당한다.&lt;/p&gt;
&lt;hr data-end=&quot;3344&quot; data-start=&quot;3341&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;3360&quot; data-start=&quot;3346&quot; data-section-id=&quot;1n9hzop&quot;&gt;8. 웨이브 구성 예시&lt;/h1&gt;
&lt;p data-end=&quot;3389&quot; data-start=&quot;3362&quot; data-ke-size=&quot;size16&quot;&gt;현재 기획한 기본적인 웨이브 구성은 다음과 같다.&lt;/p&gt;
&lt;div&gt;Wave적 타입출현 위치특징
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;3582&quot; data-start=&quot;3391&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;3582&quot; data-start=&quot;3438&quot;&gt;
&lt;tr data-end=&quot;3480&quot; data-start=&quot;3438&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3442&quot; data-start=&quot;3438&quot;&gt;1&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3454&quot; data-start=&quot;3442&quot;&gt;붉은 슬라임 / 비행형 가오리&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3467&quot; data-start=&quot;3454&quot;&gt;하단 입구 &amp;rarr; 중앙&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3480&quot; data-start=&quot;3467&quot;&gt;기본 패턴, 소수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;3532&quot; data-start=&quot;3481&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3485&quot; data-start=&quot;3481&quot;&gt;2&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3502&quot; data-start=&quot;3485&quot;&gt;람머스 슬라임 / 쁘띠 뮤탈&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3515&quot; data-start=&quot;3502&quot;&gt;양쪽 측면 &amp;rarr; 중앙&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3532&quot; data-start=&quot;3515&quot;&gt;중간 난이도, 더 빠른 이동속도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;3582&quot; data-start=&quot;3533&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3537&quot; data-start=&quot;3533&quot;&gt;3&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3555&quot; data-start=&quot;3537&quot;&gt;해골 사신 인형 / 대형 몬스터&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3565&quot; data-start=&quot;3555&quot;&gt;성탑 + 중앙&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;3582&quot; data-start=&quot;3565&quot;&gt;보스급 전투, 강한 패턴&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3625&quot; data-start=&quot;3584&quot; data-ke-size=&quot;size16&quot;&gt;실제 수량과 타이밍은 구현 후 플레이 테스트를 진행하면서 조정할 예정이다.&lt;/p&gt;
&lt;p data-end=&quot;3701&quot; data-start=&quot;3627&quot; data-ke-size=&quot;size16&quot;&gt;따라서 처음부터 수치를 완벽하게 결정하기보다는 &lt;b&gt;시스템을 먼저 구현하고 실제 플레이를 통해 밸런스를 조정하는 방향&lt;/b&gt;으로 생각했다.&lt;/p&gt;
&lt;hr data-end=&quot;3706&quot; data-start=&quot;3703&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;3730&quot; data-start=&quot;3708&quot; data-section-id=&quot;cvl90u&quot;&gt;9. 에셋 병합 과정에서 발생한 문제&lt;/h1&gt;
&lt;p data-end=&quot;3785&quot; data-start=&quot;3732&quot; data-ke-size=&quot;size16&quot;&gt;오늘은 시스템 기획뿐만 아니라 팀원들이 작업한 에셋을 머지하는 과정에서도 문제를 하나 발견했다.&lt;/p&gt;
&lt;p data-end=&quot;3835&quot; data-start=&quot;3787&quot; data-ke-size=&quot;size16&quot;&gt;탄환으로 사용할 &lt;b&gt;구미베어 젤리 에셋이 4개가 하나의 메쉬로 묶여 있는 상태&lt;/b&gt;였다.&lt;/p&gt;
&lt;p data-end=&quot;3885&quot; data-start=&quot;3837&quot; data-ke-size=&quot;size16&quot;&gt;게임에서는 각각의 젤리를 개별적으로 사용해야 했기 때문에 메쉬를 분리할 필요가 있었다.&lt;/p&gt;
&lt;hr data-end=&quot;3890&quot; data-start=&quot;3887&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;3906&quot; data-start=&quot;3892&quot; data-section-id=&quot;13jbltx&quot;&gt;10. 메쉬 분리 방법&lt;/h1&gt;
&lt;p data-end=&quot;3949&quot; data-start=&quot;3908&quot; data-ke-size=&quot;size16&quot;&gt;언리얼 에디터에서 해당 에셋을 열고 모델링 모드를 이용해 메쉬를 분리했다.&lt;/p&gt;
&lt;p data-end=&quot;3969&quot; data-start=&quot;3951&quot; data-ke-size=&quot;size16&quot;&gt;내가 사용한 과정은 다음과 같다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;에셋 선택
&amp;darr;
좌측 상단 Select Mode
&amp;darr;
Modeling Mode로 변경
&amp;darr;
XForm
&amp;darr;
Split&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4072&quot; data-start=&quot;4046&quot; data-ke-size=&quot;size16&quot;&gt;그리고 Split 옵션을 다음과 같이 변경했다.&lt;/p&gt;
&lt;h3 data-end=&quot;4089&quot; data-start=&quot;4074&quot; data-section-id=&quot;7efuip&quot; data-ke-size=&quot;size23&quot;&gt;Output Type&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;delphi&quot;&gt;&lt;code&gt;Dynamic&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;4128&quot; data-start=&quot;4112&quot; data-section-id=&quot;em8ciz&quot; data-ke-size=&quot;size23&quot;&gt;Split Method&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;By Poly Groups&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4214&quot; data-start=&quot;4158&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 설정한 뒤 Split을 실행하니 하나로 묶여 있던 4개의 젤리 메쉬를 각각 분리할 수 있었다.&lt;/p&gt;
&lt;hr data-end=&quot;4219&quot; data-start=&quot;4216&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;4239&quot; data-start=&quot;4221&quot; data-section-id=&quot;1gvzjeg&quot;&gt;11. 이번 작업에서 배운 점&lt;/h1&gt;
&lt;p data-end=&quot;4329&quot; data-start=&quot;4241&quot; data-ke-size=&quot;size16&quot;&gt;이번 작업을 통해 단순히 에셋을 가져와 사용하는 것뿐만 아니라 &lt;b&gt;가져온 에셋의 구조를 확인하고 게임에 맞게 수정하는 과정도 필요하다&lt;/b&gt;는 것을 알게 되었다.&lt;/p&gt;
&lt;p data-end=&quot;4342&quot; data-start=&quot;4331&quot; data-ke-size=&quot;size16&quot;&gt;특히 같은 에셋이라도&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;여러 개의 Mesh가 각각 존재하는 경우&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4381&quot; data-start=&quot;4380&quot; data-ke-size=&quot;size16&quot;&gt;와&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;하나의 Mesh 안에 여러 개의 오브젝트가 묶여 있는 경우&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4457&quot; data-start=&quot;4429&quot; data-ke-size=&quot;size16&quot;&gt;는 수정 방법이 다를 수 있다는 것을 알게 되었다.&lt;/p&gt;
&lt;p data-end=&quot;4545&quot; data-start=&quot;4459&quot; data-ke-size=&quot;size16&quot;&gt;이번에 사용한 Split &amp;rarr; By Poly Groups 방식은 &lt;b&gt;메쉬가 폴리곤 그룹 단위로 구성되어 있는 경우 분리할 수 있는 방법&lt;/b&gt;으로 이해했다.&lt;/p&gt;
&lt;p data-end=&quot;4639&quot; data-start=&quot;4547&quot; data-ke-size=&quot;size16&quot;&gt;따라서 앞으로 다른 에셋에서도 무조건 같은 방법이 적용된다고 생각하기보다는, &lt;b&gt;해당 에셋의 Mesh 구조와 Polygon Group 구성을 먼저 확인해야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;4644&quot; data-start=&quot;4641&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;4661&quot; data-start=&quot;4646&quot; data-section-id=&quot;e3jzv3&quot;&gt;12. 오늘의 핵심 정리&lt;/h1&gt;
&lt;p data-end=&quot;4717&quot; data-start=&quot;4663&quot; data-ke-size=&quot;size16&quot;&gt;이번 작업에서 가장 크게 정리된 부분은 &lt;b&gt;게임의 기획을 실제 시스템 구조로 연결하는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;4723&quot; data-start=&quot;4719&quot; data-ke-size=&quot;size16&quot;&gt;처음에는&lt;/p&gt;
&lt;blockquote data-end=&quot;4747&quot; data-start=&quot;4725&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;4747&quot; data-start=&quot;4727&quot; data-ke-size=&quot;size16&quot;&gt;&quot;웨이브 방식으로 몬스터가 나온다.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;4773&quot; data-start=&quot;4749&quot; data-ke-size=&quot;size16&quot;&gt;정도로 생각했다면, 이번에는 이를 구체적으로&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;Map
 &amp;darr;
SpawnVolume
 &amp;darr;
Spawn 위치
 &amp;darr;
WaveManager
 &amp;darr;
Enemy Spawn
 &amp;darr;
Enemy 처치 확인
 &amp;darr;
Wave 종료
 &amp;darr;
다음 Wave&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4910&quot; data-start=&quot;4886&quot; data-ke-size=&quot;size16&quot;&gt;라는 시스템 구조로 생각할 수 있게 되었다.&lt;/p&gt;
&lt;p data-end=&quot;4956&quot; data-start=&quot;4912&quot; data-ke-size=&quot;size16&quot;&gt;또한 REM 수면이라는 기획 요소도 단순한 스토리 설정으로 끝나는 것이 아니라,&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;dos&quot;&gt;&lt;code&gt;REM
&amp;darr;
전투
&amp;darr;
웨이브 종료
&amp;darr;
탐색 / 루팅 / 준비
&amp;darr;
다음 REM&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5054&quot; data-start=&quot;5013&quot; data-ke-size=&quot;size16&quot;&gt;이라는 &lt;b&gt;실제 게임 플레이 사이클&lt;/b&gt;로 연결할 수 있다는 점을 정리했다.&lt;/p&gt;
&lt;hr data-end=&quot;5059&quot; data-start=&quot;5056&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;5073&quot; data-start=&quot;5061&quot; data-section-id=&quot;l9355&quot; data-ke-size=&quot;size26&quot;&gt;  한 줄 회고&lt;/h2&gt;
&lt;blockquote data-end=&quot;5252&quot; data-start=&quot;5075&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;5252&quot; data-start=&quot;5077&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;오늘은 Dream Protector의 전체 게임 구조와 내가 담당할 Map / Spawn / WaveManager의 역할을 구체화하고, 실제 에셋 작업 과정에서는 하나로 묶여 있던 메쉬를 Modeling Mode &amp;rarr; XForm &amp;rarr; Split &amp;rarr; By Poly Groups를 통해 분리하는 방법을 익혔다.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <author>view29579</author>
      <guid isPermaLink="true">https://view29579.tistory.com/48</guid>
      <comments>https://view29579.tistory.com/48#entry48comment</comments>
      <pubDate>Mon, 7 Sep 2026 21:06:23 +0900</pubDate>
    </item>
    <item>
      <title>Unreal C++ TIL &amp;mdash; 3차 분반수업</title>
      <link>https://view29579.tistory.com/47</link>
      <description>&lt;h2 data-end=&quot;316&quot; data-start=&quot;291&quot; data-section-id=&quot;ggh341&quot; data-ke-size=&quot;size26&quot;&gt;1. UPrimitiveComponent&lt;/h2&gt;
&lt;p data-end=&quot;383&quot; data-start=&quot;318&quot; data-ke-size=&quot;size16&quot;&gt;언리얼에서 Actor를 구성하는 Component를 공부하면서 UPrimitiveComponent에 대해 배웠다.&lt;/p&gt;
&lt;p data-end=&quot;460&quot; data-start=&quot;385&quot; data-ke-size=&quot;size16&quot;&gt;UPrimitiveComponent는 &lt;b&gt;렌더링이나 충돌 등의 물리적 기능을 가질 수 있는 Component의 기반 클래스&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;479&quot; data-start=&quot;462&quot; data-ke-size=&quot;size16&quot;&gt;대표적으로 우리가 자주 사용하는&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;593&quot; data-start=&quot;481&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;505&quot; data-start=&quot;481&quot; data-section-id=&quot;hf71zt&quot;&gt;UStaticMeshComponent&lt;/li&gt;
&lt;li data-end=&quot;532&quot; data-start=&quot;506&quot; data-section-id=&quot;10qvld8&quot;&gt;USkeletalMeshComponent&lt;/li&gt;
&lt;li data-end=&quot;550&quot; data-start=&quot;533&quot; data-section-id=&quot;1e7vkx3&quot;&gt;UBoxComponent&lt;/li&gt;
&lt;li data-end=&quot;571&quot; data-start=&quot;551&quot; data-section-id=&quot;1vfsjxn&quot;&gt;USphereComponent&lt;/li&gt;
&lt;li data-end=&quot;593&quot; data-start=&quot;572&quot; data-section-id=&quot;1cmapfz&quot;&gt;UCapsuleComponent&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;626&quot; data-start=&quot;595&quot; data-ke-size=&quot;size16&quot;&gt;등이 UPrimitiveComponent를 상속한다.&lt;/p&gt;
&lt;p data-end=&quot;644&quot; data-start=&quot;628&quot; data-ke-size=&quot;size16&quot;&gt;대략적인 관계는 다음과 같다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;UObject
 └─ UActorComponent
     └─ USceneComponent
         └─ UPrimitiveComponent
             └─ UStaticMeshComponent&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;890&quot; data-start=&quot;780&quot; data-ke-size=&quot;size16&quot;&gt;즉, UPrimitiveComponent는 단순히 화면에 보이는 Mesh만을 의미하는 것이 아니라 &lt;b&gt;충돌, 렌더링 등 물리적인 표현이 가능한 Component의 기반&lt;/b&gt;이라고 이해하면 된다.&lt;/p&gt;
&lt;hr data-end=&quot;895&quot; data-start=&quot;892&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;928&quot; data-start=&quot;897&quot; data-section-id=&quot;qaphif&quot;&gt;2. Scene Component와 Transform&lt;/h1&gt;
&lt;p data-end=&quot;975&quot; data-start=&quot;930&quot; data-ke-size=&quot;size16&quot;&gt;이번 수업에서 중요하게 배운 내용 중 하나가 USceneComponent이다.&lt;/p&gt;
&lt;p data-end=&quot;1033&quot; data-start=&quot;977&quot; data-ke-size=&quot;size16&quot;&gt;USceneComponent는 &lt;b&gt;Transform 정보를 가지고 있는 Component&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;1049&quot; data-start=&quot;1035&quot; data-ke-size=&quot;size16&quot;&gt;Transform에는 크게&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1095&quot; data-start=&quot;1051&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1066&quot; data-start=&quot;1051&quot; data-section-id=&quot;pf6nqz&quot;&gt;Location &amp;rarr; 위치&lt;/li&gt;
&lt;li data-end=&quot;1082&quot; data-start=&quot;1067&quot; data-section-id=&quot;fgvxba&quot;&gt;Rotation &amp;rarr; 회전&lt;/li&gt;
&lt;li data-end=&quot;1095&quot; data-start=&quot;1083&quot; data-section-id=&quot;13vj0wu&quot;&gt;Scale &amp;rarr; 크기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1102&quot; data-start=&quot;1097&quot; data-ke-size=&quot;size16&quot;&gt;가 있다.&lt;/p&gt;
&lt;p data-end=&quot;1106&quot; data-start=&quot;1104&quot; data-ke-size=&quot;size16&quot;&gt;즉,&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;USceneComponent
 └─ Location
 └─ Rotation
 └─ Scale&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1188&quot; data-start=&quot;1173&quot; data-ke-size=&quot;size16&quot;&gt;을 가지고 있다고 이해했다.&lt;/p&gt;
&lt;h3 data-end=&quot;1215&quot; data-start=&quot;1190&quot; data-section-id=&quot;14cdr1g&quot; data-ke-size=&quot;size23&quot;&gt;Actor와 Root Component&lt;/h3&gt;
&lt;p data-end=&quot;1286&quot; data-start=&quot;1217&quot; data-ke-size=&quot;size16&quot;&gt;Actor에 Scene Component가 여러 개 있다면 그중 하나를 &lt;b&gt;Root Component&lt;/b&gt;로 지정할 수 있다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;Actor
 └─ RootComponent
      ├─ Mesh
      ├─ Camera
      └─ SpringArm&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1421&quot; data-start=&quot;1374&quot; data-ke-size=&quot;size16&quot;&gt;Root Component는 &lt;b&gt;Actor 전체 Transform의 기준&lt;/b&gt;이 된다.&lt;/p&gt;
&lt;p data-end=&quot;1452&quot; data-start=&quot;1423&quot; data-ke-size=&quot;size16&quot;&gt;쉽게 말하면 Actor의 좌표 기준점이라고 이해했다.&lt;/p&gt;
&lt;p data-end=&quot;1554&quot; data-start=&quot;1454&quot; data-ke-size=&quot;size16&quot;&gt;언리얼의 Actor는 Transform을 Actor가 직접 가지고 있는 것처럼 보이지만 실제로는 &lt;b&gt;Root Component가 Actor의 Transform 기준을 담당한다.&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;1559&quot; data-start=&quot;1556&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;1586&quot; data-start=&quot;1561&quot; data-section-id=&quot;1ib6tm5&quot;&gt;3. Component Attachment&lt;/h1&gt;
&lt;p data-end=&quot;1622&quot; data-start=&quot;1588&quot; data-ke-size=&quot;size16&quot;&gt;Component끼리는 서로 부모-자식 관계를 만들 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;1645&quot; data-start=&quot;1624&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 플레이어에게 카메라를 붙이면&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;Player
 └─ Capsule (Root)
      └─ Mesh
      └─ SpringArm
           └─ Camera&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1755&quot; data-start=&quot;1740&quot; data-ke-size=&quot;size16&quot;&gt;같은 구조를 만들 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;1767&quot; data-start=&quot;1757&quot; data-ke-size=&quot;size16&quot;&gt;여기서 중요한 점은&lt;/p&gt;
&lt;blockquote data-end=&quot;1795&quot; data-start=&quot;1769&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1795&quot; data-start=&quot;1771&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Attachment는 상속이 아니다.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;1840&quot; data-start=&quot;1797&quot; data-ke-size=&quot;size16&quot;&gt;C++의 상속과 Component Attachment는 완전히 다른 개념이다.&lt;/p&gt;
&lt;h3 data-end=&quot;1852&quot; data-start=&quot;1842&quot; data-section-id=&quot;g4w9qh&quot; data-ke-size=&quot;size23&quot;&gt;C++ 상속&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;UStaticMeshComponent
        &amp;darr;
UPrimitiveComponent
        &amp;darr;
USceneComponent&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1973&quot; data-start=&quot;1944&quot; data-ke-size=&quot;size16&quot;&gt;이것은 &lt;b&gt;클래스와 클래스 사이의 상속 관계&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;1977&quot; data-start=&quot;1975&quot; data-ke-size=&quot;size16&quot;&gt;반면&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;Root
 └─ Mesh
     └─ Camera&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2052&quot; data-start=&quot;2021&quot; data-ke-size=&quot;size16&quot;&gt;는 &lt;b&gt;Component 사이의 부모-자식 관계&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;2057&quot; data-start=&quot;2054&quot; data-ke-size=&quot;size16&quot;&gt;따라서&lt;/p&gt;
&lt;blockquote data-end=&quot;2139&quot; data-start=&quot;2059&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;2139&quot; data-start=&quot;2061&quot; data-ke-size=&quot;size16&quot;&gt;UStaticMeshComponent &amp;rarr; UPrimitiveComponent와&lt;br /&gt;Root &amp;rarr; Mesh는 완전히 별개의 개념이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;2168&quot; data-start=&quot;2141&quot; data-ke-size=&quot;size16&quot;&gt;이 부분은 앞으로 헷갈리지 않도록 구분해야 한다.&lt;/p&gt;
&lt;hr data-end=&quot;2173&quot; data-start=&quot;2170&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;2214&quot; data-start=&quot;2175&quot; data-section-id=&quot;4j5wkd&quot;&gt;4. SetupAttachment와 AttachToComponent&lt;/h1&gt;
&lt;h3 data-end=&quot;2237&quot; data-start=&quot;2216&quot; data-section-id=&quot;cpgti1&quot; data-ke-size=&quot;size23&quot;&gt;SetupAttachment()&lt;/h3&gt;
&lt;p data-end=&quot;2281&quot; data-start=&quot;2239&quot; data-ke-size=&quot;size16&quot;&gt;주로 &lt;b&gt;생성자에서 Component의 부모 관계를 설정할 때 사용&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-end=&quot;2288&quot; data-start=&quot;2283&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;Camera-&amp;gt;SetupAttachment(SpringArm);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2344&quot; data-start=&quot;2338&quot; data-ke-size=&quot;size16&quot;&gt;이라고 하면&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;SpringArm
   └─ Camera&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2400&quot; data-start=&quot;2382&quot; data-ke-size=&quot;size16&quot;&gt;라는 부모-자식 관계를 설정한다.&lt;/p&gt;
&lt;p data-end=&quot;2404&quot; data-start=&quot;2402&quot; data-ke-size=&quot;size16&quot;&gt;즉,&lt;/p&gt;
&lt;blockquote data-end=&quot;2438&quot; data-start=&quot;2406&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;2438&quot; data-start=&quot;2408&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Component 구조를 미리 만들어 놓는 느낌&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;2449&quot; data-start=&quot;2440&quot; data-ke-size=&quot;size16&quot;&gt;이라고 이해했다.&lt;/p&gt;
&lt;hr data-end=&quot;2454&quot; data-start=&quot;2451&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2479&quot; data-start=&quot;2456&quot; data-section-id=&quot;1nukcjc&quot; data-ke-size=&quot;size23&quot;&gt;AttachToComponent()&lt;/h3&gt;
&lt;p data-end=&quot;2561&quot; data-start=&quot;2481&quot; data-ke-size=&quot;size16&quot;&gt;게임이 실행되는 도중에 Component의 Attachment 관계를 변경해야 한다면 AttachToComponent()를 사용할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;2584&quot; data-start=&quot;2563&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 플레이어가 무기를 교체한다면&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;Player
 └─ Hand
      └─ Weapon&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2662&quot; data-start=&quot;2631&quot; data-ke-size=&quot;size16&quot;&gt;처럼 새로운 무기를 손에 붙이는 작업에 사용할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;2668&quot; data-start=&quot;2664&quot; data-ke-size=&quot;size16&quot;&gt;정리하면&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;SetupAttachment()
&amp;rarr; 주로 생성자에서 초기 Attachment 설정

AttachToComponent()
&amp;rarr; 게임 실행 중 Attachment 변경&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2799&quot; data-start=&quot;2774&quot; data-ke-size=&quot;size16&quot;&gt;공식 문서에서도 이 용도로 구분해서 설명한다.&lt;/p&gt;
&lt;hr data-end=&quot;2804&quot; data-start=&quot;2801&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;2829&quot; data-start=&quot;2806&quot; data-section-id=&quot;vwi8xd&quot;&gt;5. Movement Component&lt;/h1&gt;
&lt;p data-end=&quot;2892&quot; data-start=&quot;2831&quot; data-ke-size=&quot;size16&quot;&gt;언리얼에서는 Actor의 이동이나 특정 움직임을 담당하는 &lt;b&gt;Movement Component&lt;/b&gt;가 존재한다.&lt;/p&gt;
&lt;p data-end=&quot;2899&quot; data-start=&quot;2894&quot; data-ke-size=&quot;size16&quot;&gt;대표적으로&lt;/p&gt;
&lt;h3 data-end=&quot;2932&quot; data-start=&quot;2901&quot; data-section-id=&quot;1g39pae&quot; data-ke-size=&quot;size23&quot;&gt;UCharacterMovementComponent&lt;/h3&gt;
&lt;p data-end=&quot;2957&quot; data-start=&quot;2934&quot; data-ke-size=&quot;size16&quot;&gt;ACharacter의 이동을 담당한다.&lt;/p&gt;
&lt;p data-end=&quot;2999&quot; data-start=&quot;2959&quot; data-ke-size=&quot;size16&quot;&gt;걷기, 달리기, 점프, 중력 등의 캐릭터 이동과 관련된 기능을 처리한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;Character
   &amp;darr;
CharacterMovementComponent
   &amp;darr;
이동 / 점프 / 중력 / 속도 등&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;3111&quot; data-start=&quot;3081&quot; data-section-id=&quot;1jgj55v&quot; data-ke-size=&quot;size23&quot;&gt;URotatingMovementComponent&lt;/h3&gt;
&lt;p data-end=&quot;3144&quot; data-start=&quot;3113&quot; data-ke-size=&quot;size16&quot;&gt;Actor를 지속적으로 회전시키는 Component이다.&lt;/p&gt;
&lt;p data-end=&quot;3151&quot; data-start=&quot;3146&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;아이템
  &amp;darr;
계속 빙글빙글 회전&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3248&quot; data-start=&quot;3185&quot; data-ke-size=&quot;size16&quot;&gt;같은 효과를 코드로 직접 매 프레임 회전시키지 않고 Movement Component를 이용해서 구현할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;3336&quot; data-start=&quot;3250&quot; data-ke-size=&quot;size16&quot;&gt;즉 Movement Component는 단순히 &quot;캐릭터만 움직이는 것&quot;이 아니라 &lt;b&gt;Actor의 특정 움직임을 담당하는 Component&lt;/b&gt;라고 이해했다.&lt;/p&gt;
&lt;hr data-end=&quot;3341&quot; data-start=&quot;3338&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;3374&quot; data-start=&quot;3343&quot; data-section-id=&quot;ocw9ap&quot;&gt;6. 전방 선언(Forward Declaration)&lt;/h1&gt;
&lt;p data-end=&quot;3395&quot; data-start=&quot;3376&quot; data-ke-size=&quot;size16&quot;&gt;이번 수업에서 전방 선언도 배웠다.&lt;/p&gt;
&lt;p data-end=&quot;3463&quot; data-start=&quot;3397&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 헤더에서 어떤 클래스의 &lt;b&gt;포인터나 참조만 사용하고 있다면&lt;/b&gt; 굳이 해당 클래스의 전체 헤더를 포함하지 않고&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;class UCameraComponent;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3520&quot; data-start=&quot;3501&quot; data-ke-size=&quot;size16&quot;&gt;처럼 이름만 미리 알려줄 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;3538&quot; data-start=&quot;3522&quot; data-ke-size=&quot;size16&quot;&gt;이것이 &lt;b&gt;전방 선언&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;3563&quot; data-start=&quot;3540&quot; data-ke-size=&quot;size16&quot;&gt;그리고 실제 구현이 필요한 .cpp에서&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;autoit&quot;&gt;&lt;code&gt;#include &quot;Camera/CameraComponent.h&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3620&quot; data-start=&quot;3613&quot; data-ke-size=&quot;size16&quot;&gt;를 포함한다.&lt;/p&gt;
&lt;h3 data-end=&quot;3634&quot; data-start=&quot;3622&quot; data-section-id=&quot;i31ydo&quot; data-ke-size=&quot;size23&quot;&gt;왜 사용하는가?&lt;/h3&gt;
&lt;p data-end=&quot;3658&quot; data-start=&quot;3636&quot; data-ke-size=&quot;size16&quot;&gt;헤더 파일의 의존성을 줄이기 위해서이다.&lt;/p&gt;
&lt;p data-end=&quot;3696&quot; data-start=&quot;3660&quot; data-ke-size=&quot;size16&quot;&gt;특히 .h 파일은 다른 여러 .cpp에서 포함될 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;3728&quot; data-start=&quot;3698&quot; data-ke-size=&quot;size16&quot;&gt;따라서 헤더에 불필요한 #include가 많아질수록&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;A.h
 &amp;darr;
B.h
 &amp;darr;
C.h
 &amp;darr;
D.h&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3788&quot; data-start=&quot;3768&quot; data-ke-size=&quot;size16&quot;&gt;처럼 의존성이 계속 늘어날 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;3800&quot; data-start=&quot;3790&quot; data-ke-size=&quot;size16&quot;&gt;그래서 가능한 경우&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;// .h
class UCameraComponent;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;// .cpp
#include &quot;Camera/CameraComponent.h&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3908&quot; data-start=&quot;3900&quot; data-ke-size=&quot;size16&quot;&gt;처럼 분리한다.&lt;/p&gt;
&lt;hr data-end=&quot;3913&quot; data-start=&quot;3910&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;3924&quot; data-start=&quot;3915&quot; data-section-id=&quot;1qvlfyl&quot;&gt;7. IWYU&lt;/h1&gt;
&lt;p data-end=&quot;3981&quot; data-start=&quot;3926&quot; data-ke-size=&quot;size16&quot;&gt;언리얼 엔진은 &lt;b&gt;IWYU(Include What You Use)&lt;/b&gt; 방식의 헤더 관리를 사용한다.&lt;/p&gt;
&lt;p data-end=&quot;3988&quot; data-start=&quot;3983&quot; data-ke-size=&quot;size16&quot;&gt;뜻 그대로&lt;/p&gt;
&lt;blockquote data-end=&quot;4025&quot; data-start=&quot;3990&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;4025&quot; data-start=&quot;3992&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;내가 사용하는 것에 필요한 헤더만 Include하자.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;4035&quot; data-start=&quot;4027&quot; data-ke-size=&quot;size16&quot;&gt;라는 개념이다.&lt;/p&gt;
&lt;p data-end=&quot;4044&quot; data-start=&quot;4037&quot; data-ke-size=&quot;size16&quot;&gt;따라서 무작정&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;autoit&quot;&gt;&lt;code&gt;#include &quot;Everything.h&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4132&quot; data-start=&quot;4082&quot; data-ke-size=&quot;size16&quot;&gt;식으로 가져오는 것이 아니라 해당 파일에서 실제로 필요한 헤더만 포함하는 습관이 중요하다.&lt;/p&gt;
&lt;hr data-end=&quot;4137&quot; data-start=&quot;4134&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;4162&quot; data-start=&quot;4139&quot; data-section-id=&quot;170jwod&quot;&gt;8. 전방 선언을 사용할 수 있는 경우&lt;/h1&gt;
&lt;p data-end=&quot;4184&quot; data-start=&quot;4164&quot; data-ke-size=&quot;size16&quot;&gt;여기가 아직 가장 헷갈리는 부분이다.&lt;/p&gt;
&lt;h3 data-end=&quot;4203&quot; data-start=&quot;4186&quot; data-section-id=&quot;159qc9f&quot; data-ke-size=&quot;size23&quot;&gt;전방 선언이 가능한 경우&lt;/h3&gt;
&lt;p data-end=&quot;4229&quot; data-start=&quot;4205&quot; data-ke-size=&quot;size16&quot;&gt;해당 타입의 &lt;b&gt;이름만 알면 되는 경우&lt;/b&gt;.&lt;/p&gt;
&lt;p data-end=&quot;4247&quot; data-start=&quot;4231&quot; data-ke-size=&quot;size16&quot;&gt;대표적으로 포인터나 레퍼런스.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;class UCameraComponent;

UCameraComponent* Camera;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4358&quot; data-start=&quot;4312&quot; data-ke-size=&quot;size16&quot;&gt;이런 경우에는 클래스의 내부 구조까지 알 필요가 없기 때문에 전방 선언이 가능하다.&lt;/p&gt;
&lt;hr data-end=&quot;4363&quot; data-start=&quot;4360&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;4383&quot; data-start=&quot;4365&quot; data-section-id=&quot;12a5woe&quot; data-ke-size=&quot;size23&quot;&gt;전방 선언이 안 되는 경우&lt;/h3&gt;
&lt;p data-end=&quot;4407&quot; data-start=&quot;4385&quot; data-ke-size=&quot;size16&quot;&gt;클래스 자체의 실제 내용이 필요한 경우.&lt;/p&gt;
&lt;p data-end=&quot;4422&quot; data-start=&quot;4409&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 상속받는 경우&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;class AMyCharacter : public ACharacter&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4525&quot; data-start=&quot;4475&quot; data-ke-size=&quot;size16&quot;&gt;ACharacter가 실제로 어떤 클래스인지 알아야 하기 때문에 해당 헤더가 필요하다.&lt;/p&gt;
&lt;p data-end=&quot;4584&quot; data-start=&quot;4527&quot; data-ke-size=&quot;size16&quot;&gt;또한 클래스의 멤버를 직접 사용하거나 객체의 크기 등을 알아야 하는 상황에서는 완전한 정의가 필요하다.&lt;/p&gt;
&lt;p data-end=&quot;4610&quot; data-start=&quot;4586&quot; data-ke-size=&quot;size16&quot;&gt;그래서 아직은 다음 정도만 기억하기로 했다.&lt;/p&gt;
&lt;blockquote data-end=&quot;4689&quot; data-start=&quot;4612&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;4689&quot; data-start=&quot;4614&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;포인터/레퍼런스로 이름만 필요 &amp;rarr; 전방 선언 고려&lt;/b&gt;&lt;br /&gt;&lt;b&gt;상속하거나 내부 내용을 실제로 사용 &amp;rarr; 헤더 Include 필요&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;4694&quot; data-start=&quot;4691&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;4711&quot; data-start=&quot;4696&quot; data-section-id=&quot;ey3cqm&quot;&gt;9. Spring Arm&lt;/h1&gt;
&lt;p data-end=&quot;4740&quot; data-start=&quot;4713&quot; data-ke-size=&quot;size16&quot;&gt;USpringArmComponent도 배웠다.&lt;/p&gt;
&lt;p data-end=&quot;4798&quot; data-start=&quot;4742&quot; data-ke-size=&quot;size16&quot;&gt;Spring Arm은 자식 Component를 일정 거리만큼 떨어뜨려 유지하는 Component이다.&lt;/p&gt;
&lt;p data-end=&quot;4826&quot; data-start=&quot;4800&quot; data-ke-size=&quot;size16&quot;&gt;대표적인 사용 방법이 &lt;b&gt;3인칭 카메라&lt;/b&gt;이다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;Player
 └─ SpringArm
      └─ Camera&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4925&quot; data-start=&quot;4878&quot; data-ke-size=&quot;size16&quot;&gt;Spring Arm의 길이를 설정하면 Camera가 플레이어와 일정 거리를 유지한다.&lt;/p&gt;
&lt;p data-end=&quot;5010&quot; data-start=&quot;4927&quot; data-ke-size=&quot;size16&quot;&gt;또한 카메라와 플레이어 사이에 벽 등의 충돌이 발생하면 Spring Arm이 길이를 줄여서 &lt;b&gt;카메라가 벽을 뚫고 들어가는 것을 방지&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;5021&quot; data-start=&quot;5012&quot; data-ke-size=&quot;size16&quot;&gt;다만 내가 적어둔&lt;/p&gt;
&lt;blockquote data-end=&quot;5051&quot; data-start=&quot;5023&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;5051&quot; data-start=&quot;5025&quot; data-ke-size=&quot;size16&quot;&gt;&quot;FPS에서 벽 바라보면 FOV가 늘어나는 것&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;5108&quot; data-start=&quot;5053&quot; data-ke-size=&quot;size16&quot;&gt;은 Spring Arm의 대표적인 기능이라고 보기보다는 &lt;b&gt;다른 카메라 연출과 혼동한 부분&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;5125&quot; data-start=&quot;5110&quot; data-ke-size=&quot;size16&quot;&gt;Spring Arm의 핵심은&lt;/p&gt;
&lt;blockquote data-end=&quot;5164&quot; data-start=&quot;5127&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;5164&quot; data-start=&quot;5129&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;카메라와 캐릭터 사이의 거리 유지 + 충돌 시 길이 조절&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;5182&quot; data-start=&quot;5166&quot; data-ke-size=&quot;size16&quot;&gt;이라고 기억하는 게 정확하다.&lt;/p&gt;
&lt;hr data-end=&quot;5187&quot; data-start=&quot;5184&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;5211&quot; data-start=&quot;5189&quot; data-section-id=&quot;fihzcv&quot;&gt;10. Camera Component&lt;/h1&gt;
&lt;p data-end=&quot;5246&quot; data-start=&quot;5213&quot; data-ke-size=&quot;size16&quot;&gt;UCameraComponent는 실제 카메라를 담당한다.&lt;/p&gt;
&lt;p data-end=&quot;5291&quot; data-start=&quot;5248&quot; data-ke-size=&quot;size16&quot;&gt;단순히 위치와 회전만 담당하는 것이 아니라 카메라의 여러 설정을 가지고 있다.&lt;/p&gt;
&lt;p data-end=&quot;5298&quot; data-start=&quot;5293&quot; data-ke-size=&quot;size16&quot;&gt;대표적으로&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;5361&quot; data-start=&quot;5300&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;5310&quot; data-start=&quot;5300&quot; data-section-id=&quot;3ic6c5&quot;&gt;Location&lt;/li&gt;
&lt;li data-end=&quot;5321&quot; data-start=&quot;5311&quot; data-section-id=&quot;46son0&quot;&gt;Rotation&lt;/li&gt;
&lt;li data-end=&quot;5342&quot; data-start=&quot;5322&quot; data-section-id=&quot;eew1g0&quot;&gt;Field of View(FOV)&lt;/li&gt;
&lt;li data-end=&quot;5361&quot; data-start=&quot;5343&quot; data-section-id=&quot;1i5x2lo&quot;&gt;Projection 관련 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;5369&quot; data-start=&quot;5363&quot; data-ke-size=&quot;size16&quot;&gt;등이 있다.&lt;/p&gt;
&lt;p data-end=&quot;5373&quot; data-start=&quot;5371&quot; data-ke-size=&quot;size16&quot;&gt;즉,&lt;/p&gt;
&lt;blockquote data-end=&quot;5445&quot; data-start=&quot;5375&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;5445&quot; data-start=&quot;5377&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SpringArm = 카메라를 어떻게 따라오게 할지&lt;/b&gt;&lt;br /&gt;&lt;b&gt;CameraComponent = 실제 카메라 자체&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;5464&quot; data-start=&quot;5447&quot; data-ke-size=&quot;size16&quot;&gt;라고 생각하면 이해하기 쉬웠다.&lt;/p&gt;
&lt;hr data-end=&quot;5469&quot; data-start=&quot;5466&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;5488&quot; data-start=&quot;5471&quot; data-section-id=&quot;1ib3xg7&quot;&gt;11. Raw Pointer&lt;/h1&gt;
&lt;p data-end=&quot;5512&quot; data-start=&quot;5490&quot; data-ke-size=&quot;size16&quot;&gt;이번 수업에서 가장 머리가 아팠던 부분.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;UCameraComponent* Camera;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5575&quot; data-start=&quot;5552&quot; data-ke-size=&quot;size16&quot;&gt;여기서 *는 &lt;b&gt;포인터&lt;/b&gt;를 의미한다.&lt;/p&gt;
&lt;p data-end=&quot;5588&quot; data-start=&quot;5577&quot; data-ke-size=&quot;size16&quot;&gt;포인터는 쉽게 말해서&lt;/p&gt;
&lt;blockquote data-end=&quot;5625&quot; data-start=&quot;5590&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;5625&quot; data-start=&quot;5592&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;어떤 객체가 메모리의 어디에 존재하는지를 가리키는 값&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;5630&quot; data-start=&quot;5627&quot; data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;5635&quot; data-start=&quot;5632&quot; data-ke-size=&quot;size16&quot;&gt;따라서&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;UCameraComponent* Camera;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5679&quot; data-start=&quot;5675&quot; data-ke-size=&quot;size16&quot;&gt;를 보면&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;Camera
 &amp;darr;
UCameraComponent 객체가 있는 메모리 주소&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5746&quot; data-start=&quot;5735&quot; data-ke-size=&quot;size16&quot;&gt;라고 이해하면 된다.&lt;/p&gt;
&lt;hr data-end=&quot;5751&quot; data-start=&quot;5748&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;5762&quot; data-start=&quot;5753&quot; data-section-id=&quot;w1tfib&quot; data-ke-size=&quot;size26&quot;&gt;T*의 의미&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;T* Pointer;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5842&quot; data-start=&quot;5788&quot; data-ke-size=&quot;size16&quot;&gt;여기서 T는 특정한 하나의 자료형을 의미하는 게 아니라 &lt;b&gt;타입을 대신 나타내는 표현&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;5849&quot; data-start=&quot;5844&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;fortran&quot;&gt;&lt;code&gt;int* Number;
float* Value;
UCameraComponent* Camera;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5928&quot; data-start=&quot;5916&quot; data-ke-size=&quot;size16&quot;&gt;처럼 사용할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;5931&quot; data-start=&quot;5930&quot; data-ke-size=&quot;size16&quot;&gt;즉&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;excel&quot;&gt;&lt;code&gt;T* 
 &amp;darr;
&quot;어떤 타입 T를 가리키는 포인터&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5981&quot; data-start=&quot;5973&quot; data-ke-size=&quot;size16&quot;&gt;라고 이해했다.&lt;/p&gt;
&lt;hr data-end=&quot;5986&quot; data-start=&quot;5983&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;6021&quot; data-start=&quot;5988&quot; data-section-id=&quot;1oxr8xh&quot;&gt;12. Raw Pointer와 Unreal UObject&lt;/h1&gt;
&lt;p data-end=&quot;6072&quot; data-start=&quot;6023&quot; data-ke-size=&quot;size16&quot;&gt;일반적인 C++의 Raw Pointer는 언리얼의 UObject 시스템과는 별개이다.&lt;/p&gt;
&lt;p data-end=&quot;6090&quot; data-start=&quot;6074&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 일반 C++ 객체를&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;Weapon* WeaponPtr = new Weapon();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;6181&quot; data-start=&quot;6138&quot; data-ke-size=&quot;size16&quot;&gt;처럼 생성했다면 그 객체의 메모리 관리는 일반적인 C++ 방식으로 이루어진다.&lt;/p&gt;
&lt;p data-end=&quot;6246&quot; data-start=&quot;6183&quot; data-ke-size=&quot;size16&quot;&gt;반면 언리얼의 UObject는 &lt;b&gt;Unreal의 Garbage Collection 시스템&lt;/b&gt;에 의해 관리된다.&lt;/p&gt;
&lt;p data-end=&quot;6255&quot; data-start=&quot;6248&quot; data-ke-size=&quot;size16&quot;&gt;그래서 단순히&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;UCameraComponent* Camera;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;6364&quot; data-start=&quot;6295&quot; data-ke-size=&quot;size16&quot;&gt;라고 포인터를 가지고 있는 것만으로는 Unreal GC가 해당 객체를 참조하고 있다는 사실을 제대로 추적하지 못할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;6441&quot; data-start=&quot;6366&quot; data-ke-size=&quot;size16&quot;&gt;그래서 Unreal에서는 UObject 계열 객체를 참조할 때 &lt;b&gt;Unreal의 객체 시스템에 맞는 방식&lt;/b&gt;을 사용하는 것이 중요하다.&lt;/p&gt;
&lt;hr data-end=&quot;6446&quot; data-start=&quot;6443&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;6464&quot; data-start=&quot;6448&quot; data-section-id=&quot;guk5el&quot;&gt;13. TObjectPtr&lt;/h1&gt;
&lt;p data-end=&quot;6475&quot; data-start=&quot;6466&quot; data-ke-size=&quot;size16&quot;&gt;그래서 나온 것이&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;TObjectPtr&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;6506&quot; data-start=&quot;6503&quot; data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;6513&quot; data-start=&quot;6508&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;UPROPERTY()
TObjectPtr&amp;lt;UCameraComponent&amp;gt; Camera;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;6588&quot; data-start=&quot;6576&quot; data-ke-size=&quot;size16&quot;&gt;처럼 사용할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;6632&quot; data-start=&quot;6590&quot; data-ke-size=&quot;size16&quot;&gt;TObjectPtr은 일반적인 C++ 스마트 포인터와 같은 개념이 아니라&lt;/p&gt;
&lt;blockquote data-end=&quot;6685&quot; data-start=&quot;6634&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;6685&quot; data-start=&quot;6636&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Unreal의 UObject 시스템에서 UObject를 참조하기 위한 포인터 타입&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;6696&quot; data-start=&quot;6687&quot; data-ke-size=&quot;size16&quot;&gt;이라고 이해했다.&lt;/p&gt;
&lt;p data-end=&quot;6756&quot; data-start=&quot;6698&quot; data-ke-size=&quot;size16&quot;&gt;특히 UPROPERTY()와 함께 사용하면 Unreal의 객체 시스템이 해당 참조를 추적할 수 있다.&lt;/p&gt;
&lt;hr data-end=&quot;6761&quot; data-start=&quot;6758&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;6812&quot; data-start=&quot;6763&quot; data-section-id=&quot;t7lfan&quot;&gt;14. Raw Pointer / TObjectPtr / Smart Pointer 구분&lt;/h1&gt;
&lt;p data-end=&quot;6834&quot; data-start=&quot;6814&quot; data-ke-size=&quot;size16&quot;&gt;이번 수업에서 이것도 구분해야 했다.&lt;/p&gt;
&lt;h3 data-end=&quot;6851&quot; data-start=&quot;6836&quot; data-section-id=&quot;14qbg61&quot; data-ke-size=&quot;size23&quot;&gt;Raw Pointer&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;excel&quot;&gt;&lt;code&gt;T*&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;6881&quot; data-start=&quot;6868&quot; data-ke-size=&quot;size16&quot;&gt;일반적인 C++ 포인터.&lt;/p&gt;
&lt;p data-end=&quot;6915&quot; data-start=&quot;6883&quot; data-ke-size=&quot;size16&quot;&gt;객체의 수명을 자동으로 관리해주는 스마트 포인터가 아니다.&lt;/p&gt;
&lt;hr data-end=&quot;6920&quot; data-start=&quot;6917&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;6936&quot; data-start=&quot;6922&quot; data-section-id=&quot;4o3g5t&quot; data-ke-size=&quot;size23&quot;&gt;TObjectPtr&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;TObjectPtr&amp;lt;UObject&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;7010&quot; data-start=&quot;6970&quot; data-ke-size=&quot;size16&quot;&gt;Unreal의 UObject 시스템에서 객체를 참조하기 위한 포인터.&lt;/p&gt;
&lt;hr data-end=&quot;7015&quot; data-start=&quot;7012&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;7044&quot; data-start=&quot;7017&quot; data-section-id=&quot;170zlrn&quot; data-ke-size=&quot;size23&quot;&gt;TSharedPtr / TUniquePtr&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;TSharedPtr&amp;lt;T&amp;gt;
TUniquePtr&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;7123&quot; data-start=&quot;7086&quot; data-ke-size=&quot;size16&quot;&gt;일반적인 C++ 객체의 &lt;b&gt;수명 관리&lt;/b&gt;에 사용하는 스마트 포인터.&lt;/p&gt;
&lt;p data-end=&quot;7128&quot; data-start=&quot;7125&quot; data-ke-size=&quot;size16&quot;&gt;따라서&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;brainfuck&quot;&gt;&lt;code&gt;Raw Pointer
&amp;rarr; 일반적인 C++ 포인터

TObjectPtr
&amp;rarr; Unreal UObject 참조

TSharedPtr / TUniquePtr
&amp;rarr; 일반 C++ 객체의 스마트 포인터&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;7258&quot; data-start=&quot;7248&quot; data-ke-size=&quot;size16&quot;&gt;로 구분하면 된다.&lt;/p&gt;
&lt;hr data-end=&quot;7263&quot; data-start=&quot;7260&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;7290&quot; data-start=&quot;7265&quot; data-section-id=&quot;rcgvsg&quot;&gt;15. Unreal에서 포인터를 사용할 때&lt;/h1&gt;
&lt;p data-end=&quot;7305&quot; data-start=&quot;7292&quot; data-ke-size=&quot;size16&quot;&gt;이번 수업에서 느낀 점은&lt;/p&gt;
&lt;blockquote data-end=&quot;7335&quot; data-start=&quot;7307&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;7335&quot; data-start=&quot;7309&quot; data-ke-size=&quot;size16&quot;&gt;&quot;C++ 포인터라고 다 같은 포인터가 아니다.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;7344&quot; data-start=&quot;7337&quot; data-ke-size=&quot;size16&quot;&gt;라는 것이다.&lt;/p&gt;
&lt;p data-end=&quot;7394&quot; data-start=&quot;7346&quot; data-ke-size=&quot;size16&quot;&gt;특히 Unreal에서는 UObject와 Garbage Collection이 있기 때문에&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;UObject*&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;7445&quot; data-start=&quot;7417&quot; data-ke-size=&quot;size16&quot;&gt;를 그냥 일반 C++ 포인터처럼 생각하면 안 된다.&lt;/p&gt;
&lt;p data-end=&quot;7491&quot; data-start=&quot;7447&quot; data-ke-size=&quot;size16&quot;&gt;그래서 Unreal의 UObject를 멤버 변수로 가지고 있을 때는 상황에 따라&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;UPROPERTY()
TObjectPtr&amp;lt;...&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;7550&quot; data-start=&quot;7533&quot; data-ke-size=&quot;size16&quot;&gt;형태를 사용하는 것이 권장된다.&lt;/p&gt;
&lt;hr data-end=&quot;7555&quot; data-start=&quot;7552&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;7576&quot; data-start=&quot;7557&quot; data-section-id=&quot;nc6s9e&quot;&gt;16. Unreal의 기본 방향&lt;/h1&gt;
&lt;p data-end=&quot;7617&quot; data-start=&quot;7578&quot; data-ke-size=&quot;size16&quot;&gt;회전을 이해하기 전에 &lt;b&gt;언리얼의 좌표축&lt;/b&gt;부터 확실하게 외워야 한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;X = Forward = 앞
Y = Right   = 오른쪽
Z = Up      = 위&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;7684&quot; data-start=&quot;7682&quot; data-ke-size=&quot;size16&quot;&gt;즉,&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;FVector::ForwardVector&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;7722&quot; data-start=&quot;7721&quot; data-ke-size=&quot;size16&quot;&gt;는&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;(1, 0, 0)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;7750&quot; data-start=&quot;7747&quot; data-ke-size=&quot;size16&quot;&gt;이고,&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;FVector::RightVector&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;7786&quot; data-start=&quot;7785&quot; data-ke-size=&quot;size16&quot;&gt;는&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;(0, 1, 0)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;7814&quot; data-start=&quot;7811&quot; data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;7819&quot; data-start=&quot;7816&quot; data-ke-size=&quot;size16&quot;&gt;위쪽은&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;(0, 0, 1)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;7847&quot; data-start=&quot;7844&quot; data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;hr data-end=&quot;7852&quot; data-start=&quot;7849&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;7877&quot; data-start=&quot;7854&quot; data-section-id=&quot;1epnofq&quot;&gt;17. FVector와 FRotator&lt;/h1&gt;
&lt;p data-end=&quot;7906&quot; data-start=&quot;7879&quot; data-ke-size=&quot;size16&quot;&gt;이번 수업에서 특히 중요하게 구분해야 하는 부분.&lt;/p&gt;
&lt;h3 data-end=&quot;7919&quot; data-start=&quot;7908&quot; data-section-id=&quot;1k8wybd&quot; data-ke-size=&quot;size23&quot;&gt;FVector&lt;/h3&gt;
&lt;p data-end=&quot;7940&quot; data-start=&quot;7921&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;위치 또는 방향&lt;/b&gt;을 표현한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;FVector Location;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;7988&quot; data-start=&quot;7972&quot; data-ke-size=&quot;size16&quot;&gt;하면 위치를 표현할 수 있고,&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;FVector Direction;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;8038&quot; data-start=&quot;8021&quot; data-ke-size=&quot;size16&quot;&gt;하면 방향을 표현할 수도 있다.&lt;/p&gt;
&lt;p data-end=&quot;8050&quot; data-start=&quot;8040&quot; data-ke-size=&quot;size16&quot;&gt;즉 FVector는&lt;/p&gt;
&lt;blockquote data-end=&quot;8075&quot; data-start=&quot;8052&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;8075&quot; data-start=&quot;8054&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3차원 공간에서의 X/Y/Z 값&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;8089&quot; data-start=&quot;8077&quot; data-ke-size=&quot;size16&quot;&gt;이라고 생각하면 된다.&lt;/p&gt;
&lt;hr data-end=&quot;8094&quot; data-start=&quot;8091&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;8108&quot; data-start=&quot;8096&quot; data-section-id=&quot;185pwh&quot; data-ke-size=&quot;size23&quot;&gt;FRotator&lt;/h3&gt;
&lt;p data-end=&quot;8125&quot; data-start=&quot;8110&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;회전 값&lt;/b&gt;을 표현한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;FRotator Rotation(0.0f, 90.0f, 0.0f);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;8180&quot; data-start=&quot;8177&quot; data-ke-size=&quot;size16&quot;&gt;여기서&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;Pitch = 상하 회전
Yaw   = 좌우 회전
Roll  = 기울기&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;8238&quot; data-start=&quot;8235&quot; data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;8243&quot; data-start=&quot;8240&quot; data-ke-size=&quot;size16&quot;&gt;따라서&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;FRotator(Pitch, Yaw, Roll)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;8293&quot; data-start=&quot;8284&quot; data-ke-size=&quot;size16&quot;&gt;순서로 기억한다.&lt;/p&gt;
&lt;hr data-end=&quot;8298&quot; data-start=&quot;8295&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;8334&quot; data-start=&quot;8300&quot; data-section-id=&quot;xu9mo9&quot;&gt;18. FVector vs FRotator vs 실제 회전&lt;/h1&gt;
&lt;p data-end=&quot;8359&quot; data-start=&quot;8336&quot; data-ke-size=&quot;size16&quot;&gt;이번 수업에서 가장 중요한 구분 중 하나.&lt;/p&gt;
&lt;h3 data-end=&quot;8372&quot; data-start=&quot;8361&quot; data-section-id=&quot;1k8wybd&quot; data-ke-size=&quot;size23&quot;&gt;FVector&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;어디에 있는가?
어느 방향인가?&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;8416&quot; data-start=&quot;8405&quot; data-ke-size=&quot;size16&quot;&gt;를 표현할 수 있다.&lt;/p&gt;
&lt;h3 data-end=&quot;8430&quot; data-start=&quot;8418&quot; data-section-id=&quot;185pwh&quot; data-ke-size=&quot;size23&quot;&gt;FRotator&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;얼마나 회전되어 있는가?&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;8466&quot; data-start=&quot;8459&quot; data-ke-size=&quot;size16&quot;&gt;를 표현한다.&lt;/p&gt;
&lt;h3 data-end=&quot;8490&quot; data-start=&quot;8468&quot; data-section-id=&quot;dfd8ai&quot; data-ke-size=&quot;size23&quot;&gt;SetActorRotation()&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;SetActorRotation(Rotation);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;8552&quot; data-start=&quot;8532&quot; data-ke-size=&quot;size16&quot;&gt;실제로 Actor의 회전을 변경한다.&lt;/p&gt;
&lt;p data-end=&quot;8556&quot; data-start=&quot;8554&quot; data-ke-size=&quot;size16&quot;&gt;즉,&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;FVector
&amp;rarr; 방향

FRotator
&amp;rarr; 회전값

SetActorRotation()
&amp;rarr; 실제 Actor 회전 적용&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;8646&quot; data-start=&quot;8637&quot; data-ke-size=&quot;size16&quot;&gt;이라고 정리했다.&lt;/p&gt;
&lt;hr data-end=&quot;8651&quot; data-start=&quot;8648&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;8674&quot; data-start=&quot;8653&quot; data-section-id=&quot;1bf0fs9&quot;&gt;19. FRotationMatrix&lt;/h1&gt;
&lt;p data-end=&quot;8726&quot; data-start=&quot;8676&quot; data-ke-size=&quot;size16&quot;&gt;FRotationMatrix는 처음 보면 굉장히 수학적으로 보여서 겁먹기 쉬운데 일단은&lt;/p&gt;
&lt;blockquote data-end=&quot;8774&quot; data-start=&quot;8728&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;8774&quot; data-start=&quot;8730&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;특정 회전을 기준으로 현재 앞/오른쪽/위 방향이 어디인지 계산해주는 도구&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;8788&quot; data-start=&quot;8776&quot; data-ke-size=&quot;size16&quot;&gt;라고 이해하기로 했다.&lt;/p&gt;
&lt;p data-end=&quot;8802&quot; data-start=&quot;8790&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 Actor가&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;Yaw = 90&amp;deg;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;8839&quot; data-start=&quot;8827&quot; data-ke-size=&quot;size16&quot;&gt;만큼 회전했다면 기존의&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;X = 앞
Y = 오른쪽&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;8923&quot; data-start=&quot;8868&quot; data-ke-size=&quot;size16&quot;&gt;기준이 그대로 유지되는 것이 아니라 Actor가 바라보는 방향에 맞게 새로운 방향을 계산해야 한다.&lt;/p&gt;
&lt;p data-end=&quot;8976&quot; data-start=&quot;8925&quot; data-ke-size=&quot;size16&quot;&gt;이때 FRotationMatrix 등을 이용해서 회전된 기준에서의 방향을 구할 수 있다.&lt;/p&gt;
&lt;hr data-end=&quot;8981&quot; data-start=&quot;8978&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;9002&quot; data-start=&quot;8983&quot; data-section-id=&quot;1kzho2g&quot;&gt;20. GetUnitAxis()&lt;/h1&gt;
&lt;p data-end=&quot;9038&quot; data-start=&quot;9004&quot; data-ke-size=&quot;size16&quot;&gt;회전된 기준에서 특정 축의 방향을 가져올 때 사용할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;9045&quot; data-start=&quot;9040&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;FRotationMatrix(Rotation).GetUnitAxis(EAxis::X);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;9110&quot; data-start=&quot;9108&quot; data-ke-size=&quot;size16&quot;&gt;라면&lt;/p&gt;
&lt;blockquote data-end=&quot;9163&quot; data-start=&quot;9112&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;9163&quot; data-start=&quot;9114&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;현재 Rotation을 기준으로 X축, 즉 Forward 방향이 어디를 가리키는지&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;9178&quot; data-start=&quot;9165&quot; data-ke-size=&quot;size16&quot;&gt;구하는 것으로 이해했다.&lt;/p&gt;
&lt;p data-end=&quot;9185&quot; data-start=&quot;9180&quot; data-ke-size=&quot;size16&quot;&gt;마찬가지로&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;EAxis::Y&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;9219&quot; data-start=&quot;9208&quot; data-ke-size=&quot;size16&quot;&gt;는 Right 방향,&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;EAxis::Z&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;9266&quot; data-start=&quot;9242&quot; data-ke-size=&quot;size16&quot;&gt;는 Up 방향을 구하는 데 사용할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;9330&quot; data-start=&quot;9268&quot; data-ke-size=&quot;size16&quot;&gt;그래서 나중에 캐릭터가 바라보는 방향으로 총알을 발사하거나 이동 방향을 계산할 때 이런 코드가 등장할 수 있다.&lt;/p&gt;
&lt;hr data-end=&quot;9335&quot; data-start=&quot;9332&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;9361&quot; data-start=&quot;9337&quot; data-section-id=&quot;1w4t5nu&quot;&gt;21. 캐릭터 회전에서 자주 나오는 개념&lt;/h1&gt;
&lt;p data-end=&quot;9394&quot; data-start=&quot;9363&quot; data-ke-size=&quot;size16&quot;&gt;캐릭터를 만들다 보면 다음과 같은 코드가 자주 등장한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;FRotator
FRotationMatrix
GetControlRotation()
YawRotation
GetUnitAxis(EAxis::X)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;9513&quot; data-start=&quot;9488&quot; data-ke-size=&quot;size16&quot;&gt;처음에는 각각 따로 노는 것처럼 보이지만 결국&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;gcode&quot;&gt;&lt;code&gt;&quot;캐릭터가 어디를 바라보고 있는가?&quot;
        &amp;darr;
회전값(FRotator)
        &amp;darr;
회전된 방향 계산
        &amp;darr;
Forward / Right 방향(FVector)
        &amp;darr;
이동 / 공격 / 회전 등에 사용&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;9674&quot; data-start=&quot;9660&quot; data-ke-size=&quot;size16&quot;&gt;이라는 흐름으로 연결된다.&lt;/p&gt;
&lt;hr data-end=&quot;9679&quot; data-start=&quot;9676&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;9701&quot; data-start=&quot;9681&quot; data-section-id=&quot;1jdfi1&quot;&gt;22. 이번 수업에서 헷갈렸던 것&lt;/h1&gt;
&lt;p data-end=&quot;9737&quot; data-start=&quot;9703&quot; data-ke-size=&quot;size16&quot;&gt;이번 수업에서 특히 헷갈렸던 부분은 포인터와 전방 선언이었다.&lt;/p&gt;
&lt;h3 data-end=&quot;9746&quot; data-start=&quot;9739&quot; data-section-id=&quot;1xkb19e&quot; data-ke-size=&quot;size23&quot;&gt;포인터&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;UCameraComponent* Camera;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;9809&quot; data-start=&quot;9786&quot; data-ke-size=&quot;size16&quot;&gt;에서 *가 단순히 이상한 기호가 아니라&lt;/p&gt;
&lt;blockquote data-end=&quot;9873&quot; data-start=&quot;9811&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;9873&quot; data-start=&quot;9813&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;UCameraComponent 객체를 직접 저장하는 것이 아니라 그 객체를 가리키는 주소를 저장한다.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;9890&quot; data-start=&quot;9875&quot; data-ke-size=&quot;size16&quot;&gt;는 의미라는 것을 이해했다.&lt;/p&gt;
&lt;p data-end=&quot;9983&quot; data-start=&quot;9892&quot; data-ke-size=&quot;size16&quot;&gt;그리고 Unreal에서는 UObject가 Garbage Collection의 영향을 받기 때문에 일반적인 C++ 포인터와 Unreal의 객체 참조를 구분해야 한다.&lt;/p&gt;
&lt;hr data-end=&quot;9988&quot; data-start=&quot;9985&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;9999&quot; data-start=&quot;9990&quot; data-section-id=&quot;p1mewj&quot; data-ke-size=&quot;size23&quot;&gt;전방 선언&lt;/h3&gt;
&lt;p data-end=&quot;10007&quot; data-start=&quot;10001&quot; data-ke-size=&quot;size16&quot;&gt;전방 선언은&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;class UCameraComponent;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;10073&quot; data-start=&quot;10045&quot; data-ke-size=&quot;size16&quot;&gt;처럼 클래스의 &lt;b&gt;존재만 미리 알려주는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;10078&quot; data-start=&quot;10075&quot; data-ke-size=&quot;size16&quot;&gt;따라서&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;UCameraComponent* Camera;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;10144&quot; data-start=&quot;10118&quot; data-ke-size=&quot;size16&quot;&gt;처럼 포인터를 선언하는 데는 사용할 수 있지만,&lt;/p&gt;
&lt;p data-end=&quot;10179&quot; data-start=&quot;10146&quot; data-ke-size=&quot;size16&quot;&gt;클래스의 내부 내용이 필요한 경우에는 실제 헤더가 필요하다.&lt;/p&gt;
&lt;p data-end=&quot;10252&quot; data-start=&quot;10181&quot; data-ke-size=&quot;size16&quot;&gt;아직 이 부분은 경험이 부족해서 &lt;b&gt;&quot;언제 전방 선언을 쓰고 언제 Include해야 하는지&quot;를 바로 판단하는 짬은 부족하다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;10283&quot; data-start=&quot;10254&quot; data-ke-size=&quot;size16&quot;&gt;앞으로 코드를 작성하면서 경험을 쌓아야 할 것 같다.&lt;/p&gt;
&lt;hr data-end=&quot;10288&quot; data-start=&quot;10285&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;10310&quot; data-start=&quot;10290&quot; data-section-id=&quot;rqx41o&quot;&gt;23. 오늘 배운 내용 전체 연결&lt;/h1&gt;
&lt;p data-end=&quot;10343&quot; data-start=&quot;10312&quot; data-ke-size=&quot;size16&quot;&gt;오늘 배운 내용을 하나의 구조로 연결해보면 다음과 같다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;Actor
 │
 └─ Root Component
      │
      ├─ Mesh
      │
      ├─ SpringArm
      │    └─ Camera
      │
      └─ 기타 Component&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;10540&quot; data-start=&quot;10486&quot; data-ke-size=&quot;size16&quot;&gt;Component는 USceneComponent를 기반으로 Transform을 가질 수 있고,&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;Location
Rotation
Scale&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;10612&quot; data-start=&quot;10579&quot; data-ke-size=&quot;size16&quot;&gt;을 기준으로 서로 Attachment 관계를 만들 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;10627&quot; data-start=&quot;10614&quot; data-ke-size=&quot;size16&quot;&gt;그리고 캐릭터의 움직임은&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;Movement Component&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;10668&quot; data-start=&quot;10661&quot; data-ke-size=&quot;size16&quot;&gt;가 담당한다.&lt;/p&gt;
&lt;p data-end=&quot;10681&quot; data-start=&quot;10670&quot; data-ke-size=&quot;size16&quot;&gt;카메라를 구성할 때는&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;SpringArm
   &amp;darr;
Camera&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;10731&quot; data-start=&quot;10718&quot; data-ke-size=&quot;size16&quot;&gt;구조를 사용할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;10738&quot; data-start=&quot;10733&quot; data-ke-size=&quot;size16&quot;&gt;코드에서는&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;FVector
&amp;rarr; 위치 / 방향

FRotator
&amp;rarr; 회전값

FRotationMatrix
&amp;rarr; 회전 기준의 방향 계산

SetActorRotation()
&amp;rarr; 실제 회전 적용&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;10858&quot; data-start=&quot;10850&quot; data-ke-size=&quot;size16&quot;&gt;으로 연결된다.&lt;/p&gt;
&lt;hr data-end=&quot;10863&quot; data-start=&quot;10860&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;10877&quot; data-start=&quot;10865&quot; data-section-id=&quot;1q7hj9l&quot;&gt;  과제 / 복습&lt;/h1&gt;
&lt;p data-end=&quot;10897&quot; data-start=&quot;10879&quot; data-ke-size=&quot;size16&quot;&gt;이번 수업의 과제 및 복습 내용.&lt;/p&gt;
&lt;h3 data-end=&quot;10908&quot; data-start=&quot;10899&quot; data-section-id=&quot;qzqmca&quot; data-ke-size=&quot;size23&quot;&gt;필수 복습&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;11191&quot; data-start=&quot;10910&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;10933&quot; data-start=&quot;10910&quot; data-section-id=&quot;198kisz&quot;&gt;UPrimitiveComponent&lt;/li&gt;
&lt;li data-end=&quot;10953&quot; data-start=&quot;10934&quot; data-section-id=&quot;poih64&quot;&gt;USceneComponent&lt;/li&gt;
&lt;li data-end=&quot;10970&quot; data-start=&quot;10954&quot; data-section-id=&quot;ztnau9&quot;&gt;Root Component&lt;/li&gt;
&lt;li data-end=&quot;10993&quot; data-start=&quot;10971&quot; data-section-id=&quot;1wi5sm6&quot;&gt;Component Attachment&lt;/li&gt;
&lt;li data-end=&quot;11015&quot; data-start=&quot;10994&quot; data-section-id=&quot;1onbeon&quot;&gt;SetupAttachment()&lt;/li&gt;
&lt;li data-end=&quot;11039&quot; data-start=&quot;11016&quot; data-section-id=&quot;17hwdna&quot;&gt;AttachToComponent()&lt;/li&gt;
&lt;li data-end=&quot;11060&quot; data-start=&quot;11040&quot; data-section-id=&quot;j6m4xw&quot;&gt;Movement Component&lt;/li&gt;
&lt;li data-end=&quot;11082&quot; data-start=&quot;11061&quot; data-section-id=&quot;ff0wur&quot;&gt;Forward Declaration&lt;/li&gt;
&lt;li data-end=&quot;11089&quot; data-start=&quot;11083&quot; data-section-id=&quot;1j3wdx6&quot;&gt;IWYU&lt;/li&gt;
&lt;li data-end=&quot;11103&quot; data-start=&quot;11090&quot; data-section-id=&quot;1o65pmf&quot;&gt;Raw Pointer&lt;/li&gt;
&lt;li data-end=&quot;11118&quot; data-start=&quot;11104&quot; data-section-id=&quot;n6pme7&quot;&gt;TObjectPtr&lt;/li&gt;
&lt;li data-end=&quot;11146&quot; data-start=&quot;11119&quot; data-section-id=&quot;r5yyl&quot;&gt;TSharedPtr / TUniquePtr&lt;/li&gt;
&lt;li data-end=&quot;11158&quot; data-start=&quot;11147&quot; data-section-id=&quot;4bkat3&quot;&gt;FVector&lt;/li&gt;
&lt;li data-end=&quot;11171&quot; data-start=&quot;11159&quot; data-section-id=&quot;g4t50v&quot;&gt;FRotator&lt;/li&gt;
&lt;li data-end=&quot;11191&quot; data-start=&quot;11172&quot; data-section-id=&quot;1newrkx&quot;&gt;FRotationMatrix&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;11199&quot; data-start=&quot;11193&quot; data-section-id=&quot;1hroh7b&quot; data-ke-size=&quot;size23&quot;&gt;실습&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;11236&quot; data-start=&quot;11201&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;11217&quot; data-start=&quot;11201&quot; data-section-id=&quot;8vdh5p&quot;&gt;Player Mesh 지정&lt;/li&gt;
&lt;li data-end=&quot;11236&quot; data-start=&quot;11218&quot; data-section-id=&quot;kwkrjz&quot;&gt;Player Camera 세팅&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;11244&quot; data-start=&quot;11238&quot; data-section-id=&quot;1hrqf4y&quot; data-ke-size=&quot;size23&quot;&gt;암기&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;Unreal 기본 방향

X = Forward = 앞
Y = Right   = 오른쪽
Z = Up      = 위&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;11326&quot; data-start=&quot;11323&quot; data-ke-size=&quot;size16&quot;&gt;그리고&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;FVector  = 위치 / 방향
FRotator = 회전값&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;11392&quot; data-start=&quot;11375&quot; data-ke-size=&quot;size16&quot;&gt;이 두 가지는 확실하게 익히기.&lt;/p&gt;
&lt;hr data-end=&quot;11397&quot; data-start=&quot;11394&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;11418&quot; data-start=&quot;11399&quot; data-section-id=&quot;9xshdx&quot; data-ke-size=&quot;size26&quot;&gt;  오늘의 핵심 한 줄 정리&lt;/h2&gt;
&lt;blockquote data-end=&quot;11662&quot; data-start=&quot;11420&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;11662&quot; data-start=&quot;11422&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Actor는 Component들의 집합으로 구성되고, Root Component가 Transform의 기준이 된다. Component 간 Attachment는 C++ 상속과 다른 개념이며, Unreal에서는 UObject의 생명주기와 GC를 고려해 포인터를 사용해야 한다. 또한 FVector는 위치/방향, FRotator는 회전값을 나타내며 회전된 방향을 계산할 때 FRotationMatrix 등을 활용한다.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <author>view29579</author>
      <guid isPermaLink="true">https://view29579.tistory.com/47</guid>
      <comments>https://view29579.tistory.com/47#entry47comment</comments>
      <pubDate>Thu, 3 Sep 2026 19:59:04 +0900</pubDate>
    </item>
    <item>
      <title>Unreal C++ TIL &amp;mdash; 지뢰 피하기 게임 3-4  &amp;mdash; 캐릭터 체력 시스템 &amp;amp; 아이템 상호작용</title>
      <link>https://view29579.tistory.com/46</link>
      <description>&lt;h1 data-end=&quot;425&quot; data-start=&quot;410&quot; data-section-id=&quot;ks0sv5&quot;&gt;1. 캐릭터 체력 시스템&lt;/h1&gt;
&lt;p data-end=&quot;463&quot; data-start=&quot;427&quot; data-ke-size=&quot;size16&quot;&gt;이번에는 캐릭터에게 &lt;b&gt;최대 체력과 현재 체력&lt;/b&gt;을 만들어주었다.&lt;/p&gt;
&lt;h2 data-end=&quot;474&quot; data-start=&quot;465&quot; data-section-id=&quot;14dey8q&quot; data-ke-size=&quot;size26&quot;&gt;Header&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;// 최대 체력
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Health&quot;)
float MaxHealth;

// 현재 체력
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = &quot;Health&quot;)
float Health;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;683&quot; data-start=&quot;671&quot; data-section-id=&quot;1uf1bfx&quot; data-ke-size=&quot;size23&quot;&gt;내가 이해한 것&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;MaxHealth&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;731&quot; data-start=&quot;707&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 캐릭터가 가질 수 있는 &lt;b&gt;최대 체력&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;Health&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;778&quot; data-start=&quot;752&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 현재 캐릭터가 가지고 있는 &lt;b&gt;실제 체력&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;786&quot; data-start=&quot;780&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;MaxHealth = 100
Health = 100&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;847&quot; data-start=&quot;830&quot; data-ke-size=&quot;size16&quot;&gt;상태에서 데미지를 30 받으면:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;MaxHealth = 100
Health = 70&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;895&quot; data-start=&quot;890&quot; data-ke-size=&quot;size16&quot;&gt;이 된다.&lt;/p&gt;
&lt;hr data-end=&quot;900&quot; data-start=&quot;897&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;919&quot; data-start=&quot;902&quot; data-section-id=&quot;2xycs7&quot;&gt;2. 생성자에서 체력 초기화&lt;/h1&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;MaxHealth = 100.0f;
Health = MaxHealth;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;996&quot; data-start=&quot;973&quot; data-ke-size=&quot;size16&quot;&gt;처음에는 최대 체력을 100으로 설정하고,&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;Health = MaxHealth;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1055&quot; data-start=&quot;1030&quot; data-ke-size=&quot;size16&quot;&gt;현재 체력을 최대 체력과 동일하게 만들어준다.&lt;/p&gt;
&lt;p data-end=&quot;1059&quot; data-start=&quot;1057&quot; data-ke-size=&quot;size16&quot;&gt;즉:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;게임 시작
 &amp;darr;
MaxHealth = 100
 &amp;darr;
Health = MaxHealth
 &amp;darr;
Health = 100&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1190&quot; data-start=&quot;1137&quot; data-section-id=&quot;hetmds&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;왜 Health = 100.0f라고 직접 쓰지 않고 MaxHealth를 넣었는가?&lt;/span&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1242&quot; data-start=&quot;1192&quot; data-ke-size=&quot;size16&quot;&gt;나중에 최대 체력을 변경하더라도 현재 체력을 자동으로 최대 체력에 맞출 수 있기 때문이다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;MaxHealth = 150.0f;
Health = MaxHealth;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1317&quot; data-start=&quot;1296&quot; data-ke-size=&quot;size16&quot;&gt;로 바꾸면 현재 체력도 150이 된다.&lt;/p&gt;
&lt;hr data-end=&quot;1322&quot; data-start=&quot;1319&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;1337&quot; data-start=&quot;1324&quot; data-section-id=&quot;1iza72e&quot;&gt;3. 체력 조회 함수&lt;/h1&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;UFUNCTION(BlueprintPure, Category = &quot;Health&quot;)
int32 GetHealth() const;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1439&quot; data-start=&quot;1422&quot; data-ke-size=&quot;size16&quot;&gt;현재 체력을 가져오는 함수이다.&lt;/p&gt;
&lt;p data-end=&quot;1445&quot; data-start=&quot;1441&quot; data-ke-size=&quot;size16&quot;&gt;CPP:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;float AJunCharacter::GetHealth() const
{
    return Health;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1546&quot; data-start=&quot;1521&quot; data-ke-size=&quot;size16&quot;&gt;여기서 조금 특이했던 점은 Header에서는:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int32 GetHealth() const;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1608&quot; data-start=&quot;1585&quot; data-ke-size=&quot;size16&quot;&gt;로 되어 있었는데 실제 Health는:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;float Health;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1639&quot; data-start=&quot;1636&quot; data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;1687&quot; data-start=&quot;1641&quot; data-ke-size=&quot;size16&quot;&gt;따라서 &lt;b&gt;현재 코드에서는 반환형을 float로 맞추는 것이 더 자연스럽다.&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;float GetHealth() const;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1735&quot; data-start=&quot;1726&quot; data-ke-size=&quot;size16&quot;&gt;그리고 CPP도:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;float AJunCharacter::GetHealth() const
{
    return Health;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1822&quot; data-start=&quot;1811&quot; data-ke-size=&quot;size16&quot;&gt;로 맞추는 게 좋다.&lt;/p&gt;
&lt;h3 data-end=&quot;1843&quot; data-start=&quot;1824&quot; data-section-id=&quot;vlpkfm&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;const를 붙이는 이유&lt;/span&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1892&quot; data-start=&quot;1845&quot; data-ke-size=&quot;size16&quot;&gt;이 함수는 &lt;b&gt;현재 체력을 가져오기만 하고 캐릭터의 값을 변경하지 않기 때문&lt;/b&gt;이다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;GetHealth()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1925&quot; data-start=&quot;1918&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 읽기만 함&lt;/p&gt;
&lt;p data-end=&quot;1931&quot; data-start=&quot;1927&quot; data-ke-size=&quot;size16&quot;&gt;그래서:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;const&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1957&quot; data-start=&quot;1951&quot; data-ke-size=&quot;size16&quot;&gt;를 붙인다.&lt;/p&gt;
&lt;hr data-end=&quot;1962&quot; data-start=&quot;1959&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;1977&quot; data-start=&quot;1964&quot; data-section-id=&quot;1erpqxw&quot;&gt;4. 체력 회복 함수&lt;/h1&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;UFUNCTION(BlueprintCallable, Category = &quot;Health&quot;)
void AddHealth(float Amount);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2075&quot; data-start=&quot;2071&quot; data-ke-size=&quot;size16&quot;&gt;CPP:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;void AJunCharacter::AddHealth(float Amount)
{
    Health = FMath::Clamp(
        Health + Amount,
        0.0f,
        MaxHealth
    );

    UE_LOG(
        LogTemp,
        Log,
        TEXT(&quot;Health increased to: %f&quot;),
        Health
    );
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2357&quot; data-start=&quot;2334&quot; data-section-id=&quot;p8q2fs&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;FMath::Clamp()가 핵심&lt;/span&gt;&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;FMath::Clamp(Health + Amount, 0.0f, MaxHealth);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2425&quot; data-start=&quot;2419&quot; data-ke-size=&quot;size16&quot;&gt;의 의미는:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Health + Amount
       &amp;darr;
0보다 작으면 &amp;rarr; 0
MaxHealth보다 크면 &amp;rarr; MaxHealth
그 사이면 &amp;rarr; 계산된 값&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2531&quot; data-start=&quot;2518&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 현재 체력이:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;Health = 70&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2566&quot; data-start=&quot;2558&quot; data-ke-size=&quot;size16&quot;&gt;이고 회복량이:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;Amount = 20&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2596&quot; data-start=&quot;2593&quot; data-ke-size=&quot;size16&quot;&gt;이면:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;basic&quot;&gt;&lt;code&gt;70 + 20 = 90&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2637&quot; data-start=&quot;2624&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; Health = 90&lt;/p&gt;
&lt;p data-end=&quot;2643&quot; data-start=&quot;2639&quot; data-ke-size=&quot;size16&quot;&gt;하지만:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;Health = 90
Amount = 30&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2685&quot; data-start=&quot;2682&quot; data-ke-size=&quot;size16&quot;&gt;이면:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;basic&quot;&gt;&lt;code&gt;90 + 30 = 120&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2732&quot; data-start=&quot;2714&quot; data-ke-size=&quot;size16&quot;&gt;MaxHealth가 100이므로:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;Health = 100&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2765&quot; data-start=&quot;2760&quot; data-ke-size=&quot;size16&quot;&gt;이 된다.&lt;/p&gt;
&lt;p data-end=&quot;2803&quot; data-start=&quot;2767&quot; data-ke-size=&quot;size16&quot;&gt;즉 &lt;b&gt;체력이 최대 체력을 초과하지 않도록 방어하는 코드&lt;/b&gt;이다.&lt;/p&gt;
&lt;hr data-end=&quot;2808&quot; data-start=&quot;2805&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;2838&quot; data-start=&quot;2810&quot; data-section-id=&quot;l2ea5g&quot;&gt;&lt;span&gt;5. 데미지 처리 &amp;mdash; TakeDamage()&lt;/span&gt;&lt;/h1&gt;
&lt;p data-end=&quot;2858&quot; data-start=&quot;2840&quot; data-ke-size=&quot;size16&quot;&gt;이번에 새롭게 배운 중요한 부분.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;virtual float TakeDamage(
    float DamageAmount,
    FDamageEvent const&amp;amp; DamageEvent,
    AController* EventInstigator,
    AActor* DamageCauser
) override;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3076&quot; data-start=&quot;3030&quot; data-ke-size=&quot;size16&quot;&gt;AActor에 이미 존재하는 TakeDamage()를 &lt;b&gt;오버라이드&lt;/b&gt;했다.&lt;/p&gt;
&lt;p data-end=&quot;3085&quot; data-start=&quot;3078&quot; data-ke-size=&quot;size16&quot;&gt;즉 외부에서:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;ApplyDamage()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3157&quot; data-start=&quot;3113&quot; data-ke-size=&quot;size16&quot;&gt;등을 통해 데미지가 들어오면 캐릭터가 이 함수를 통해 데미지를 처리할 수 있다.&lt;/p&gt;
&lt;hr data-end=&quot;3162&quot; data-start=&quot;3159&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;3170&quot; data-start=&quot;3164&quot; data-section-id=&quot;1hrykcm&quot; data-ke-size=&quot;size26&quot;&gt;CPP&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;float AJunCharacter::TakeDamage(
    float DamageAmount,
    FDamageEvent const&amp;amp; DamageEvent,
    AController* EventInstigator,
    AActor* DamageCauser)
{
    float ActualDamage = Super::TakeDamage(
        DamageAmount,
        DamageEvent,
        EventInstigator,
        DamageCauser
    );

    Health = FMath::Clamp(
        Health - DamageAmount,
        0.0f,
        MaxHealth
    );

    UE_LOG(
        LogTemp,
        Warning,
        TEXT(&quot;Health decreased to: %f&quot;),
        Health
    );

    if (Health &amp;lt;= 0.0f)
    {
        OnDeath();
    }

    return ActualDamage;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;3778&quot; data-start=&quot;3772&quot; data-section-id=&quot;1hrny1e&quot; data-ke-size=&quot;size23&quot;&gt;흐름&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;외부에서 데미지 발생
        &amp;darr;
TakeDamage()
        &amp;darr;
Health - DamageAmount
        &amp;darr;
Clamp로 0~MaxHealth 제한
        &amp;darr;
Health &amp;lt;= 0 ?
   &amp;darr;             &amp;darr;
  YES            NO
   &amp;darr;              &amp;darr;
OnDeath()       계속 플레이&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;4001&quot; data-start=&quot;3998&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;4013&quot; data-start=&quot;4003&quot; data-section-id=&quot;eydv17&quot;&gt;6. 사망 처리&lt;/h1&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;virtual void OnDeath();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4055&quot; data-start=&quot;4051&quot; data-ke-size=&quot;size16&quot;&gt;CPP:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;autohotkey&quot;&gt;&lt;code&gt;void AJunCharacter::OnDeath()
{
    UE_LOG(
        LogTemp,
        Error,
        TEXT(&quot;Character is Dead!&quot;)
    );
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4226&quot; data-start=&quot;4189&quot; data-ke-size=&quot;size16&quot;&gt;현재는 실제 사망 처리가 아니라 &lt;b&gt;로그만 출력&lt;/b&gt;하도록 만들었다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;Health = 0
 &amp;darr;
OnDeath()
 &amp;darr;
&quot;Character is Dead!&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4298&quot; data-start=&quot;4289&quot; data-ke-size=&quot;size16&quot;&gt;나중에는 여기에:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4345&quot; data-start=&quot;4300&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4313&quot; data-start=&quot;4300&quot; data-section-id=&quot;3ct7mv&quot;&gt;캐릭터 Destroy&lt;/li&gt;
&lt;li data-end=&quot;4324&quot; data-start=&quot;4314&quot; data-section-id=&quot;1amfld5&quot;&gt;사망 애니메이션&lt;/li&gt;
&lt;li data-end=&quot;4339&quot; data-start=&quot;4325&quot; data-section-id=&quot;qxayqc&quot;&gt;Game Over UI&lt;/li&gt;
&lt;li data-end=&quot;4345&quot; data-start=&quot;4340&quot; data-section-id=&quot;1yt8sw&quot;&gt;리스폰&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;4358&quot; data-start=&quot;4347&quot; data-ke-size=&quot;size16&quot;&gt;등을 넣을 수 있다.&lt;/p&gt;
&lt;hr data-end=&quot;4363&quot; data-start=&quot;4360&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;4401&quot; data-start=&quot;4365&quot; data-section-id=&quot;ivcw8m&quot;&gt;7. HealingItem &amp;mdash; 아이템이 플레이어의 체력을 회복&lt;/h1&gt;
&lt;p data-end=&quot;4442&quot; data-start=&quot;4403&quot; data-ke-size=&quot;size16&quot;&gt;HealingItem에서는 아이템이 플레이어와 상호작용하도록 만들었다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;void AHealingItem::ActivateItem(AActor* Activator)
{
    if (Activator &amp;amp;&amp;amp; Activator-&amp;gt;ActorHasTag(&quot;Player&quot;))
    {
        if (AJunCharacter* PlayerCharacter =
            Cast&amp;lt;AJunCharacter&amp;gt;(Activator))
        {
            PlayerCharacter-&amp;gt;AddHealth(HealAmount);
        }

        DestroyItem();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;4768&quot; data-start=&quot;4763&quot; data-section-id=&quot;1m91o1&quot; data-ke-size=&quot;size26&quot;&gt;흐름&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;플레이어가 아이템과 충돌
        &amp;darr;
ActivateItem()
        &amp;darr;
Activator가 존재하는가?
        &amp;darr;
Player 태그가 있는가?
        &amp;darr;
JunCharacter로 Cast 가능한가?
        &amp;darr;
AddHealth()
        &amp;darr;
체력 회복
        &amp;darr;
DestroyItem()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5021&quot; data-start=&quot;4973&quot; data-ke-size=&quot;size16&quot;&gt;여기서 중요한 것은 &lt;b&gt;아이템이 직접 Health 변수에 접근하지 않는다는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;PlayerCharacter-&amp;gt;AddHealth(HealAmount);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5087&quot; data-start=&quot;5075&quot; data-ke-size=&quot;size16&quot;&gt;라는 함수를 호출한다.&lt;/p&gt;
&lt;p data-end=&quot;5091&quot; data-start=&quot;5089&quot; data-ke-size=&quot;size16&quot;&gt;즉:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;HealingItem
     &amp;darr;
AddHealth()
     &amp;darr;
Character가 자기 Health를 변경&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5178&quot; data-start=&quot;5169&quot; data-ke-size=&quot;size16&quot;&gt;이 구조가 된다.&lt;/p&gt;
&lt;hr data-end=&quot;5183&quot; data-start=&quot;5180&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;5221&quot; data-start=&quot;5185&quot; data-section-id=&quot;1ogaiay&quot;&gt;8. CoinItem &amp;mdash; 아이템과 GameState의 상호작용&lt;/h1&gt;
&lt;p data-end=&quot;5275&quot; data-start=&quot;5223&quot; data-ke-size=&quot;size16&quot;&gt;CoinItem에서는 플레이어가 코인을 획득했을 때 &lt;b&gt;점수를 증가시키는 구조&lt;/b&gt;를 만들었다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;if (Activator &amp;amp;&amp;amp; Activator-&amp;gt;ActorHasTag(&quot;Player&quot;))
{
    if (UWorld* World = GetWorld())
    {
        if (ASpartaGameStateBase* GameState =
            World-&amp;gt;GetGameState&amp;lt;ASpartaGameStateBase&amp;gt;())
        {
            GameState-&amp;gt;AddScore(PointValue);
        }
    }

    DestroyItem();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5584&quot; data-start=&quot;5580&quot; data-ke-size=&quot;size16&quot;&gt;흐름은:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;플레이어가 코인 획득
        &amp;darr;
Player 태그 확인
        &amp;darr;
World 가져오기
        &amp;darr;
GameState 가져오기
        &amp;darr;
AddScore(PointValue)
        &amp;darr;
점수 증가
        &amp;darr;
코인 Destroy&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;5768&quot; data-start=&quot;5748&quot; data-section-id=&quot;19j504y&quot; data-ke-size=&quot;size23&quot;&gt;그런데 여기서 트러블슈팅 발생&lt;/h3&gt;
&lt;p data-end=&quot;5782&quot; data-start=&quot;5770&quot; data-ke-size=&quot;size16&quot;&gt;현재 내 프로젝트에는:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;SpartaGameStateBase.h&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5829&quot; data-start=&quot;5818&quot; data-ke-size=&quot;size16&quot;&gt;가 존재하지 않았다.&lt;/p&gt;
&lt;p data-end=&quot;5835&quot; data-start=&quot;5831&quot; data-ke-size=&quot;size16&quot;&gt;그래서:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;C1083
Cannot open include file:
'SpartaGameStateBase.h'&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5915&quot; data-start=&quot;5906&quot; data-ke-size=&quot;size16&quot;&gt;에러가 발생했다.&lt;/p&gt;
&lt;p data-end=&quot;5966&quot; data-start=&quot;5917&quot; data-ke-size=&quot;size16&quot;&gt;강의 프로젝트에서 사용하는 클래스 이름을 &lt;b&gt;내 프로젝트에 그대로 가져왔기 때문&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;6010&quot; data-start=&quot;5968&quot; data-ke-size=&quot;size16&quot;&gt;현재 아직 GameState를 구현하지 않았다면 해당 부분을 잠시 제외하고:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;if (Activator &amp;amp;&amp;amp; Activator-&amp;gt;ActorHasTag(&quot;Player&quot;))
{
    DestroyItem();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;6124&quot; data-start=&quot;6098&quot; data-ke-size=&quot;size16&quot;&gt;정도로 아이템 획득/삭제까지만 구현할 수 있다.&lt;/p&gt;
&lt;hr data-end=&quot;6129&quot; data-start=&quot;6126&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;6165&quot; data-start=&quot;6131&quot; data-section-id=&quot;cf6507&quot;&gt;9. MineItem &amp;mdash; 플레이어에게 데미지를 주는 아이템&lt;/h1&gt;
&lt;p data-end=&quot;6188&quot; data-start=&quot;6167&quot; data-ke-size=&quot;size16&quot;&gt;지뢰는 HealingItem과 반대다.&lt;/p&gt;
&lt;p data-end=&quot;6202&quot; data-start=&quot;6190&quot; data-ke-size=&quot;size16&quot;&gt;HealingItem:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;아이템 &amp;rarr; Player &amp;rarr; AddHealth()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;6253&quot; data-start=&quot;6244&quot; data-ke-size=&quot;size16&quot;&gt;MineItem:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;아이템 &amp;rarr; Player &amp;rarr; TakeDamage()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;6327&quot; data-start=&quot;6296&quot; data-ke-size=&quot;size16&quot;&gt;지뢰의 핵심은 &lt;b&gt;Timer를 이용한 지연 폭발&lt;/b&gt;이다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;ExplosionDelay = 5.0f;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;6368&quot; data-start=&quot;6364&quot; data-ke-size=&quot;size16&quot;&gt;그리고:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;autohotkey&quot;&gt;&lt;code&gt;GetWorld()-&amp;gt;GetTimerManager().SetTimer(
    ExplosionTimerHandle,
    this,
    &amp;amp;AMineItem::Explode,
    ExplosionDelay,
    false
);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;6522&quot; data-start=&quot;6516&quot; data-ke-size=&quot;size16&quot;&gt;이 코드는:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;5초 후 Explode() 실행&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;6563&quot; data-start=&quot;6555&quot; data-ke-size=&quot;size16&quot;&gt;이라는 뜻이다.&lt;/p&gt;
&lt;p data-end=&quot;6568&quot; data-start=&quot;6565&quot; data-ke-size=&quot;size16&quot;&gt;특히:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;false&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;6618&quot; data-start=&quot;6588&quot; data-ke-size=&quot;size16&quot;&gt;이므로 반복 타이머가 아니라 &lt;b&gt;한 번만 실행&lt;/b&gt;된다.&lt;/p&gt;
&lt;hr data-end=&quot;6623&quot; data-start=&quot;6620&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;6654&quot; data-start=&quot;6625&quot; data-section-id=&quot;1fc2amc&quot;&gt;&lt;span&gt;10. 지뢰 폭발 &amp;rarr; ApplyDamage()&lt;/span&gt;&lt;/h1&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;autohotkey&quot;&gt;&lt;code&gt;UGameplayStatics::ApplyDamage(
    Actor,
    ExplosionDamage,
    nullptr,
    this,
    UDamageType::StaticClass()
);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;6827&quot; data-start=&quot;6788&quot; data-ke-size=&quot;size16&quot;&gt;이 부분이 오늘 배운 &lt;b&gt;아이템 &amp;rarr; 캐릭터 데미지 전달&lt;/b&gt;의 핵심이다.&lt;/p&gt;
&lt;p data-end=&quot;6836&quot; data-start=&quot;6829&quot; data-ke-size=&quot;size16&quot;&gt;지뢰가 직접:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;Health -= 30;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;6874&quot; data-start=&quot;6864&quot; data-ke-size=&quot;size16&quot;&gt;하는 것이 아니다.&lt;/p&gt;
&lt;p data-end=&quot;6879&quot; data-start=&quot;6876&quot; data-ke-size=&quot;size16&quot;&gt;대신:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;MineItem
   &amp;darr;
ApplyDamage()
   &amp;darr;
Player의 TakeDamage()
   &amp;darr;
Health 감소
   &amp;darr;
Health &amp;lt;= 0 ?
   &amp;darr;
OnDeath()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;7008&quot; data-start=&quot;6997&quot; data-ke-size=&quot;size16&quot;&gt;라는 구조를 만든다.&lt;/p&gt;
&lt;p data-end=&quot;7052&quot; data-start=&quot;7010&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 하면 &lt;b&gt;데미지를 주는 쪽과 데미지를 받는 쪽을 분리할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;7057&quot; data-start=&quot;7054&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;7078&quot; data-start=&quot;7059&quot; data-section-id=&quot;yp6dsc&quot;&gt;11. 아이템 시스템 전체 구조&lt;/h1&gt;
&lt;p data-end=&quot;7105&quot; data-start=&quot;7080&quot; data-ke-size=&quot;size16&quot;&gt;오늘 배운 내용을 연결하면 이런 구조가 된다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;                    ┌──────────────┐
                    │   Player     │
                    │ JunCharacter │
                    └──────┬───────┘
                           │
                아이템과 상호작용
                           │
             ┌─────────────┼─────────────┐
             &amp;darr;             &amp;darr;             &amp;darr;
       HealingItem      CoinItem       MineItem
             │             │             │
             &amp;darr;             &amp;darr;             &amp;darr;
        AddHealth()     AddScore()   ApplyDamage()
             │             │             │
             &amp;darr;             &amp;darr;             &amp;darr;
          Health         Score       TakeDamage()
                                         │
                                         &amp;darr;
                                      Health 감소
                                         │
                                         &amp;darr;
                                      OnDeath()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;8067&quot; data-start=&quot;8027&quot; data-ke-size=&quot;size16&quot;&gt;이 구조가 오늘 배운 것 중에서 &lt;b&gt;가장 중요한 부분&lt;/b&gt;이라고 생각한다.&lt;/p&gt;
&lt;hr data-end=&quot;8072&quot; data-start=&quot;8069&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;8092&quot; data-start=&quot;8074&quot; data-section-id=&quot;8o9ng8&quot;&gt;12. 오늘의 트러블슈팅  &lt;/h1&gt;
&lt;h2 data-end=&quot;8106&quot; data-start=&quot;8094&quot; data-section-id=&quot;yrf8ps&quot; data-ke-size=&quot;size26&quot;&gt;① 유니코드 지옥&lt;/h2&gt;
&lt;p data-end=&quot;8122&quot; data-start=&quot;8108&quot; data-ke-size=&quot;size16&quot;&gt;코드를 복사하는 과정에서:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;-&amp;gt;   &amp;rarr; 
=    
(    
)    
&amp;lt;    &lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;8190&quot; data-start=&quot;8173&quot; data-ke-size=&quot;size16&quot;&gt;등으로 깨지는 현상이 발생했다.&lt;/p&gt;
&lt;p data-end=&quot;8198&quot; data-start=&quot;8192&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;ExplosionCollision&amp;rarr;SetupAttachment(Scene);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;8265&quot; data-start=&quot;8255&quot; data-ke-size=&quot;size16&quot;&gt;정상적인 C++는:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;ExplosionCollision-&amp;gt;SetupAttachment(Scene);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;8326&quot; data-start=&quot;8323&quot; data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;h3 data-end=&quot;8334&quot; data-start=&quot;8328&quot; data-section-id=&quot;1hrnhqa&quot; data-ke-size=&quot;size23&quot;&gt;해결&lt;/h3&gt;
&lt;p data-end=&quot;8377&quot; data-start=&quot;8336&quot; data-ke-size=&quot;size16&quot;&gt;깨진 코드를 그대로 사용하지 않고 &lt;b&gt;정상적인 C++ 기호로 복구&lt;/b&gt;했다.&lt;/p&gt;
&lt;hr data-end=&quot;8382&quot; data-start=&quot;8379&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;8417&quot; data-start=&quot;8384&quot; data-section-id=&quot;13ydp95&quot;&gt;&lt;span&gt;13. MineItem.h와 .cpp가 섞인 문제&lt;/span&gt;&lt;/h1&gt;
&lt;p data-end=&quot;8437&quot; data-start=&quot;8419&quot; data-ke-size=&quot;size16&quot;&gt;오늘 가장 중요한 실수 중 하나.&lt;/p&gt;
&lt;p data-end=&quot;8460&quot; data-start=&quot;8439&quot; data-ke-size=&quot;size16&quot;&gt;MineItem.h에 있어야 하는:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;UCLASS()

class AMineItem : public ABaseItem
{
    GENERATED_BODY()
    
    ...
};&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;8568&quot; data-start=&quot;8558&quot; data-ke-size=&quot;size16&quot;&gt;가 사라지고 대신:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;AMineItem::AMineItem()
{
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;8643&quot; data-start=&quot;8617&quot; data-ke-size=&quot;size16&quot;&gt;같은 &lt;b&gt;CPP 구현 코드가 들어가 있었다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;8649&quot; data-start=&quot;8645&quot; data-ke-size=&quot;size16&quot;&gt;그래서:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;1c&quot;&gt;&lt;code&gt;&quot;어? 왜 MineItem.h에 UCLASS가 없지?&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;8711&quot; data-start=&quot;8695&quot; data-ke-size=&quot;size16&quot;&gt;라는 이상한 상황이 발생했다.&lt;/p&gt;
&lt;h3 data-end=&quot;8722&quot; data-start=&quot;8713&quot; data-section-id=&quot;ij30em&quot; data-ke-size=&quot;size23&quot;&gt;정상 구조&lt;/h3&gt;
&lt;p data-end=&quot;8738&quot; data-start=&quot;8724&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MineItem.h&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;클래스 선언
UPROPERTY
UFUNCTION
함수 원형&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;8802&quot; data-start=&quot;8786&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MineItem.cpp&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;생성자 구현
함수 구현
실제 로직&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;8839&quot; data-start=&quot;8836&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;8863&quot; data-start=&quot;8841&quot; data-section-id=&quot;mpi1a0&quot;&gt;&lt;span&gt;14. generated.h 에러&lt;/span&gt;&lt;/h1&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;C1083
Cannot open include file:
'MineItem.generated.h'&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;8975&quot; data-start=&quot;8933&quot; data-ke-size=&quot;size16&quot;&gt;이 에러도 처음에는 generated.h 파일 자체가 문제인 것처럼 보였다.&lt;/p&gt;
&lt;p data-end=&quot;9089&quot; data-start=&quot;8977&quot; data-ke-size=&quot;size16&quot;&gt;하지만 generated.h는 내가 직접 만드는 파일이 아니라 &lt;b&gt;UnrealHeaderTool이 UCLASS, UPROPERTY, UFUNCTION 등을 기반으로 생성하는 파일&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;9095&quot; data-start=&quot;9091&quot; data-ke-size=&quot;size16&quot;&gt;따라서:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;autoit&quot;&gt;&lt;code&gt;#include &quot;MineItem.generated.h&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;9156&quot; data-start=&quot;9141&quot; data-ke-size=&quot;size16&quot;&gt;자체가 잘못된 것이 아니라,&lt;/p&gt;
&lt;p data-end=&quot;9212&quot; data-start=&quot;9158&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그 전에 헤더 구조가 깨져서 UHT가 정상적으로 처리하지 못했을 가능성&lt;/b&gt;을 먼저 봐야 한다.&lt;/p&gt;
&lt;p data-end=&quot;9258&quot; data-start=&quot;9214&quot; data-ke-size=&quot;size16&quot;&gt;그리고 .generated.h는 헤더의 &lt;b&gt;마지막 include&lt;/b&gt;로 둔다.&lt;/p&gt;
&lt;hr data-end=&quot;9263&quot; data-start=&quot;9260&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;9301&quot; data-start=&quot;9265&quot; data-section-id=&quot;1h5lrfx&quot;&gt;&lt;span&gt;15. C1014 too many include files&lt;/span&gt;&lt;/h1&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;C1014
too many include files: depth = 1024&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;9370&quot; data-start=&quot;9359&quot; data-ke-size=&quot;size16&quot;&gt;이 에러도 발생했다.&lt;/p&gt;
&lt;p data-end=&quot;9423&quot; data-start=&quot;9372&quot; data-ke-size=&quot;size16&quot;&gt;이는 헤더가 서로 무한히 include되는 &lt;b&gt;순환 참조&lt;/b&gt;가 발생했을 때 나타날 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;9427&quot; data-start=&quot;9425&quot; data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;MineItem.h
 &amp;darr;
BaseItem.h
 &amp;darr;
MineItem.h
 &amp;darr;
BaseItem.h
 &amp;darr;
...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;9506&quot; data-start=&quot;9502&quot; data-ke-size=&quot;size16&quot;&gt;따라서:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;autoit&quot;&gt;&lt;code&gt;MineItem.cpp
#include &quot;MineItem.h&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;9570&quot; data-start=&quot;9555&quot; data-ke-size=&quot;size16&quot;&gt;자체가 문제인 것이 아니라,&lt;/p&gt;
&lt;p data-end=&quot;9609&quot; data-start=&quot;9572&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;헤더끼리 서로 물고 있는 구조가 문제&lt;/b&gt;라는 것을 알게 되었다.&lt;/p&gt;
&lt;hr data-end=&quot;9614&quot; data-start=&quot;9611&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;9633&quot; data-start=&quot;9616&quot; data-section-id=&quot;8t2vw7&quot;&gt;16. 오늘 배운 핵심 정리&lt;/h1&gt;
&lt;h3 data-end=&quot;9641&quot; data-start=&quot;9635&quot; data-section-id=&quot;1hrpvfb&quot; data-ke-size=&quot;size23&quot;&gt;체력&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;MaxHealth&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;9672&quot; data-start=&quot;9665&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 최대 체력&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;Health&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;9700&quot; data-start=&quot;9693&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 현재 체력&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;AddHealth()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;9733&quot; data-start=&quot;9726&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 체력 회복&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;TakeDamage()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;9768&quot; data-start=&quot;9760&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 데미지 처리&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;OnDeath()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;9812&quot; data-start=&quot;9792&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 체력이 0이 되었을 때 사망 처리&lt;/p&gt;
&lt;hr data-end=&quot;9817&quot; data-start=&quot;9814&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;9831&quot; data-start=&quot;9819&quot; data-section-id=&quot;splbd7&quot; data-ke-size=&quot;size23&quot;&gt;아이템 상호작용&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;HealingItem
&amp;rarr; AddHealth()
&amp;rarr; 체력 증가&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;MineItem
&amp;rarr; ApplyDamage()
&amp;rarr; TakeDamage()
&amp;rarr; 체력 감소&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;CoinItem
&amp;rarr; GameState
&amp;rarr; AddScore()
&amp;rarr; 점수 증가&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;9999&quot; data-start=&quot;9996&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;10024&quot; data-start=&quot;10001&quot; data-section-id=&quot;1ypi1fx&quot; data-ke-size=&quot;size23&quot;&gt;Unreal C++에서 중요한 구조&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;.h
&amp;rarr; 무엇이 존재하는지 선언

.cpp
&amp;rarr; 실제로 어떻게 동작하는지 구현&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;10086&quot; data-start=&quot;10082&quot; data-ke-size=&quot;size16&quot;&gt;그리고:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;autoit&quot;&gt;&lt;code&gt;#include &quot;MineItem.generated.h&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;10189&quot; data-start=&quot;10132&quot; data-ke-size=&quot;size16&quot;&gt;은 직접 만드는 파일이 아니라 &lt;b&gt;UHT가 생성하는 파일&lt;/b&gt;이며, 반드시! 헤더의 마지막 include로 둔다.&lt;/p&gt;
&lt;hr data-end=&quot;10194&quot; data-start=&quot;10191&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;10211&quot; data-start=&quot;10196&quot; data-section-id=&quot;4swrw6&quot;&gt;  오늘의 한 줄 회고&lt;/h1&gt;
&lt;blockquote data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;10567&quot; data-start=&quot;10213&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-is-last-node=&quot;&quot; data-end=&quot;10567&quot; data-start=&quot;10215&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;오늘은 단순히 체력과 아이템 기능을 구현한 것뿐만 아니라, HealingItem &amp;rarr; AddHealth(), MineItem &amp;rarr; ApplyDamage() &amp;rarr; TakeDamage(), CoinItem &amp;rarr; GameState &amp;rarr; AddScore()처럼 &quot;아이템이 플레이어의 데이터를 직접 건드리는 것이 아니라 적절한 함수를 통해 상호작용한다&quot;는 구조를 이해했다. 또한 유니코드 깨짐, .h/.cpp 혼동, generated.h 생성 문제 등의 트러블슈팅을 통해 Unreal C++에서 파일 구조와 프로젝트 클래스 관계가 얼마나 중요한지도 경험했다.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <author>view29579</author>
      <guid isPermaLink="true">https://view29579.tistory.com/46</guid>
      <comments>https://view29579.tistory.com/46#entry46comment</comments>
      <pubDate>Mon, 24 Aug 2026 20:54:48 +0900</pubDate>
    </item>
    <item>
      <title>Unreal C++ TIL &amp;mdash; 지뢰 피하기 게임 3-3 (DataTable과 랜덤 아이템 스폰 시스템 구현)</title>
      <link>https://view29579.tistory.com/45</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;1. 오늘 학습한 내용&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;오늘은 기존에 구현했던 아이템 시스템에서 한 단계 더 나아가 &lt;/span&gt;&lt;b&gt;&lt;span&gt;DataTable을 이용한 아이템 데이터 관리와 랜덤 스폰 시스템&lt;/span&gt;&lt;/b&gt;&lt;span&gt;을 구현해보았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번 작업에서는 크게 다음 내용을 다뤘다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;FTableRowBase&lt;/span&gt;&lt;span&gt;를 상속받은 아이템 데이터 구조체 생성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;USTRUCT(BlueprintType)&lt;/span&gt;&lt;span&gt;를 이용한 구조체의 언리얼 엔진 및 블루프린트 인식&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;TSubclassOf&amp;lt;AActor&amp;gt;&lt;/span&gt;&lt;span&gt;를 이용한 아이템 클래스 지정&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;UBoxComponent&lt;/span&gt;&lt;span&gt;를 이용한 스폰 영역 설정&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;스폰 영역 내부의 랜덤 좌표 계산&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;SpawnActor()&lt;/span&gt;&lt;span&gt;를 이용한 액터 생성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;DataTable을 이용한 아이템 데이터 관리&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;2. ItemSpawnRow 구조체&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;먼저 DataTable의 한 행에 들어갈 데이터를 정의하기 위해 &lt;/span&gt;&lt;span&gt;FItemSpawnRow&lt;/span&gt;&lt;span&gt; 구조체를 만들었다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;USTRUCT(BlueprintType)
struct FItemSpawnRow : public FTableRowBase
{
    GENERATED_BODY()

public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    FName ItemName;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    TSubclassOf&amp;lt;AActor&amp;gt; ItemClass;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    float SpawnChance;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;FTableRowBase&lt;/span&gt;&lt;span&gt;를 상속받음으로써 이 구조체를 &lt;/span&gt;&lt;b&gt;&lt;span&gt;DataTable의 Row 데이터로 사용할 수 있게 된다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;한 행에는 다음과 같은 정보가 들어간다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;ItemName
ItemClass
SpawnChance&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉, 아이템 하나에 대한 데이터를 하나의 행으로 관리할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어 DataTable에서 다음과 같이 관리할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Coin    &amp;rarr; BP_Coin    &amp;rarr; 50
Potion  &amp;rarr; BP_Potion  &amp;rarr; 30
Mine    &amp;rarr; BP_Mine    &amp;rarr; 20&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게 하면 아이템의 종류나 스폰 확률 같은 데이터를 코드에 직접 하나하나 작성하지 않고 &lt;/span&gt;&lt;b&gt;&lt;span&gt;DataTable에서 관리할 수 있다는 점&lt;/span&gt;&lt;/b&gt;&lt;span&gt;을 배웠다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;3. TSubclassOf에 대한 이해&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번에 &lt;/span&gt;&lt;span&gt;TSubclassOf&amp;lt;AActor&amp;gt;&lt;/span&gt;&lt;span&gt;도 다시 사용해보았다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;TSubclassOf&amp;lt;AActor&amp;gt; ItemClass;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이것은 아무 객체나 넣는 것이 아니라 &lt;/span&gt;&lt;b&gt;&lt;span&gt;AActor를 상속받은 클래스만 지정할 수 있도록 제한하는 역할&lt;/span&gt;&lt;/b&gt;&lt;span&gt;을 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 DataTable에서 아이템의 실제 클래스를 선택할 수 있고, 이후 &lt;/span&gt;&lt;span&gt;SpawnActor()&lt;/span&gt;&lt;span&gt;에 전달하여 실제 액터를 생성할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또한 &lt;/span&gt;&lt;span&gt;TSubclassOf&lt;/span&gt;&lt;span&gt;와 &lt;/span&gt;&lt;span&gt;TSoftClassPtr&lt;/span&gt;&lt;span&gt;의 차이도 함께 학습했다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;TSubclassOf&lt;/span&gt;&lt;span&gt; &amp;rarr; 사용할 클래스를 직접 참조&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;TSoftClassPtr&lt;/span&gt;&lt;span&gt; &amp;rarr; 클래스의 경로를 이용하는 소프트 참조&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번 시스템에서는 실제로 스폰할 아이템 클래스를 지정해야 하기 때문에 &lt;/span&gt;&lt;span&gt;TSubclassOf&lt;/span&gt;&lt;span&gt;를 사용했다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;4. SpawnVolume 구현&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;아이템이 생성될 영역을 만들기 위해 &lt;/span&gt;&lt;span&gt;ASpawnVolume&lt;/span&gt;&lt;span&gt;을 구현했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;USceneComponent* Scene;
UBoxComponent* SpawningBox;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Scene&lt;/span&gt;&lt;span&gt;을 루트 컴포넌트로 만들고 &lt;/span&gt;&lt;span&gt;SpawningBox&lt;/span&gt;&lt;span&gt;를 그 하위에 붙였다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;Scene
└── SpawningBox&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게 함으로써 Box 영역을 기준으로 아이템을 스폰할 수 있도록 만들었다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;5. 스폰 영역 안에서 랜덤 좌표 만들기&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;가장 재미있었던 부분 중 하나는 스폰 영역 안에서 랜덤한 위치를 계산하는 것이었다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;FVector BoxExtent = SpawningBox-&amp;gt;GetScaledBoxExtent();
FVector BoxOrigin = SpawningBox-&amp;gt;GetComponentLocation();

return BoxOrigin + FVector(
    FMath::FRandRange(-BoxExtent.X, BoxExtent.X),
    FMath::FRandRange(-BoxExtent.Y, BoxExtent.Y),
    FMath::FRandRange(-BoxExtent.Z, BoxExtent.Z)
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;GetScaledBoxExtent()&lt;/span&gt;&lt;span&gt;를 이용하여 Box의 현재 스케일이 적용된 크기를 얻고, &lt;/span&gt;&lt;span&gt;GetComponentLocation()&lt;/span&gt;&lt;span&gt;을 통해 Box의 중심 위치를 가져온다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그 다음 각 축마다&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;arcade&quot;&gt;&lt;code&gt;-Extent ~ +Extent&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;범위에서 랜덤한 값을 생성하여 중심 위치에 더한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;결과적으로 Box 내부의 임의의 위치가 만들어진다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;        Box
┌─────────────────┐
│      &amp;bull;          │
│   &amp;bull;        &amp;bull;    │
│        &amp;bull;        │
│ &amp;bull;            &amp;bull;  │
└─────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 과정을 통해 아이템이 매번 같은 위치가 아니라 &lt;/span&gt;&lt;b&gt;&lt;span&gt;스폰 영역 내부의 랜덤한 위치에 생성될 수 있게 된다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;6. SpawnActor를 이용한 실제 아이템 생성&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;랜덤 위치를 구한 뒤에는 &lt;/span&gt;&lt;span&gt;SpawnActor()&lt;/span&gt;&lt;span&gt;를 이용해 실제 아이템을 생성했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;GetWorld()-&amp;gt;SpawnActor&amp;lt;AActor&amp;gt;(
    ItemClass,
    GetRandomPointInVolume(),
    FRotator::ZeroRotator
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 각각의 인자를 구분해서 이해했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;ItemClass
&amp;rarr; 무엇을 생성할 것인가?

GetRandomPointInVolume()
&amp;rarr; 어디에 생성할 것인가?

FRotator::ZeroRotator
&amp;rarr; 어떤 회전으로 생성할 것인가?&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;아이템의 종류 + 랜덤 위치 + 기본 회전값&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;을 조합해서 실제 월드에 아이템을 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot;&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;7. 오늘 느낀 점&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;오늘은 특별히 큰 트러블슈팅이 발생하지는 않았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;대신 오늘 작업을 하면서 이전과는 조금 다른 느낌을 받았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;지금까지는 주로 캐릭터를 만들고 움직이게 하거나, 컴포넌트를 붙이고 애니메이션을 적용하는 등 &lt;/span&gt;&lt;b&gt;&lt;span&gt;게임의 기능을 직접 구현하는 과정&lt;/span&gt;&lt;/b&gt;&lt;span&gt;에 집중했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그런데 이번에 DataTable과 랜덤 스폰 시스템을 만들어보면서 처음으로 &lt;/span&gt;&lt;b&gt;&lt;span&gt;&quot;게임이 실제로 데이터를 이용해서 돌아간다&quot;​&lt;/span&gt;&lt;/b&gt;&lt;span&gt;는 느낌이 강하게 들었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;특히 DataTable에 아이템의 이름, 클래스, 스폰 확률을 넣고 그것을 코드에서 가져와 실제 월드에 아이템으로 생성하는 과정을 보면서 게임의 시스템이 조금씩 연결되고 있다는 느낌을 받았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그리고 DataTable은 게임의 기획자가 데이터를 관리할 때도 활용할 수 있다는 점이 흥미로웠다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;코드를 직접 수정하지 않고 DataTable의 값을 변경하는 것만으로 아이템의 종류나 스폰 확률 등을 조정할 수 있기 때문에, 프로그래머와 기획자가 역할을 나누어 작업하는 게임 개발 과정도 조금은 이해할 수 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;무엇보다 지금까지의 실습은 &quot;기능을 하나 구현했다&quot;는 느낌이 강했다면, 오늘은 &lt;/span&gt;&lt;b&gt;&lt;span&gt;&quot;게임을 구성하는 시스템 하나를 만들었다&quot;​&lt;/span&gt;&lt;/b&gt;&lt;span&gt;는 느낌이 들어서 재미있었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞으로 아이템 종류가 늘어나고 스폰 규칙이나 확률까지 연결된다면 DataTable을 활용하는 이유를 더 확실하게 이해할 수 있을 것 같다.&lt;/span&gt;&lt;/p&gt;</description>
      <author>view29579</author>
      <guid isPermaLink="true">https://view29579.tistory.com/45</guid>
      <comments>https://view29579.tistory.com/45#entry45comment</comments>
      <pubDate>Fri, 21 Aug 2026 23:20:30 +0900</pubDate>
    </item>
    <item>
      <title>Unreal C++ TIL &amp;mdash; 지뢰 피하기 게임 3-2 (아이템 상속 구조와 virtual / override)</title>
      <link>https://view29579.tistory.com/44</link>
      <description>&lt;p data-end=&quot;211&quot; data-start=&quot;191&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Date: 2026.08.20&lt;/b&gt;&lt;/p&gt;
&lt;h2 data-end=&quot;223&quot; data-start=&quot;213&quot; data-section-id=&quot;m06sam&quot; data-ke-size=&quot;size26&quot;&gt;오늘 배운 것&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;496&quot; data-start=&quot;225&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;257&quot; data-start=&quot;225&quot; data-section-id=&quot;hcd6gy&quot;&gt;Unreal C++에서 아이템 클래스의 상속 구조 구현&lt;/li&gt;
&lt;li data-end=&quot;296&quot; data-start=&quot;258&quot; data-section-id=&quot;1av95o4&quot;&gt;ActorHasTag(&quot;Player&quot;)를 이용한 플레이어 판별&lt;/li&gt;
&lt;li data-end=&quot;344&quot; data-start=&quot;297&quot; data-section-id=&quot;1txaaod&quot;&gt;GEngine-&amp;gt;AddOnScreenDebugMessage()를 이용한 디버깅&lt;/li&gt;
&lt;li data-end=&quot;379&quot; data-start=&quot;345&quot; data-section-id=&quot;1ictld6&quot;&gt;부모 클래스의 함수를 자식 클래스가 상속받아 사용하는 과정&lt;/li&gt;
&lt;li data-end=&quot;407&quot; data-start=&quot;380&quot; data-section-id=&quot;mqctr1&quot;&gt;virtual과 override의 관계&lt;/li&gt;
&lt;li data-end=&quot;448&quot; data-start=&quot;408&quot; data-section-id=&quot;1rhxzj2&quot;&gt;자식 클래스에서 함수를 재정의하면 부모의 기능이 가려질 수 있다는 것&lt;/li&gt;
&lt;li data-end=&quot;496&quot; data-start=&quot;449&quot; data-section-id=&quot;1a02ugr&quot;&gt;공통 기능은 부모 클래스에 작성하고, 자식 클래스에서는 필요한 값만 변경하는 구조&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;501&quot; data-start=&quot;498&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;525&quot; data-start=&quot;503&quot; data-section-id=&quot;3narnh&quot;&gt;1. 아이템 클래스의 기본 상속 구조&lt;/h1&gt;
&lt;p data-end=&quot;548&quot; data-start=&quot;527&quot; data-ke-size=&quot;size16&quot;&gt;오늘 만든 아이템 구조는 다음과 같다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:0:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;ABaseItem &lt;br /&gt;│ &lt;br /&gt;├──&amp;nbsp;AMineItem &lt;br /&gt;│ &lt;br /&gt;├──&amp;nbsp;AHealingItem &lt;br /&gt;│ &lt;br /&gt;└──&amp;nbsp;ACoinItem &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;│ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;├──&amp;nbsp;ABigCoinItem &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;│ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;└──&amp;nbsp;ASmallCoinItem&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;713&quot; data-start=&quot;684&quot; data-ke-size=&quot;size16&quot;&gt;BaseItem을 가장 상위 부모 클래스로 두고,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;733&quot; data-start=&quot;715&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;719&quot; data-start=&quot;715&quot; data-section-id=&quot;yik9nc&quot;&gt;지뢰&lt;/li&gt;
&lt;li data-end=&quot;728&quot; data-start=&quot;720&quot; data-section-id=&quot;hj46fx&quot;&gt;회복 아이템&lt;/li&gt;
&lt;li data-end=&quot;733&quot; data-start=&quot;729&quot; data-section-id=&quot;yijz7o&quot;&gt;코인&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;753&quot; data-start=&quot;735&quot; data-ke-size=&quot;size16&quot;&gt;을 각각 자식 클래스로 만들었다.&lt;/p&gt;
&lt;p data-end=&quot;766&quot; data-start=&quot;755&quot; data-ke-size=&quot;size16&quot;&gt;그리고 코인은 다시:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;789&quot; data-start=&quot;768&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;777&quot; data-start=&quot;768&quot; data-section-id=&quot;pvndrj&quot;&gt;BigCoin&lt;/li&gt;
&lt;li data-end=&quot;789&quot; data-start=&quot;778&quot; data-section-id=&quot;zwfbzw&quot;&gt;SmallCoin&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;806&quot; data-start=&quot;791&quot; data-ke-size=&quot;size16&quot;&gt;으로 한 단계 더 상속했다.&lt;/p&gt;
&lt;hr data-end=&quot;811&quot; data-start=&quot;808&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;832&quot; data-start=&quot;813&quot; data-section-id=&quot;1psw6av&quot;&gt;2. HealingItem 구현&lt;/h1&gt;
&lt;p data-end=&quot;883&quot; data-start=&quot;834&quot; data-ke-size=&quot;size16&quot;&gt;AHealingItem에는 회복량을 저장할 변수로 HealAmount를 만들었다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:1:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot; data-language=&quot;cpp&quot;&gt;
&lt;div&gt;UPROPERTY(&lt;span&gt;EditAnywhere&lt;/span&gt;, &lt;span&gt;BlueprintReadWrite&lt;/span&gt;, &lt;span&gt;Category&lt;/span&gt; = &lt;span&gt;&quot;Item&quot;&lt;/span&gt;)&lt;/div&gt;
&lt;div&gt;&lt;span&gt;float&lt;/span&gt; &lt;span&gt;HealAmount&lt;/span&gt;;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;994&quot; data-start=&quot;978&quot; data-ke-size=&quot;size16&quot;&gt;생성자에서 기본값을 설정했다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:2:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot; data-language=&quot;cpp&quot;&gt;
&lt;div&gt;AHealingItem::&lt;span&gt;AHealingItem&lt;/span&gt;()&lt;/div&gt;
&lt;div&gt;{&lt;/div&gt;
&lt;div&gt;&lt;span&gt;HealAmount&lt;/span&gt; = &lt;span&gt;20.0f&lt;/span&gt;;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;ItemType&lt;/span&gt; = &lt;span&gt;&quot;Healing&quot;&lt;/span&gt;;&lt;/div&gt;
&lt;div&gt;}&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1129&quot; data-start=&quot;1091&quot; data-ke-size=&quot;size16&quot;&gt;처음에는 ActivateItem()에서 단순히 아이템만 삭제했다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:3:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot; data-language=&quot;cpp&quot;&gt;
&lt;div&gt;&lt;span&gt;void&lt;/span&gt; AHealingItem::&lt;span&gt;ActivateItem&lt;/span&gt;(&lt;span&gt;AActor&lt;/span&gt;* &lt;span&gt;Activator&lt;/span&gt;)&lt;/div&gt;
&lt;div&gt;{&lt;/div&gt;
&lt;div&gt;&lt;span&gt;DestroyItem&lt;/span&gt;();&lt;/div&gt;
&lt;div&gt;}&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1279&quot; data-start=&quot;1217&quot; data-ke-size=&quot;size16&quot;&gt;이후 실제 기능을 구현하기 전에 &lt;b&gt;아이템이 정상적으로 활성화되는지 확인하기 위해 디버그 메시지를 추가&lt;/b&gt;했다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:4:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot; data-language=&quot;cpp&quot;&gt;
&lt;div&gt;&lt;span&gt;GEngine&lt;/span&gt;-&amp;gt;AddOnScreenDebugMessage(&lt;/div&gt;
&lt;div&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;,&lt;/div&gt;
&lt;div&gt;&lt;span&gt;2.0f&lt;/span&gt;,&lt;/div&gt;
&lt;div&gt;FColor::&lt;span&gt;Green&lt;/span&gt;,&lt;/div&gt;
&lt;div&gt;FString::&lt;span&gt;Printf&lt;/span&gt;(&lt;span&gt;TEXT&lt;/span&gt;(&lt;span&gt;&quot;Player healing %.0f by HealingItem&quot;&lt;/span&gt;), &lt;span&gt;HealAmount&lt;/span&gt;)&lt;/div&gt;
&lt;div&gt;);&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1495&quot; data-start=&quot;1443&quot; data-ke-size=&quot;size16&quot;&gt;여기서 HealAmount가 float이므로 %d가 아니라 %.0f를 사용했다.&lt;/p&gt;
&lt;hr data-end=&quot;1500&quot; data-start=&quot;1497&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;1537&quot; data-start=&quot;1502&quot; data-section-id=&quot;18gslwv&quot;&gt;&lt;span&gt;3. FString::Printf()의 형식 지정자 문제&lt;/span&gt;&lt;/h1&gt;
&lt;p data-end=&quot;1556&quot; data-start=&quot;1539&quot; data-ke-size=&quot;size16&quot;&gt;처음에는 다음과 같이 작성했다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:5:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot; data-language=&quot;cpp&quot;&gt;
&lt;div&gt;FString::&lt;span&gt;Printf&lt;/span&gt;(&lt;/div&gt;
&lt;div&gt;&lt;span&gt;TEXT&lt;/span&gt;(&lt;span&gt;&quot;Player damaged %d by MineItem&quot;&lt;/span&gt;),&lt;/div&gt;
&lt;div&gt;&lt;span&gt;ExplosionDamage&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;)&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1682&quot; data-start=&quot;1652&quot; data-ke-size=&quot;size16&quot;&gt;그런데 컴파일 과정에서 C7595 오류가 발생했다.&lt;/p&gt;
&lt;p data-end=&quot;1733&quot; data-start=&quot;1684&quot; data-ke-size=&quot;size16&quot;&gt;원인은 ExplosionDamage가 float인데 %d를 사용했기 때문이다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:6:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot;&gt;
&lt;div&gt;%d &amp;rarr; int&lt;/div&gt;
&lt;div&gt;%f &amp;rarr; float&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1772&quot; data-start=&quot;1768&quot; data-ke-size=&quot;size16&quot;&gt;따라서:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:7:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot; data-language=&quot;cpp&quot;&gt;
&lt;div&gt;TEXT(&lt;span&gt;&quot;Player damaged %.0f by MineItem&quot;&lt;/span&gt;)&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1834&quot; data-start=&quot;1826&quot; data-ke-size=&quot;size16&quot;&gt;처럼 수정했다.&lt;/p&gt;
&lt;p data-end=&quot;1896&quot; data-start=&quot;1836&quot; data-ke-size=&quot;size16&quot;&gt;이 과정을 통해 &lt;b&gt;문자열 안의 포맷 지정자와 실제 전달하는 변수의 타입이 맞아야 한다&lt;/b&gt;는 것을 확인했다.&lt;/p&gt;
&lt;hr data-end=&quot;1901&quot; data-start=&quot;1898&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;1919&quot; data-start=&quot;1903&quot; data-section-id=&quot;lqwsqy&quot;&gt;4. CoinItem 구현&lt;/h1&gt;
&lt;p data-end=&quot;1975&quot; data-start=&quot;1921&quot; data-ke-size=&quot;size16&quot;&gt;코인은 ACoinItem을 부모로 두고 BigCoin과 SmallCoin을 자식으로 만들었다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:8:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot;&gt;
&lt;div&gt;ACoinItem&lt;/div&gt;
&lt;div&gt;├── ABigCoinItem&lt;/div&gt;
&lt;div&gt;└── ASmallCoinItem&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2055&quot; data-start=&quot;2036&quot; data-ke-size=&quot;size16&quot;&gt;코인마다 획득하는 점수가 다르므로:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:9:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot; data-language=&quot;cpp&quot;&gt;
&lt;div&gt;&lt;span&gt;int32&lt;/span&gt; &lt;span&gt;PointValue&lt;/span&gt;;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2094&quot; data-start=&quot;2087&quot; data-ke-size=&quot;size16&quot;&gt;를 만들었다.&lt;/p&gt;
&lt;p data-end=&quot;2135&quot; data-start=&quot;2096&quot; data-ke-size=&quot;size16&quot;&gt;그리고 CoinItem.cpp에서는 공통적인 코인 기능을 구현했다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:10:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot; data-language=&quot;cpp&quot;&gt;
&lt;div&gt;&lt;span&gt;void&lt;/span&gt; ACoinItem::&lt;span&gt;ActivateItem&lt;/span&gt;(&lt;span&gt;AActor&lt;/span&gt;* &lt;span&gt;Activator&lt;/span&gt;)&lt;/div&gt;
&lt;div&gt;{&lt;/div&gt;
&lt;div&gt;&lt;span&gt;if&lt;/span&gt; (&lt;span&gt;Activator&lt;/span&gt; &lt;span&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span&gt;Activator&lt;/span&gt;-&amp;gt;ActorHasTag(&lt;span&gt;&quot;Player&quot;&lt;/span&gt;))&lt;/div&gt;
&lt;div&gt;{&lt;/div&gt;
&lt;div&gt;&lt;span&gt;GEngine&lt;/span&gt;-&amp;gt;AddOnScreenDebugMessage(&lt;/div&gt;
&lt;div&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;,&lt;/div&gt;
&lt;div&gt;&lt;span&gt;2.0f&lt;/span&gt;,&lt;/div&gt;
&lt;div&gt;FColor::&lt;span&gt;Green&lt;/span&gt;,&lt;/div&gt;
&lt;div&gt;FString::&lt;span&gt;Printf&lt;/span&gt;(&lt;span&gt;TEXT&lt;/span&gt;(&lt;span&gt;&quot;Player gained %d points!&quot;&lt;/span&gt;), &lt;span&gt;PointValue&lt;/span&gt;)&lt;/div&gt;
&lt;div&gt;);&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;DestroyItem&lt;/span&gt;();&lt;/div&gt;
&lt;div&gt;}&lt;/div&gt;
&lt;div&gt;}&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2484&quot; data-start=&quot;2480&quot; data-ke-size=&quot;size16&quot;&gt;여기서:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:11:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot; data-language=&quot;cpp&quot;&gt;
&lt;div&gt;&lt;span&gt;Activator&lt;/span&gt;-&amp;gt;ActorHasTag(&lt;span&gt;&quot;Player&quot;&lt;/span&gt;)&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2573&quot; data-start=&quot;2531&quot; data-ke-size=&quot;size16&quot;&gt;를 통해 &lt;b&gt;현재 아이템을 활성화시킨 Actor가 플레이어인지 확인&lt;/b&gt;했다.&lt;/p&gt;
&lt;hr data-end=&quot;2578&quot; data-start=&quot;2575&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;2610&quot; data-start=&quot;2580&quot; data-section-id=&quot;1fwgywc&quot;&gt;5. BigCoin에서 부모 기능을 상속받도록 수정&lt;/h1&gt;
&lt;p data-end=&quot;2642&quot; data-start=&quot;2612&quot; data-ke-size=&quot;size16&quot;&gt;BigCoin에서는 생성자에서 점수만 다르게 설정했다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:12:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot; data-language=&quot;cpp&quot;&gt;
&lt;div&gt;ABigCoinItem::&lt;span&gt;ABigCoinItem&lt;/span&gt;()&lt;/div&gt;
&lt;div&gt;{&lt;/div&gt;
&lt;div&gt;&lt;span&gt;PointValue&lt;/span&gt; = &lt;span&gt;50&lt;/span&gt;;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;ItemType&lt;/span&gt; = &lt;span&gt;&quot;BigCoin&quot;&lt;/span&gt;;&lt;/div&gt;
&lt;div&gt;}&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2762&quot; data-start=&quot;2736&quot; data-ke-size=&quot;size16&quot;&gt;처음에는 BigCoin에도 다음 코드가 있었다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:13:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot; data-language=&quot;cpp&quot;&gt;
&lt;div&gt;&lt;span&gt;virtual&lt;/span&gt; &lt;span&gt;void&lt;/span&gt; &lt;span&gt;ActivateItem&lt;/span&gt;(&lt;span&gt;AActor&lt;/span&gt;* &lt;span&gt;Activator&lt;/span&gt;) &lt;span&gt;override&lt;/span&gt;;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2844&quot; data-start=&quot;2831&quot; data-ke-size=&quot;size16&quot;&gt;그리고 .cpp에는:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:14:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot; data-language=&quot;cpp&quot;&gt;
&lt;div&gt;&lt;span&gt;void&lt;/span&gt; ABigCoinItem::&lt;span&gt;ActivateItem&lt;/span&gt;(&lt;span&gt;AActor&lt;/span&gt;* &lt;span&gt;Activator&lt;/span&gt;)&lt;/div&gt;
&lt;div&gt;{&lt;/div&gt;
&lt;div&gt;&lt;span&gt;DestroyItem&lt;/span&gt;();&lt;/div&gt;
&lt;div&gt;}&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2938&quot; data-start=&quot;2932&quot; data-ke-size=&quot;size16&quot;&gt;가 있었다.&lt;/p&gt;
&lt;p data-end=&quot;3037&quot; data-start=&quot;2940&quot; data-ke-size=&quot;size16&quot;&gt;그런데 이렇게 하면 BigCoin이 ACoinItem의 ActivateItem()을 사용하는 것이 아니라 &lt;b&gt;자기 자신의 ActivateItem()을 실행한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3043&quot; data-start=&quot;3039&quot; data-ke-size=&quot;size16&quot;&gt;따라서:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:15:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot;&gt;
&lt;div&gt;BigCoin&lt;/div&gt;
&lt;div&gt;&amp;darr;&lt;/div&gt;
&lt;div&gt;ABigCoinItem::ActivateItem()&lt;/div&gt;
&lt;div&gt;&amp;darr;&lt;/div&gt;
&lt;div&gt;DestroyItem()&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3126&quot; data-start=&quot;3119&quot; data-ke-size=&quot;size16&quot;&gt;만 실행되고,&lt;/p&gt;
&lt;p data-end=&quot;3145&quot; data-start=&quot;3128&quot; data-ke-size=&quot;size16&quot;&gt;부모인 ACoinItem의:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:16:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot; data-language=&quot;cpp&quot;&gt;
&lt;div&gt;&lt;span&gt;&quot;Player gained %d points!&quot;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3200&quot; data-start=&quot;3186&quot; data-ke-size=&quot;size16&quot;&gt;메시지는 실행되지 않았다.&lt;/p&gt;
&lt;hr data-end=&quot;3205&quot; data-start=&quot;3202&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;3236&quot; data-start=&quot;3207&quot; data-section-id=&quot;8cp0dt&quot;&gt;6. 트러블슈팅 &amp;mdash; 왜 String이 안 떴을까?&lt;/h1&gt;
&lt;p data-end=&quot;3244&quot; data-start=&quot;3238&quot; data-ke-size=&quot;size16&quot;&gt;문제 상황:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:17:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot;&gt;
&lt;div&gt;BigCoin과 Overlap&lt;/div&gt;
&lt;div&gt;&amp;darr;&lt;/div&gt;
&lt;div&gt;BigCoin 사라짐&lt;/div&gt;
&lt;div&gt;&amp;darr;&lt;/div&gt;
&lt;div&gt;그런데 &quot;Player gained 50 points!&quot;가 안 나옴&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3454&quot; data-start=&quot;3345&quot; data-ke-size=&quot;size16&quot;&gt;처음에는 Overlap 자체의 문제라고 생각할 수도 있었지만, 아이템이 정상적으로 Destroy되는 것을 통해 Overlap과 ActivateItem() 자체는 실행되고 있다는 것을 확인했다.&lt;/p&gt;
&lt;p data-end=&quot;3471&quot; data-start=&quot;3456&quot; data-ke-size=&quot;size16&quot;&gt;결국 BigCoin에 있던:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:18:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot; data-language=&quot;cpp&quot;&gt;
&lt;div&gt;&lt;span&gt;void&lt;/span&gt; ABigCoinItem::&lt;span&gt;ActivateItem&lt;/span&gt;(&lt;span&gt;AActor&lt;/span&gt;* &lt;span&gt;Activator&lt;/span&gt;)&lt;/div&gt;
&lt;div&gt;{&lt;/div&gt;
&lt;div&gt;&lt;span&gt;DestroyItem&lt;/span&gt;();&lt;/div&gt;
&lt;div&gt;}&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3567&quot; data-start=&quot;3559&quot; data-ke-size=&quot;size16&quot;&gt;이 원인이었다.&lt;/p&gt;
&lt;p data-end=&quot;3651&quot; data-start=&quot;3569&quot; data-ke-size=&quot;size16&quot;&gt;이 함수가 존재하기 때문에 BigCoin은 부모의 ActivateItem()을 사용하지 않고 &lt;b&gt;자기 자신의 함수를 실행하고 있었던 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;hr data-end=&quot;3656&quot; data-start=&quot;3653&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;3696&quot; data-start=&quot;3658&quot; data-section-id=&quot;sv7hf1&quot;&gt;&lt;span&gt;7. virtual / override를 직접 이해한 순간&lt;/span&gt;&lt;/h1&gt;
&lt;p data-end=&quot;3730&quot; data-start=&quot;3698&quot; data-ke-size=&quot;size16&quot;&gt;BigCoin의 ActivateItem()을 삭제하고,&lt;/p&gt;
&lt;p data-end=&quot;3736&quot; data-start=&quot;3732&quot; data-ke-size=&quot;size16&quot;&gt;헤더의:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:19:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot; data-language=&quot;cpp&quot;&gt;
&lt;div&gt;&lt;span&gt;virtual&lt;/span&gt; &lt;span&gt;void&lt;/span&gt; &lt;span&gt;ActivateItem&lt;/span&gt;(&lt;span&gt;AActor&lt;/span&gt;* &lt;span&gt;Activator&lt;/span&gt;) &lt;span&gt;override&lt;/span&gt;;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3812&quot; data-start=&quot;3805&quot; data-ke-size=&quot;size16&quot;&gt;도 삭제했다.&lt;/p&gt;
&lt;p data-end=&quot;3876&quot; data-start=&quot;3814&quot; data-ke-size=&quot;size16&quot;&gt;그러자 BigCoin이 부모인 ACoinItem의 ActivateItem()을 그대로 사용하기 시작했다.&lt;/p&gt;
&lt;p data-end=&quot;3889&quot; data-start=&quot;3878&quot; data-ke-size=&quot;size16&quot;&gt;BigCoin에서는:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:20:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot; data-language=&quot;cpp&quot;&gt;
&lt;div&gt;&lt;span&gt;PointValue&lt;/span&gt; = &lt;span&gt;50&lt;/span&gt;;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3946&quot; data-start=&quot;3920&quot; data-ke-size=&quot;size16&quot;&gt;만 설정되어 있으므로 부모의 함수가 실행될 때:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:21:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot; data-language=&quot;cpp&quot;&gt;
&lt;div&gt;FString::&lt;span&gt;Printf&lt;/span&gt;(&lt;/div&gt;
&lt;div&gt;&lt;span&gt;TEXT&lt;/span&gt;(&lt;span&gt;&quot;Player gained %d points!&quot;&lt;/span&gt;),&lt;/div&gt;
&lt;div&gt;&lt;span&gt;PointValue&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;);&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4060&quot; data-start=&quot;4033&quot; data-ke-size=&quot;size16&quot;&gt;의 PointValue에 50이 들어갔다.&lt;/p&gt;
&lt;p data-end=&quot;4065&quot; data-start=&quot;4062&quot; data-ke-size=&quot;size16&quot;&gt;결과:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:22:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot;&gt;
&lt;div&gt;Player gained 50 points!&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4116&quot; data-start=&quot;4105&quot; data-ke-size=&quot;size16&quot;&gt;정상적으로 출력됐다.&lt;/p&gt;
&lt;hr data-end=&quot;4121&quot; data-start=&quot;4118&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;4141&quot; data-start=&quot;4123&quot; data-section-id=&quot;jor0vw&quot;&gt;8. 오늘 가장 중요했던 이해&lt;/h1&gt;
&lt;p data-end=&quot;4156&quot; data-start=&quot;4143&quot; data-ke-size=&quot;size16&quot;&gt;이번 과정을 통해 단순히&lt;/p&gt;
&lt;blockquote data-end=&quot;4180&quot; data-start=&quot;4158&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;4180&quot; data-start=&quot;4160&quot; data-ke-size=&quot;size16&quot;&gt;&quot;virtual은 가상 함수다.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;4229&quot; data-start=&quot;4182&quot; data-ke-size=&quot;size16&quot;&gt;라고 외우는 것보다 &lt;b&gt;실제로 부모와 자식의 함수를 비교하면서 이해할 수 있었다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4238&quot; data-start=&quot;4231&quot; data-ke-size=&quot;size16&quot;&gt;현재 구조는:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:23:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot;&gt;
&lt;div&gt;ACoinItem&lt;/div&gt;
&lt;div&gt;│&lt;/div&gt;
&lt;div&gt;├── ActivateItem()&lt;/div&gt;
&lt;div&gt;│ └── 코인을 먹으면 점수 출력 + 아이템 삭제&lt;/div&gt;
&lt;div&gt;│&lt;/div&gt;
&lt;div&gt;└── PointValue&lt;/div&gt;
&lt;div&gt;&amp;uarr;&lt;/div&gt;
&lt;div&gt;│&lt;/div&gt;
&lt;div&gt;├── BigCoin &amp;rarr; 50&lt;/div&gt;
&lt;div&gt;│&lt;/div&gt;
&lt;div&gt;└── SmallCoin &amp;rarr; 작은 값&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4424&quot; data-start=&quot;4411&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 구성할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;4486&quot; data-start=&quot;4426&quot; data-ke-size=&quot;size16&quot;&gt;즉 &lt;b&gt;공통적인 기능은 부모 클래스에 작성하고, 자식 클래스에서는 자신에게 필요한 값만 변경&lt;/b&gt;하면 된다.&lt;/p&gt;
&lt;p data-end=&quot;4548&quot; data-start=&quot;4488&quot; data-ke-size=&quot;size16&quot;&gt;그래서 BigCoin과 SmallCoin에 똑같은 ActivateItem() 코드를 복붙할 필요가 없다.&lt;/p&gt;
&lt;hr data-end=&quot;4553&quot; data-start=&quot;4550&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;4569&quot; data-start=&quot;4555&quot; data-section-id=&quot;8ncwta&quot;&gt;  오늘의 핵심 정리&lt;/h1&gt;
&lt;h3 data-end=&quot;4584&quot; data-start=&quot;4571&quot; data-section-id=&quot;14bpgg7&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;virtual&lt;/span&gt;&lt;/h3&gt;
&lt;p data-end=&quot;4595&quot; data-start=&quot;4586&quot; data-ke-size=&quot;size16&quot;&gt;부모 클래스에서:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:24:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot; data-language=&quot;cpp&quot;&gt;
&lt;div&gt;&lt;span&gt;virtual&lt;/span&gt; &lt;span&gt;void&lt;/span&gt; &lt;span&gt;ActivateItem&lt;/span&gt;(&lt;span&gt;AActor&lt;/span&gt;* &lt;span&gt;Activator&lt;/span&gt;);&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4701&quot; data-start=&quot;4655&quot; data-ke-size=&quot;size16&quot;&gt;라고 선언하면 &lt;b&gt;자식 클래스가 이 함수를 재정의할 수 있도록 열어두는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;h3 data-end=&quot;4717&quot; data-start=&quot;4703&quot; data-section-id=&quot;wswc7m&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;override&lt;/span&gt;&lt;/h3&gt;
&lt;p data-end=&quot;4728&quot; data-start=&quot;4719&quot; data-ke-size=&quot;size16&quot;&gt;자식 클래스에서:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:25:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot; data-language=&quot;cpp&quot;&gt;
&lt;div&gt;&lt;span&gt;virtual&lt;/span&gt; &lt;span&gt;void&lt;/span&gt; &lt;span&gt;ActivateItem&lt;/span&gt;(&lt;span&gt;AActor&lt;/span&gt;* &lt;span&gt;Activator&lt;/span&gt;) &lt;span&gt;override&lt;/span&gt;;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4846&quot; data-start=&quot;4797&quot; data-ke-size=&quot;size16&quot;&gt;라고 하면 &lt;b&gt;부모의 virtual 함수를 자식이 자기 방식으로 재정의한다는 의미&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-end=&quot;4859&quot; data-start=&quot;4848&quot; data-ke-size=&quot;size16&quot;&gt;그리고 중요한 것은:&lt;/p&gt;
&lt;blockquote data-end=&quot;4915&quot; data-start=&quot;4861&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;4915&quot; data-start=&quot;4863&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;자식에서 함수를 override하면 부모의 함수가 자동으로 같이 실행되는 것이 아니다.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;4962&quot; data-start=&quot;4917&quot; data-ke-size=&quot;size16&quot;&gt;자식 함수가 실행되기 때문에 부모 함수의 기능이 필요하다면 별도로 처리해야 한다.&lt;/p&gt;
&lt;p data-end=&quot;5032&quot; data-start=&quot;4964&quot; data-ke-size=&quot;size16&quot;&gt;반대로 자식에서 ActivateItem() 자체를 만들지 않으면 &lt;b&gt;부모의 구현을 그대로 물려받아 사용할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;5037&quot; data-start=&quot;5034&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;5058&quot; data-start=&quot;5039&quot; data-section-id=&quot;1v6r3eq&quot;&gt;  오늘 얻은 가장 큰 깨달음&lt;/h1&gt;
&lt;p data-end=&quot;5072&quot; data-start=&quot;5060&quot; data-ke-size=&quot;size16&quot;&gt;처음에는 상속 구조를:&lt;/p&gt;
&lt;blockquote data-end=&quot;5097&quot; data-start=&quot;5074&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;5097&quot; data-start=&quot;5076&quot; data-ke-size=&quot;size16&quot;&gt;&quot;부모 &amp;rarr; 자식으로 코드를 물려준다.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;5146&quot; data-start=&quot;5099&quot; data-ke-size=&quot;size16&quot;&gt;정도로 생각했는데, 오늘 직접 코드를 수정하면서 조금 더 구체적으로 이해하게 되었다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:26:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot;&gt;
&lt;div&gt;부모&lt;/div&gt;
&lt;div&gt;&amp;rarr; 공통적인 행동을 담당&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;자식&lt;/div&gt;
&lt;div&gt;&amp;rarr; 부모의 행동을 그대로 사용할 수도 있고&lt;/div&gt;
&lt;div&gt;&amp;rarr; 필요하다면 override해서 행동을 바꿀 수도 있고&lt;/div&gt;
&lt;div&gt;&amp;rarr; 공통 기능은 그대로 두고 값만 다르게 설정할 수도 있다.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5293&quot; data-start=&quot;5272&quot; data-ke-size=&quot;size16&quot;&gt;특히 BigCoin의 문제를 해결하면서&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;6fa26058-a9ff-4e94-ba9e-531e86d6cf97:27:editor&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div contenteditable=&quot;false&quot;&gt;
&lt;div&gt;&quot;왜 BigCoin에서는 부모의 String이 안 뜨지?&quot;&lt;/div&gt;
&lt;div&gt;&amp;darr;&lt;/div&gt;
&lt;div&gt;&quot;아, BigCoin이 ActivateItem을 자기 것으로 재정의했네.&quot;&lt;/div&gt;
&lt;div&gt;&amp;darr;&lt;/div&gt;
&lt;div&gt;&quot;그걸 지우니까 부모의 ActivateItem을 사용하는구나.&quot;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5454&quot; data-start=&quot;5439&quot; data-ke-size=&quot;size16&quot;&gt;라는 흐름을 직접 경험했다.&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;5523&quot; data-start=&quot;5456&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;오늘은 virtual과 override를 문법으로 외운 게 아니라 실제 트러블슈팅을 통해 이해한 날이었다.&lt;/b&gt;&lt;/p&gt;</description>
      <author>view29579</author>
      <guid isPermaLink="true">https://view29579.tistory.com/44</guid>
      <comments>https://view29579.tistory.com/44#entry44comment</comments>
      <pubDate>Thu, 20 Aug 2026 15:34:02 +0900</pubDate>
    </item>
  </channel>
</rss>