<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>DevCol (Development Collaboration)</title>
    <link>https://devcol.tistory.com/</link>
    <description>DevCol (Development Collaboration). 함께 개발 &amp;amp; 공부 &amp;amp; IT 정보 나눔장소</description>
    <language>ko</language>
    <pubDate>Sun, 14 Jun 2026 17:29:01 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>DevCol</managingEditor>
    <image>
      <title>DevCol (Development Collaboration)</title>
      <url>https://tistory1.daumcdn.net/tistory/5215502/attach/42bfe05947494deb8c6fae4d91a77892</url>
      <link>https://devcol.tistory.com</link>
    </image>
    <item>
      <title>파티클과 사운드로 게임 효과 연출하기 | [언리얼 엔진 C++ (Unreal Engine C++)]</title>
      <link>https://devcol.tistory.com/117</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screen Shot 2026-06-12 16 58 30.gif&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dTQhkT/dJMcaffUMbn/dWk34QXXoXr4VL42nXnRW0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dTQhkT/dJMcaffUMbn/dWk34QXXoXr4VL42nXnRW0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dTQhkT/dJMcaffUMbn/dWk34QXXoXr4VL42nXnRW0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/dTQhkT/dJMcaffUMbn/dWk34QXXoXr4VL42nXnRW0/img.gif&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;1280&quot; height=&quot;720&quot; data-filename=&quot;Screen Shot 2026-06-12 16 58 30.gif&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt;파티클과 사운드로 게임 효과 연출하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a1&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;파티클&amp;nbsp;시각&amp;nbsp;효과&amp;nbsp;추가하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣ &lt;b&gt;파티클 시스템 (Particla System) 기본 개념 이해하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;파티클 시스템이란?&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;파티클 시스템&lt;/b&gt; (Particle System)은 게임 내에서 &lt;b&gt;불꽃&lt;/b&gt;, &lt;b&gt;연기&lt;/b&gt;, &lt;b&gt;폭발&lt;/b&gt;, &lt;b&gt;먼지&lt;/b&gt; 등 다양한 시각적 효과를 구현하기 위한 도구입니다.&lt;/li&gt;
&lt;li&gt;파티클은 다수의 작은 &amp;lsquo;입자&amp;rsquo; (Particle)들이 모여 움직이면서 특정한 모양, 색상, 혹은 애니메이션 효과를 만들어냅니다.&lt;/li&gt;
&lt;li&gt;언리얼 엔진에서는 파티클 시스템을 사용해 효과적인 &lt;b&gt;VFX (Visual Effects)&lt;/b&gt; 를 구현할 수 있도록 풍부한 기능을 제공합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Cascade vs. Niagara&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Cascade&lt;/b&gt;: 언리얼 엔진 3 시절부터 제공된 &lt;b&gt;오래된 파티클 편집 툴&lt;/b&gt;입니다. 언리얼 엔진 4, 5에서도 여전히 호환되지만, 신규 기능 업데이트는 주로 &lt;b&gt;Niagara&lt;/b&gt; 위주로 이루어지고 있습니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;초급자가 배우기에 &lt;b&gt;상대적으로 간단&lt;/b&gt;하고 빠르게 결과를 볼 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;레거시 프로젝트&lt;/b&gt;나 기존 아티스트 툴체인에서 많이 사용&lt;/li&gt;
&lt;li&gt;복잡하거나 고급스러운 VFX 연출에는 한계&lt;/li&gt;
&lt;li&gt;아직까지 그래도 사용되는 부분이 꽤 있기 때문에 어느 정도 알고는 있어야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Niagara&lt;/b&gt;: 언리얼 엔진 4 후반부터 새롭게 도입된 &lt;b&gt;차세대 파티클 시스템&lt;/b&gt;입니다. 언리얼 엔진 5에서는 Niagara가 공식적으로 권장되는 방식입니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;모듈 단위&lt;/b&gt;로 다양한 파티클 동작을 정교하게 제어 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;블루프린트&lt;/b&gt;나 &lt;b&gt;머티리얼&lt;/b&gt;, &lt;b&gt;스크립팅&lt;/b&gt;과 유기적으로 연동되어 고급 VFX를 쉽게 만들 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GPU 파티클&lt;/b&gt;, &lt;b&gt;신규 기능 업데이트&lt;/b&gt;가 빠르게 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;만약 언리얼 엔진을 처음 접하거나, 파티클 효과를 빠르게 만들어봐야 한다면 &lt;b&gt;Cascade&lt;/b&gt;부터 익히는 것도 좋은 방법입니다. 하지만, 새 프로젝트를 계획 중이고 고급 이펙트를 구현하고 싶다면 &lt;b&gt;Niagara&lt;/b&gt; 학습을 권장합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이름 앞에 P_ 또는 Niagara_ 와 같은 접두어를 붙여두면, 프로젝트 내에서 파티클 에셋을 쉽게 구분할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나이아가라 UE 공식 문서: &lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/getting-started-in-niagara-effects-for-unreal-engine?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dev.epicgames.com/documentation/unreal-engine/getting-started-in-niagara-effects-for-unreal-engine?lang=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781229662887&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Getting Started in Niagara Effects for Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&quot; data-og-description=&quot;This page collects all the getting started learning materials for Niagara.&quot; data-og-host=&quot;dev.epicgames.com&quot; data-og-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/getting-started-in-niagara-effects-for-unreal-engine?lang=ko&quot; data-og-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/getting-started-in-niagara-effects-for-unreal-engine&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/d7gGUH/dJMb9jOve7N/EcsAjFYDp2PQ5TV9S4rxe0/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/bwAibj/dJMb9iIPfa8/u9kpqZa7TR87SEzFYgUtek/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/fPRmA/dJMb9fZDEUi/svYPcRK0ZkZZTK8FkZQjF0/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/getting-started-in-niagara-effects-for-unreal-engine?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/getting-started-in-niagara-effects-for-unreal-engine?lang=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/d7gGUH/dJMb9jOve7N/EcsAjFYDp2PQ5TV9S4rxe0/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/bwAibj/dJMb9iIPfa8/u9kpqZa7TR87SEzFYgUtek/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/fPRmA/dJMb9fZDEUi/svYPcRK0ZkZZTK8FkZQjF0/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Getting Started in Niagara Effects for Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;This page collects all the getting started learning materials for Niagara.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.epicgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐스케이드 UE 공식 문서: &lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/cascade-particle-editor-reference?application_version=4.27&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dev.epicgames.com/documentation/unreal-engine/cascade-particle-editor-reference?application_version=4.27&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781229665423&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Designing Visuals, Rendering, and Graphics with Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&quot; data-og-description=&quot;Rendering subsystem including lighting and shadowing, materials and textures, visual effects, and post processing in Unreal Engine.&quot; data-og-host=&quot;dev.epicgames.com&quot; data-og-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/cascade-particle-editor-reference?application_version=4.27&quot; data-og-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/designing-visuals-rendering-and-graphics-with-unreal-engine&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bVqFTi/dJMb8QMkxi9/XJbeLXs0gIT81jDc4FwHW0/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/cLWpvc/dJMb8U813x5/1uYUt9W3a5tfGYVkq29nr0/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/CO3pN/dJMb82MLxSG/VnGi8k7w1ymhNVjBUQk6VK/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/cascade-particle-editor-reference?application_version=4.27&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/cascade-particle-editor-reference?application_version=4.27&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bVqFTi/dJMb8QMkxi9/XJbeLXs0gIT81jDc4FwHW0/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/cLWpvc/dJMb8U813x5/1uYUt9W3a5tfGYVkq29nr0/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/CO3pN/dJMb82MLxSG/VnGi8k7w1ymhNVjBUQk6VK/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Designing Visuals, Rendering, and Graphics with Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Rendering subsystem including lighting and shadowing, materials and textures, visual effects, and post processing in Unreal Engine.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.epicgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2️⃣ &lt;b&gt;아이템 획득에&lt;/b&gt; 파티클 적용하기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 아이템은 상호작용 시 ActivateItem 함수를 실행하도로 설계를 했습니다. 여기에 파티클을 붙인다면 BaseItem을 상속받는 아이템들 모두에서 파티클을 설정할 수 있습니다.&lt;/li&gt;
&lt;li&gt;또한, 파티클 이펙트가 발생한 후 2초 뒤 이펙트가 사라지도록 설정을 해야 합니다. 이 부분까지도 고려해서 꼼꼼하게 코드를 수정해 보도록 합시다.&lt;/li&gt;
&lt;li&gt;빌드를 하고 에디터로 돌아가서, 파티클을 붙여줄 아이템 Blueprint를 (예를 들어, 지뢰 아이템) 열어봅니다. Details 창을 보면 Item 카테고리 아래에 Effects라는 카테고리가 생겼고, 여기서 파티클 이펙트를 설정할 수 있습니다. 리소스에 있는 파티클 중 맘에 드는 것으로 이펙트를 할당하고 컴파일 후 저장해 줍니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 아이템에 파티클 &amp;amp; 사운드 추가해 줍시다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;979&quot; data-origin-height=&quot;497&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clHxhH/dJMcaci5CLJ/92jAXIPxxi0KZGqenGm5u1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clHxhH/dJMcaci5CLJ/92jAXIPxxi0KZGqenGm5u1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clHxhH/dJMcaci5CLJ/92jAXIPxxi0KZGqenGm5u1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclHxhH%2FdJMcaci5CLJ%2F92jAXIPxxi0KZGqenGm5u1%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;979&quot; height=&quot;497&quot; data-origin-width=&quot;979&quot; data-origin-height=&quot;497&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;929&quot; data-origin-height=&quot;476&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKiezR/dJMcaaySRWv/LavkSZle0ve0VeqkRUCXf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKiezR/dJMcaaySRWv/LavkSZle0ve0VeqkRUCXf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKiezR/dJMcaaySRWv/LavkSZle0ve0VeqkRUCXf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKiezR%2FdJMcaaySRWv%2FLavkSZle0ve0VeqkRUCXf1%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;929&quot; height=&quot;476&quot; data-origin-width=&quot;929&quot; data-origin-height=&quot;476&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1781232495026&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pragma once

#include &quot;CoreMinimal.h&quot;
#include &quot;GameFramework/Actor.h&quot;
#include &quot;ItemInterface.h&quot;  // 만들어둔 인터페이스 헤더 포함

#include &quot;BaseItem.generated.h&quot;

class USphereComponent;

UCLASS()
class BC_CH3_ASSIGNMENT_5_API ABaseItem : public AActor, public IItemInterface
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ABaseItem();

protected:
	// 아이템 유형(타입)을 편집 가능하게 지정
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Item&quot;)
	FName ItemType;
	
	// 루트 컴포넌트 (씬)
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Item|Component&quot;)
	USceneComponent* Scene;
	// 충돌 컴포넌트 (플레이어 진입 범위 감지용)
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Item|Component&quot;)
	USphereComponent* Collision;
	// 아이템 시각 표현용 스태틱 메시
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Item|Component&quot;)
	UStaticMeshComponent* StaticMesh;
	
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Item|Effects&quot;)
	UParticleSystem* PickupParticle;
	
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Item|Effects&quot;)
	USoundBase* PickupSound;
	
	virtual void OnItemOverlap(
			UPrimitiveComponent* OverlappedComp,
			AActor* OtherActor,
			UPrimitiveComponent* OtherComp,
			int32 OtherBodyIndex,
			bool bFromSweep,
			const FHitResult&amp;amp; SweepResult) override;
	
	virtual void OnItemEndOverlap(
			UPrimitiveComponent* OverlappedComp,
			AActor* OtherActor,
			UPrimitiveComponent* OtherComp,
			int32 OtherBodyIndex) override;
	
	virtual void ActivateItem(AActor* Activator) override;
	virtual FName GetItemType() const override;
	
	// 아이템을 제거하는 공통 함수 (추가 이펙트나 로직을 넣을 수 있음)
	virtual void DestroyItem();
	
private:
	const FName CollisionProfile_OverlapAllDynamic = TEXT(&quot;OverlapAllDynamic&quot;);

};&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1781232505568&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;BaseItem.h&quot;
#include &quot;Components/SphereComponent.h&quot;
#include &quot;Kismet/GameplayStatics.h&quot;
#include &quot;Particles/ParticleSystemComponent.h&quot;


ABaseItem::ABaseItem()
{
	PrimaryActorTick.bCanEverTick = false;

	// 루트 컴포넌트 생성 및 설정
	Scene = CreateDefaultSubobject&amp;lt;USceneComponent&amp;gt;(TEXT(&quot;Scene&quot;));
	SetRootComponent(Scene);

	// 충돌 컴포넌트 생성 및 설정
	Collision = CreateDefaultSubobject&amp;lt;USphereComponent&amp;gt;(TEXT(&quot;Collision&quot;));
	// 겹침만 감지하는 프로파일 설정
	//Collision-&amp;gt;SetCollisionProfileName(TEXT(&quot;OverlapAllDynamic&quot;));
	Collision-&amp;gt;SetCollisionProfileName(CollisionProfile_OverlapAllDynamic);
	// 루트 컴포넌트로 설정
	Collision-&amp;gt;SetupAttachment(Scene);

	// 스태틱 메시 컴포넌트 생성 및 설정
	StaticMesh = CreateDefaultSubobject&amp;lt;UStaticMeshComponent&amp;gt;(TEXT(&quot;StaticMesh&quot;));
	StaticMesh-&amp;gt;SetupAttachment(Collision);
	// 메시가 불필요하게 충돌을 막지 않도록 하기 위해, 별도로 NoCollision 등으로 설정할 수 있음.

	// Overlap 이벤트 바인딩
	Collision-&amp;gt;OnComponentBeginOverlap.AddDynamic(this, &amp;amp;ABaseItem::OnItemOverlap);
	Collision-&amp;gt;OnComponentEndOverlap.AddDynamic(this, &amp;amp;ABaseItem::OnItemEndOverlap);
}

void ABaseItem::OnItemOverlap(
	UPrimitiveComponent* OverlappedComp,
	AActor* OtherActor,
	UPrimitiveComponent* OtherComp,
	int32 OtherBodyIndex,
	bool bFromSweep,
	const FHitResult&amp;amp; SweepResult)
{
	/*
	추가 팁: 인터페이스(Interface) 활용하기만약 플레이어뿐만 아니라 '데미지를 입을 수 있는 모든 대상'을 판별하고 싶다면, 
	Cast 대신 언리얼 인터페이스(UInterface)를 사용해 OtherActor-&amp;gt;Implements&amp;lt;UMyDamageInterface&amp;gt;() 형태로 판별하는 것이 아키텍처 관점에서 훨씬 깔끔합니다.
	
	// 싱글 플레이어 게임이거나 0번 로컬 플레이어를 판별할 때 가장 간단하고 직관적인 방법입니다. 충돌한 액터가 현재 월드의 플레이어 폰과 같은지 메모리 주소를 직접 비교합니다.
	// 단점: 멀티플레이어 환경(다른 클라이언트의 플레이어 캐릭터)에서는 작동하지 않을 수 있습니다.
	if (OtherActor &amp;amp;&amp;amp; OtherActor == GetWorld()-&amp;gt;GetFirstPlayerController()-&amp;gt;GetPawn())
	{		
		GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 2.0f, FColor::Blue, FString::Printf(TEXT(&quot;플레이어가 충돌했습니다!!!&quot;)));
	}  
	
	// 멀티플레이어 환경에서 적 플레이어, 아군 플레이어 구분 없이 '유저가 잡고 있는 캐릭터'를 모두 판별해 냅니다. 
	// AI 캐릭터(IsBotControlled)는 자동으로 걸러집니다.
	// #include &quot;GameFramework/Pawn.h&quot; // 다른 곳에서 선언된거랑 가능한한 여기서도 선언해두자
	if (OtherActor)
	{
		// 우선 APawn으로 캐스팅 (모든 캐릭터는 폰의 일종입니다)
		APawn* TouchedPawn = Cast&amp;lt;APawn&amp;gt;(OtherActor);
		
		// 폰이 맞고, 현재 플레이어 컨트롤러가 빙의(Possess)한 상태인지 확인
		if (TouchedPawn &amp;amp;&amp;amp; TouchedPawn-&amp;gt;IsPlayerControlled())
		{
			GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, FString::Printf(TEXT(&quot;플레이어가 조종 중인 액터입니다!!!&quot;)));
		}
	}	
	
	// 플레이어와 AI를 동시에 분기 처리하기
	// 하나의 충돌 함수 안에서 플레이어와 AI를 나누어 각각 다른 로직
	// (예: 플레이어면 UI 연출, AI면 데미지만 처리)을 실행하고 싶다면 다음과 같이 작성합니다.
	
	if (OtherActor)
	{
		APawn* TouchedPawn = Cast&amp;lt;APawn&amp;gt;(OtherActor);
			if (TouchedPawn)
			{
				if (TouchedPawn-&amp;gt;IsPlayerControlled())
				{
					// 실제 플레이어 전용 로직
					UE_LOG(LogTemp, Log, TEXT(&quot;플레이어 충돌&quot;));
				}
				else if (TouchedPawn-&amp;gt;IsBotControlled())
				{
					//  AI 봇 전용 로직
					UE_LOG(LogTemp, Log, TEXT(&quot;AI 캐릭터 충돌&quot;));
				}
			}
	}

	 */


	// OtherActor가 플레이어인지 확인 (&quot;Player&quot; 태그 활용)
	if (OtherActor &amp;amp;&amp;amp; OtherActor-&amp;gt;ActorHasTag(&quot;Player&quot;))
	{
		GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, FString::Printf(TEXT(&quot;Overlap!!!&quot;)));
		// 아이템 사용 (획득) 로직 호출
		ActivateItem(OtherActor);
	}
}

void ABaseItem::OnItemEndOverlap(
	UPrimitiveComponent* OverlappedComp,
	AActor* OtherActor,
	UPrimitiveComponent* OtherComp,
	int32 OtherBodyIndex)
{
}

void ABaseItem::ActivateItem(AActor* Activator)
{	
	
	//GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, FString::Printf(TEXT(&quot;Overlap!!&quot;)));

	UParticleSystemComponent* Particle = nullptr;
	
	// PickupParticle == BP 에서 지정해둔 에셋
	if (PickupParticle)
	{
		Particle = UGameplayStatics::SpawnEmitterAtLocation(
			GetWorld(),
			PickupParticle,
			GetActorLocation(),
			GetActorRotation(),
			true
		);
	}

	if (PickupSound)
	{
		UGameplayStatics::PlaySoundAtLocation(
			GetWorld(),
			PickupSound,
			GetActorLocation()
		);
		
		/*FTimerHandle DestroyParticleTimerHandle;
		TWeakObjectPtr&amp;lt;UParticleSystemComponent&amp;gt; WeakParticle = Particle;

		GetWorld()-&amp;gt;GetTimerManager().SetTimer(
			DestroyParticleTimerHandle,
			[WeakParticle]()
			{
			     if (WeakParticle.IsValid())
				{
					WeakParticle-&amp;gt;DestroyComponent();
							
				}
			},
			2.0f,
			false
		);*/
		
		
	}
}

FName ABaseItem::GetItemType() const
{
	return ItemType;
}

void ABaseItem::DestroyItem()
{
	Destroy();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다른 아이템 클래스들의 ActivateItem 함수에 BaseItem 을 상속받는 코드도 추가해줘야 합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Super::ActivateItem(Activator);&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;pre id=&quot;code_1781231344517&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void AMineItem::ActivateItem(AActor* Activator)
{
	Super::ActivateItem(Activator);
	
	// ExplosionDelay 후 폭발 실행
	GetWorld()-&amp;gt;GetTimerManager().SetTimer(ExplosionTimerHandle, this, &amp;amp;AMineItem::Explode, ExplosionDelay);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 Particle 들이 생성 후 안 사라지기 때문에 따로 관리를 해줘야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1781234061925&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;UParticleSystemComponent* Particle = nullptr;
	
	if (ExplosionParticle)
	{
		Particle = UGameplayStatics::SpawnEmitterAtLocation(
			GetWorld(),
			ExplosionParticle,
			GetActorLocation(),
			GetActorRotation(),
			//true // 여기서 true 면 auto destroy 되어야하는데 안된다면, particle이 loop 형신인거라 다른 추가 조치를 해주어야 합니다.
			false // 그래서 loop 나 세밀한 조정을 원한경우 따로 destroy 구현합니다
		);
	}
	
	if (ExplosionSound)
	{		
		UGameplayStatics::PlaySoundAtLocation(
			GetWorld(),
			ExplosionSound,
			GetActorLocation(),
			GetActorRotation(),
			true 
		);
		
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 여기서 만들어진 sound는 particle 과는 다르게 따로 destroy 안 해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;UGameplayStatics::PlaySoundAtLocation()로 재생한 사운드는 보통 따로 &lt;b&gt;Destroy&lt;/b&gt; 해주지 않아도 되는 이유는 PlaySoundAtLocation()은 &lt;b&gt;Fire and Forget&lt;/b&gt; 방식입니다.&lt;/span&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;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;&amp;ldquo;이 위치에서 이 소리 한 번 재생해 줘&amp;rdquo;&lt;br /&gt;라고 엔진에 요청하고, 이후 관리는 엔진이 처리해요.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그래서 아이템 획득음, 폭발음처럼 &lt;b&gt;짧게 한 번 재생되는 효과음&lt;/b&gt;은 따로 Destroy가 필요 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;그럼 언제 사운드를 직접 관리하나요?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음 같은 경우에는 PlaySoundAtLocation()보다 &lt;b&gt;AudioComponent&lt;/b&gt;를 사용하는 경우가 많아요.&lt;/span&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;span&gt;배경음악처럼 오래 재생되는 사운드&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;중간에 Stop 해야 하는 사운드&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;특정 Actor에 붙어서 따라다녀야 하는 사운드&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이런 경우에는 &lt;b&gt;SpawnSoundAtLocation&lt;/b&gt;() 또는 &lt;b&gt;SpawnSoundAttached&lt;/b&gt;()로 컴포넌트를 받아서 관리할 수 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;현재 코드처럼 아이템 획득 사운드라면:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;cpp&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;autohotkey&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;UGameplayStatics::PlaySoundAtLocation(
    GetWorld(),
    PickupSound,
    GetActorLocation()
);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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;b&gt;Looping 파티클&lt;/b&gt;이면 화면에 계속 남을 수 있어서, 필요하면 타이머로 DestroyComponent()를 해주는 어야 합니다.&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;짧은 효과음은 자동 정리&lt;br /&gt;루프 파티클이나 오래 남는 컴포넌트는 직접 정리 고려&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a4&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;Item 관련 C++ 클래스 코드들&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BaseItem.h&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1781235725671&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pragma once

#include &quot;CoreMinimal.h&quot;
#include &quot;GameFramework/Actor.h&quot;
#include &quot;ItemInterface.h&quot;  // 만들어둔 인터페이스 헤더 포함

#include &quot;BaseItem.generated.h&quot;

class USphereComponent;

UCLASS()
class BC_CH3_ASSIGNMENT_5_API ABaseItem : public AActor, public IItemInterface
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ABaseItem();

protected:
	// 아이템 유형(타입)을 편집 가능하게 지정
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Item&quot;)
	FName ItemType;
	
	// 루트 컴포넌트 (씬)
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Item|Component&quot;)
	USceneComponent* Scene;
	// 충돌 컴포넌트 (플레이어 진입 범위 감지용)
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Item|Component&quot;)
	USphereComponent* Collision;
	// 아이템 시각 표현용 스태틱 메시
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Item|Component&quot;)
	UStaticMeshComponent* StaticMesh;
	
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Item|Effects&quot;)
	UParticleSystem* PickupParticle;
	
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Item|Effects&quot;)
	USoundBase* PickupSound;
	
	virtual void OnItemOverlap(
			UPrimitiveComponent* OverlappedComp,
			AActor* OtherActor,
			UPrimitiveComponent* OtherComp,
			int32 OtherBodyIndex,
			bool bFromSweep,
			const FHitResult&amp;amp; SweepResult) override;
	
	virtual void OnItemEndOverlap(
			UPrimitiveComponent* OverlappedComp,
			AActor* OtherActor,
			UPrimitiveComponent* OtherComp,
			int32 OtherBodyIndex) override;
	
	virtual void ActivateItem(AActor* Activator) override;
	virtual FName GetItemType() const override;
	
	// 아이템을 제거하는 공통 함수 (추가 이펙트나 로직을 넣을 수 있음)
	virtual void DestroyItem();
	
private:
	const FName CollisionProfile_OverlapAllDynamic = TEXT(&quot;OverlapAllDynamic&quot;);

};&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BaseItem.Cpp&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1781235750318&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;BaseItem.h&quot;
#include &quot;Components/SphereComponent.h&quot;
#include &quot;Kismet/GameplayStatics.h&quot;
#include &quot;Particles/ParticleSystemComponent.h&quot;


ABaseItem::ABaseItem()
{
	PrimaryActorTick.bCanEverTick = false;

	// 루트 컴포넌트 생성 및 설정
	Scene = CreateDefaultSubobject&amp;lt;USceneComponent&amp;gt;(TEXT(&quot;Scene&quot;));
	SetRootComponent(Scene);

	// 충돌 컴포넌트 생성 및 설정
	Collision = CreateDefaultSubobject&amp;lt;USphereComponent&amp;gt;(TEXT(&quot;Collision&quot;));
	// 겹침만 감지하는 프로파일 설정
	//Collision-&amp;gt;SetCollisionProfileName(TEXT(&quot;OverlapAllDynamic&quot;));
	Collision-&amp;gt;SetCollisionProfileName(CollisionProfile_OverlapAllDynamic);
	// 루트 컴포넌트로 설정
	Collision-&amp;gt;SetupAttachment(Scene);

	// 스태틱 메시 컴포넌트 생성 및 설정
	StaticMesh = CreateDefaultSubobject&amp;lt;UStaticMeshComponent&amp;gt;(TEXT(&quot;StaticMesh&quot;));
	StaticMesh-&amp;gt;SetupAttachment(Collision);
	// 메시가 불필요하게 충돌을 막지 않도록 하기 위해, 별도로 NoCollision 등으로 설정할 수 있음.

	// Overlap 이벤트 바인딩
	Collision-&amp;gt;OnComponentBeginOverlap.AddDynamic(this, &amp;amp;ABaseItem::OnItemOverlap);
	Collision-&amp;gt;OnComponentEndOverlap.AddDynamic(this, &amp;amp;ABaseItem::OnItemEndOverlap);
}

void ABaseItem::OnItemOverlap(
	UPrimitiveComponent* OverlappedComp,
	AActor* OtherActor,
	UPrimitiveComponent* OtherComp,
	int32 OtherBodyIndex,
	bool bFromSweep,
	const FHitResult&amp;amp; SweepResult)
{
	/*
	추가 팁: 인터페이스(Interface) 활용하기만약 플레이어뿐만 아니라 '데미지를 입을 수 있는 모든 대상'을 판별하고 싶다면, 
	Cast 대신 언리얼 인터페이스(UInterface)를 사용해 OtherActor-&amp;gt;Implements&amp;lt;UMyDamageInterface&amp;gt;() 형태로 판별하는 것이 아키텍처 관점에서 훨씬 깔끔합니다.
	
	// 싱글 플레이어 게임이거나 0번 로컬 플레이어를 판별할 때 가장 간단하고 직관적인 방법입니다. 충돌한 액터가 현재 월드의 플레이어 폰과 같은지 메모리 주소를 직접 비교합니다.
	// 단점: 멀티플레이어 환경(다른 클라이언트의 플레이어 캐릭터)에서는 작동하지 않을 수 있습니다.
	if (OtherActor &amp;amp;&amp;amp; OtherActor == GetWorld()-&amp;gt;GetFirstPlayerController()-&amp;gt;GetPawn())
	{		
		GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 2.0f, FColor::Blue, FString::Printf(TEXT(&quot;플레이어가 충돌했습니다!!!&quot;)));
	}  
	
	// 멀티플레이어 환경에서 적 플레이어, 아군 플레이어 구분 없이 '유저가 잡고 있는 캐릭터'를 모두 판별해 냅니다. 
	// AI 캐릭터(IsBotControlled)는 자동으로 걸러집니다.
	// #include &quot;GameFramework/Pawn.h&quot; // 다른 곳에서 선언된거랑 가능한한 여기서도 선언해두자
	if (OtherActor)
	{
		// 우선 APawn으로 캐스팅 (모든 캐릭터는 폰의 일종입니다)
		APawn* TouchedPawn = Cast&amp;lt;APawn&amp;gt;(OtherActor);
		
		// 폰이 맞고, 현재 플레이어 컨트롤러가 빙의(Possess)한 상태인지 확인
		if (TouchedPawn &amp;amp;&amp;amp; TouchedPawn-&amp;gt;IsPlayerControlled())
		{
			GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, FString::Printf(TEXT(&quot;플레이어가 조종 중인 액터입니다!!!&quot;)));
		}
	}	
	
	// 플레이어와 AI를 동시에 분기 처리하기
	// 하나의 충돌 함수 안에서 플레이어와 AI를 나누어 각각 다른 로직
	// (예: 플레이어면 UI 연출, AI면 데미지만 처리)을 실행하고 싶다면 다음과 같이 작성합니다.
	
	if (OtherActor)
	{
		APawn* TouchedPawn = Cast&amp;lt;APawn&amp;gt;(OtherActor);
			if (TouchedPawn)
			{
				if (TouchedPawn-&amp;gt;IsPlayerControlled())
				{
					// 실제 플레이어 전용 로직
					UE_LOG(LogTemp, Log, TEXT(&quot;플레이어 충돌&quot;));
				}
				else if (TouchedPawn-&amp;gt;IsBotControlled())
				{
					//  AI 봇 전용 로직
					UE_LOG(LogTemp, Log, TEXT(&quot;AI 캐릭터 충돌&quot;));
				}
			}
	}

	 */


	// OtherActor가 플레이어인지 확인 (&quot;Player&quot; 태그 활용)
	if (OtherActor &amp;amp;&amp;amp; OtherActor-&amp;gt;ActorHasTag(&quot;Player&quot;))
	{
		GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, FString::Printf(TEXT(&quot;Overlap!!!&quot;)));
		// 아이템 사용 (획득) 로직 호출
		ActivateItem(OtherActor);
	}
}

void ABaseItem::OnItemEndOverlap(
	UPrimitiveComponent* OverlappedComp,
	AActor* OtherActor,
	UPrimitiveComponent* OtherComp,
	int32 OtherBodyIndex)
{
}

void ABaseItem::ActivateItem(AActor* Activator)
{	
	
	//GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, FString::Printf(TEXT(&quot;Overlap!!&quot;)));

	
	UParticleSystemComponent* Particle = nullptr;
	
	// PickupParticle == BP 에서 지정해둔 에셋
	if (PickupParticle)
	{
		Particle = UGameplayStatics::SpawnEmitterAtLocation(
			GetWorld(),
			PickupParticle,
			GetActorLocation(),
			GetActorRotation(),
			true
		);
	}

	if (PickupSound)
	{
		UGameplayStatics::PlaySoundAtLocation(
			GetWorld(),
			PickupSound,
			GetActorLocation()
		);

	}
	
	if (Particle)
	{
		if (GEngine)
		GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, FString::Printf(TEXT(&quot;ActivateItem from Base Item&quot;)));
		
		FTimerHandle DestroyParticleTimerHandle;
		TWeakObjectPtr&amp;lt;UParticleSystemComponent&amp;gt; WeakParticle = Particle;

		GetWorld()-&amp;gt;GetTimerManager().SetTimer(
			DestroyParticleTimerHandle,
			[WeakParticle]()
			{
				 if (WeakParticle.IsValid())
				 {
					 WeakParticle-&amp;gt;DestroyComponent();
							
				 }
			 },
			 2.0f,
			 false
		 );
	}
}

FName ABaseItem::GetItemType() const
{
	return ItemType;
}

void ABaseItem::DestroyItem()
{
	Destroy();
	
	/*if (PickupParticle)
	{
		FTimerHandle DestroyParticleTimerHandle;
		
		GetWorld()-&amp;gt;GetTimerManager().SetTimer(
			DestroyParticleTimerHandle,
			// lamda: 익명 함수 (이름이 없는 함수)
			// [ ] 일종의 캡쳐리스트 람다 싱행시 [ ] 안에 있는 (현재는 Particle) 변수를 바깥 스코프에서 값을 가져다가 
			// 사용할 수 있게 만드는 것.
			[Particle]()
			{
				Particle-&amp;gt;DestroyComponent();
			},
			1.0f, // destroy time in sec
			false
		);
	}*/
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MineItem.h&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1781235781920&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pragma once

#include &quot;CoreMinimal.h&quot;
#include &quot;BaseItem.h&quot;
#include &quot;MineItem.generated.h&quot;


UCLASS()
class BC_CH3_ASSIGNMENT_5_API AMineItem : public ABaseItem
{
	GENERATED_BODY()
	
public:
	AMineItem();
	
protected:
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = &quot;Item|Component&quot;)
	USphereComponent* ExplosionCollision;
	
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Item|Effects&quot;)
	UParticleSystem* ExplosionParticle;
	
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Item|Effects&quot;)
	USoundBase* ExplosionSound;
	
	// 폭발까지 걸리는 시간
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=&quot;Mine&quot;)
	float ExplosionDelay;
	
	// 폭발 범위
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Mine&quot;)
	float ExplosionRadius;

	// 폭발 데미지
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=&quot;Mine&quot;)
	int ExplosionDamage;
	
	bool bHasExploded;
	// 지뢰 발동 여부
	FTimerHandle ExplosionTimerHandle;

	virtual void ActivateItem(AActor* Activator) override;
	
	void Explode();
	

private:
	
	const FName CollisionProfile_OverlapAllDynamic = TEXT(&quot;OverlapAllDynamic&quot;);
};&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MineItem.cpp&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1781235856161&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;MineItem.h&quot;
#include &quot;Components/SphereComponent.h&quot;
#include &quot;Kismet/GameplayStatics.h&quot;
#include &quot;Particles/ParticleSystemComponent.h&quot;

AMineItem::AMineItem()
{
	ExplosionDelay = 5.0f;
	ExplosionRadius = 300.0f;
	ExplosionDamage = 30.0f;
	ItemType = &quot;Mine&quot;;
	bHasExploded = false;
    
	ExplosionCollision = CreateDefaultSubobject&amp;lt;USphereComponent&amp;gt;(TEXT(&quot;ExplosionCollision&quot;));
	ExplosionCollision-&amp;gt;InitSphereRadius(ExplosionRadius);
	//ExplosionCollision-&amp;gt;SetCollisionProfileName(TEXT(&quot;OverlapAllDynamic&quot;)); 
	ExplosionCollision-&amp;gt;SetCollisionProfileName(CollisionProfile_OverlapAllDynamic); 
	ExplosionCollision-&amp;gt;SetupAttachment(Scene);
}

void AMineItem::ActivateItem(AActor* Activator)
{
	if (bHasExploded) return;
	
	
	Super::ActivateItem(Activator);
	
	// ExplosionDelay 후 폭발 실행
	GetWorld()-&amp;gt;GetTimerManager().SetTimer(ExplosionTimerHandle, this, &amp;amp;AMineItem::Explode, ExplosionDelay);
	
	bHasExploded = true;
}

void AMineItem::Explode()
{
	UParticleSystemComponent* Particle = nullptr;
	
	if (GEngine)
		GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, FString::Printf(TEXT(&quot;ActivateItem Explode&quot;)));
	
	if (ExplosionParticle)
	{
		Particle = UGameplayStatics::SpawnEmitterAtLocation(
			GetWorld(),
			ExplosionParticle,
			GetActorLocation(),
			GetActorRotation(),
			//true // 여기서 true 면 auto destroy 되어야하는데 안된다면, particle이 loop 형신인거라 다른 추가 조치를 해주어야 합니다.
			false // 그래서 loop 나 세밀한 조정을 원한경우 따로 destroy 구현합니다
		);
	}
	
	if (ExplosionSound)
	{		
		UGameplayStatics::PlaySoundAtLocation(
			GetWorld(),
			ExplosionSound,
			GetActorLocation(),
			GetActorRotation(),
			true 
		);
		
	}
	
	TArray&amp;lt;AActor*&amp;gt; OverlappingActors;
	ExplosionCollision-&amp;gt;GetOverlappingActors(OverlappingActors);

	for (AActor* Actor : OverlappingActors)
	{
		if (Actor &amp;amp;&amp;amp; Actor-&amp;gt;ActorHasTag(&quot;Player&quot;))
		{
			GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, FString::Printf(TEXT(&quot;Player damaged %d by MineItem&quot;), ExplosionDamage));
			
			// 데미지를 발생시켜 Actor-&amp;gt;TakeDamage()가 실행되도록 함
			UGameplayStatics::ApplyDamage(
				Actor,                      // 데미지를 받을 액터
				ExplosionDamage,            // 데미지 양
				nullptr,                    // 데미지를 유발한 주체 (지뢰를 설치한 캐릭터가 없으므로 nullptr)
				this,                       // 데미지를 유발한 오브젝트(지뢰)
				UDamageType::StaticClass()  // 기본 데미지 유형
			);
			
			
		}
	}

	// 지뢰 제거
	DestroyItem();
	
	if (Particle)
	{
		if (GEngine)
		{
			GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, FString::Printf(TEXT(&quot;Particle destroyed wid delay %f&quot;), ExplosionDelay));
		}
		
		FTimerHandle DestroyParticleTimerHandle;
		
		GetWorld()-&amp;gt;GetTimerManager().SetTimer(
			DestroyParticleTimerHandle,
			// lamda: 익명 함수 (이름이 없는 함수)
			// [ ] 일종의 캡쳐리스트 람다 싱행시 [ ] 안에 있는 (현재는 Particle) 변수를 바깥 스코프에서 값을 가져다가 
			// 사용할 수 있게 만드는 것.
			[Particle]()
			{
				Particle-&amp;gt;DestroyComponent();
			},
			
			
			ExplosionDelay,
			//1.0f, // destroy time in sec
			false
		);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style2&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 id=&quot;a1&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;Debugging&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;padding: 0.3em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #5b63fb; font-weight: bold; text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;문제: &lt;/span&gt;게임 완성 후 테스팅 플레이 해봤는데 갑자기 게임이 크래쉬 해버렸다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제일 큰 문제가 바로 플레이 중 갑자기 크래쉬 해버린다는 거다.. 그래서 무엇 때문인지 감을 못 잡았다.&lt;/p&gt;
&lt;h4 style=&quot;padding: 0.3em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #5b63fb; font-weight: bold; text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;해결 방법: 많은 Null Check&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예상하기는 파티클 생성이랑 그거 해제 시 메모리 접근이 잘못돼서 그런 거 같다. 그래서 그런 쪽 코드에 다 Safety? (null check)을 걸었더니 해결되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;padding: 0.3em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #5b63fb; font-weight: bold; text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;느낀 점: 조심해서 코드를 짜자!&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확실히 언리얼 엔진이 무겁고 더 많이 신경 써서 다뤄야겠다고 배웠다.&lt;/p&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;p data-ke-size=&quot;size16&quot;&gt;그런데 걱정은 이렇게 작은 프로젝트에서 크래쉬 나는데... 조금 큰 거는 크래쉬 나면 디버깅 어떻게 하지....&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a1&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;완성된 모습&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Youtube:&lt;a href=&quot;https://youtu.be/DBJt9eXNTGU&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://youtu.be/DBJt9eXNTGU&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=DBJt9eXNTGU&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/YD88v/dJMb8SpQsRA/vN9g5uDLBKtWyQueyzX0o1/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;Bootcamp Ch3 Pre-Assignment5 - Redesigning the Game Loop and UI | Unreal Engine 5  [UE5 C++]&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/DBJt9eXNTGU&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&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;b&gt;현재 게임로직&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;총 3개의 스테이지(Level) 존재&lt;/li&gt;
&lt;li&gt;아이템 랜덤 생성: Health Potion, Big &amp;amp; Small Coin, Mine&lt;/li&gt;
&lt;li&gt;각 스테이지에 생성된 모든 Coin 획득 시 다음&amp;nbsp; 스테이지로 이동&lt;/li&gt;
&lt;li&gt;Level 올라갈 시 체력 Restore&lt;/li&gt;
&lt;li&gt;시간 초과 혹은 체력이 0 이 되면 Game Over&lt;/li&gt;
&lt;li&gt;3개의 스테이즈 다 클리어시 Game Complete&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Github Link: &lt;a href=&quot;https://github.com/devcol-main/BC_Ch3_Assignment_5/blob/main/README.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/devcol-main/BC_Ch3_Assignment_5/blob/main/README.md&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781250821109&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;BC_Ch3_Assignment_5/README.md at main &amp;middot; devcol-main/BC_Ch3_Assignment_5&quot; data-og-description=&quot;Contribute to devcol-main/BC_Ch3_Assignment_5 development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/devcol-main/BC_Ch3_Assignment_5/blob/main/README.md&quot; data-og-url=&quot;https://github.com/devcol-main/BC_Ch3_Assignment_5/blob/main/README.md&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ShmOe/dJMb82eVrYI/73MWMY1tpGkTkulc0AhOd1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/eEJXdy/dJMb86PacdD/X5EsgyaYVvwNhUZrDZEyj0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/devcol-main/BC_Ch3_Assignment_5/blob/main/README.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/devcol-main/BC_Ch3_Assignment_5/blob/main/README.md&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ShmOe/dJMb82eVrYI/73MWMY1tpGkTkulc0AhOd1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/eEJXdy/dJMb86PacdD/X5EsgyaYVvwNhUZrDZEyj0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;BC_Ch3_Assignment_5/README.md at main &amp;middot; devcol-main/BC_Ch3_Assignment_5&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to devcol-main/BC_Ch3_Assignment_5 development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #5b63fb; font-weight: bold; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;추천&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나이아가라 UE 공식 문서: &lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/getting-started-in-niagara-effects-for-unreal-engine?lang=ko&quot;&gt;https://dev.epicgames.com/documentation/unreal-engine/getting-started-in-niagara-effects-for-unreal-engine?lang=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781229673437&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Getting Started in Niagara Effects for Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&quot; data-og-description=&quot;This page collects all the getting started learning materials for Niagara.&quot; data-og-host=&quot;dev.epicgames.com&quot; data-og-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/getting-started-in-niagara-effects-for-unreal-engine?lang=ko&quot; data-og-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/getting-started-in-niagara-effects-for-unreal-engine&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/d7gGUH/dJMb9jOve7N/EcsAjFYDp2PQ5TV9S4rxe0/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/bwAibj/dJMb9iIPfa8/u9kpqZa7TR87SEzFYgUtek/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/fPRmA/dJMb9fZDEUi/svYPcRK0ZkZZTK8FkZQjF0/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/getting-started-in-niagara-effects-for-unreal-engine?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/getting-started-in-niagara-effects-for-unreal-engine?lang=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/d7gGUH/dJMb9jOve7N/EcsAjFYDp2PQ5TV9S4rxe0/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/bwAibj/dJMb9iIPfa8/u9kpqZa7TR87SEzFYgUtek/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/fPRmA/dJMb9fZDEUi/svYPcRK0ZkZZTK8FkZQjF0/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Getting Started in Niagara Effects for Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;This page collects all the getting started learning materials for Niagara.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.epicgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐스케이드 UE 공식 문서: &lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/cascade-particle-editor-reference?application_version=4.27&quot;&gt;https://dev.epicgames.com/documentation/unreal-engine/cascade-particle-editor-reference?application_version=4.27&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781229674903&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Designing Visuals, Rendering, and Graphics with Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&quot; data-og-description=&quot;Rendering subsystem including lighting and shadowing, materials and textures, visual effects, and post processing in Unreal Engine.&quot; data-og-host=&quot;dev.epicgames.com&quot; data-og-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/cascade-particle-editor-reference?application_version=4.27&quot; data-og-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/designing-visuals-rendering-and-graphics-with-unreal-engine&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bVqFTi/dJMb8QMkxi9/XJbeLXs0gIT81jDc4FwHW0/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/cLWpvc/dJMb8U813x5/1uYUt9W3a5tfGYVkq29nr0/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/CO3pN/dJMb82MLxSG/VnGi8k7w1ymhNVjBUQk6VK/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/cascade-particle-editor-reference?application_version=4.27&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/cascade-particle-editor-reference?application_version=4.27&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bVqFTi/dJMb8QMkxi9/XJbeLXs0gIT81jDc4FwHW0/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/cLWpvc/dJMb8U813x5/1uYUt9W3a5tfGYVkq29nr0/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/CO3pN/dJMb82MLxSG/VnGi8k7w1ymhNVjBUQk6VK/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Designing Visuals, Rendering, and Graphics with Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Rendering subsystem including lighting and shadowing, materials and textures, visual effects, and post processing in Unreal Engine.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.epicgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/107&quot;&gt;[Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781250825307&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;인터페이스 기반 아이템 클래스 설계하기 인터페이스 이해하기1️⃣ 인터페이스란?인터페이스 (Interface)란 클래스 (또는 오브젝트)가 반드시 구현해야 할 함수 목록만을 미리 정의해 두고, 실제 &quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/107&quot; data-og-url=&quot;https://devcol.tistory.com/107&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/i8Eu8/dJMb86O97yQ/KrdVAwlbKoqPioBFaTZrp1/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/RHrb0/dJMb81f00nk/GXBARX8wUIPEhZfFsbJ0w0/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/dXIyx2/dJMb896b3nW/NsulI0BwU9V1lIiWOJWOTk/img.png?width=997&amp;amp;height=544&amp;amp;face=0_0_997_544&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/107&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/107&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/i8Eu8/dJMb86O97yQ/KrdVAwlbKoqPioBFaTZrp1/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/RHrb0/dJMb81f00nk/GXBARX8wUIPEhZfFsbJ0w0/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/dXIyx2/dJMb896b3nW/NsulI0BwU9V1lIiWOJWOTk/img.png?width=997&amp;amp;height=544&amp;amp;face=0_0_997_544');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스 기반 아이템 클래스 설계하기 인터페이스 이해하기1️⃣ 인터페이스란?인터페이스 (Interface)란 클래스 (또는 오브젝트)가 반드시 구현해야 할 함수 목록만을 미리 정의해 두고, 실제&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://devcol.tistory.com/108&quot;&gt;[Unreal Engine/UE 기초] - 충돌 이벤트로 획득되는 아이템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781250826320&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;충돌 이벤트로 획득되는 아이템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;충돌 이벤트로 획득되는 아이템 구현하기 이전 포스팅에서는 클래스 구조만 짜고 로직은 비여있던 상태.이전 포스팅: [Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼 &quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/108&quot; data-og-url=&quot;https://devcol.tistory.com/108&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/usseC/dJMb88e84Rw/q2vM2cRV1xYSSwwGwMCYu1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/lg8Ak/dJMb84qgXWz/DNq0qEzBG0sApFbp7nw8k0/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/ulNRY/dJMb83Srmsy/4jxZqnPrqkOy4bgB8aksmK/img.png?width=1596&amp;amp;height=489&amp;amp;face=0_0_1596_489&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/108&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/108&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/usseC/dJMb88e84Rw/q2vM2cRV1xYSSwwGwMCYu1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/lg8Ak/dJMb84qgXWz/DNq0qEzBG0sApFbp7nw8k0/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/ulNRY/dJMb83Srmsy/4jxZqnPrqkOy4bgB8aksmK/img.png?width=1596&amp;amp;height=489&amp;amp;face=0_0_1596_489');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;충돌 이벤트로 획득되는 아이템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;충돌 이벤트로 획득되는 아이템 구현하기 이전 포스팅에서는 클래스 구조만 짜고 로직은 비여있던 상태.이전 포스팅: [Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://devcol.tistory.com/109&quot;&gt;[Unreal Engine/UE 기초] - 아이템 스폰 및 레벨 데이터 관리하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781250827593&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;아이템 스폰 및 레벨 데이터 관리하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;아이템 스폰 및 레벨 데이터 관리하기 랜덤 위치에 아이템 스폰하기 1️⃣ 레벨 셋팅하기Resources 폴더에 Maps 폴더에는 3개의 레벨이 이미 존재합니다. 각각 난이도에 따라서 크기가 다른 맵이고, &quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/109&quot; data-og-url=&quot;https://devcol.tistory.com/109&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bb7rOB/dJMb9lMjLJO/5kTyg5YcZObBNMipdSgoKK/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/bab4de/dJMb9cBQjCV/WVs1kCtDKwGDGpLGykbOb1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/bjzwRD/dJMb9iaZqLR/5u93kLFlxAX5jUZeK1Tjp0/img.png?width=943&amp;amp;height=571&amp;amp;face=0_0_943_571&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/109&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/109&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bb7rOB/dJMb9lMjLJO/5kTyg5YcZObBNMipdSgoKK/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/bab4de/dJMb9cBQjCV/WVs1kCtDKwGDGpLGykbOb1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/bjzwRD/dJMb9iaZqLR/5u93kLFlxAX5jUZeK1Tjp0/img.png?width=943&amp;amp;height=571&amp;amp;face=0_0_943_571');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;아이템 스폰 및 레벨 데이터 관리하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;아이템 스폰 및 레벨 데이터 관리하기 랜덤 위치에 아이템 스폰하기 1️⃣ 레벨 셋팅하기Resources 폴더에 Maps 폴더에는 3개의 레벨이 이미 존재합니다. 각각 난이도에 따라서 크기가 다른 맵이고,&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://devcol.tistory.com/110&quot;&gt;[Unreal Engine/UE 기초] - 캐릭터 체력 및 점수 관리 시스템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781250829085&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;캐릭터 체력 및 점수 관리 시스템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;캐릭터 체력 및 점수 관리 시스템 구현하기 캐릭터 체력 시스템 구현하기 1️⃣ 캐릭터 클래스에 체력 변수 및 함수 선언PlayerState를 쓰지 않는 이유PlayerState: 각 플레이어마다의 어떤 정보를 관&quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/110&quot; data-og-url=&quot;https://devcol.tistory.com/110&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/to8Hp/dJMb84qgXWB/XkF0sv4nkNFVMwPN3RxyiK/img.png?width=773&amp;amp;height=359&amp;amp;face=0_0_773_359,https://scrap.kakaocdn.net/dn/in3Hi/dJMb86O97yR/xLKESERIx6levctoUfRwE1/img.png?width=773&amp;amp;height=359&amp;amp;face=0_0_773_359,https://scrap.kakaocdn.net/dn/bul1bf/dJMb82MLv19/7XshaErT4bI4caYIunjHmK/img.png?width=915&amp;amp;height=558&amp;amp;face=0_0_915_558&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/110&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/110&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/to8Hp/dJMb84qgXWB/XkF0sv4nkNFVMwPN3RxyiK/img.png?width=773&amp;amp;height=359&amp;amp;face=0_0_773_359,https://scrap.kakaocdn.net/dn/in3Hi/dJMb86O97yR/xLKESERIx6levctoUfRwE1/img.png?width=773&amp;amp;height=359&amp;amp;face=0_0_773_359,https://scrap.kakaocdn.net/dn/bul1bf/dJMb82MLv19/7XshaErT4bI4caYIunjHmK/img.png?width=915&amp;amp;height=558&amp;amp;face=0_0_915_558');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;캐릭터 체력 및 점수 관리 시스템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;캐릭터 체력 및 점수 관리 시스템 구현하기 캐릭터 체력 시스템 구현하기 1️⃣ 캐릭터 클래스에 체력 변수 및 함수 선언PlayerState를 쓰지 않는 이유PlayerState: 각 플레이어마다의 어떤 정보를 관&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://devcol.tistory.com/111&quot;&gt;[Unreal Engine/UE 기초] - 게임 루프 설계를 통한 게임 흐름 제어하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781250832080&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;게임 루프 설계를 통한 게임 흐름 제어하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;게임 루프 설계를 통한 게임 흐름 제어하기 GameState를 이용한 게임 루프 구현하기 게임루프: 보통 게임의 핵심적인 흐름을 얘기합니다. 즉 게임이 시작할 때부터 종료까지 수행하는 단계들게임&quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/111&quot; data-og-url=&quot;https://devcol.tistory.com/111&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Mapg6/dJMb82eVrYS/zNUWCsh491iOCo6aQNM2KK/img.png?width=800&amp;amp;height=566&amp;amp;face=0_0_800_566,https://scrap.kakaocdn.net/dn/2y5JI/dJMb9bwaDzq/AzWkkNHhYbR2CeGTBxKAY0/img.png?width=800&amp;amp;height=566&amp;amp;face=0_0_800_566,https://scrap.kakaocdn.net/dn/bdtQQz/dJMb9frNMyx/NnXPLGKrJAH6qBywC7JT21/img.png?width=1167&amp;amp;height=827&amp;amp;face=0_0_1167_827&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/111&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/111&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Mapg6/dJMb82eVrYS/zNUWCsh491iOCo6aQNM2KK/img.png?width=800&amp;amp;height=566&amp;amp;face=0_0_800_566,https://scrap.kakaocdn.net/dn/2y5JI/dJMb9bwaDzq/AzWkkNHhYbR2CeGTBxKAY0/img.png?width=800&amp;amp;height=566&amp;amp;face=0_0_800_566,https://scrap.kakaocdn.net/dn/bdtQQz/dJMb9frNMyx/NnXPLGKrJAH6qBywC7JT21/img.png?width=1167&amp;amp;height=827&amp;amp;face=0_0_1167_827');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;게임 루프 설계를 통한 게임 흐름 제어하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;게임 루프 설계를 통한 게임 흐름 제어하기 GameState를 이용한 게임 루프 구현하기 게임루프: 보통 게임의 핵심적인 흐름을 얘기합니다. 즉 게임이 시작할 때부터 종료까지 수행하는 단계들게임&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/114&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; [Unreal Engine/UE 기초] - UI 위젯 설계와 실시간 데이터 연동하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781250831932&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;UI 위젯 설계와 실시간 데이터 연동하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;UI 위젯 설계와 실시간 데이터 연동하기 | [언리얼 엔진 C++ (Unreal Engine C++)] UMG (User Widget) 위젯 기초 디자인 이해하기 1️⃣ HUD (Heads-Up Display)란?HUD는 게임 내에서 플레이어에게 정보를 제공하기 위&quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/114&quot; data-og-url=&quot;https://devcol.tistory.com/114&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dWdB9W/dJMb84qgXWC/Giz2KwYRqTn2WeK2KDaatK/img.gif?width=400&amp;amp;height=203&amp;amp;face=0_0_400_203,https://scrap.kakaocdn.net/dn/cm53lH/dJMb83SrmsD/w26ooHE74oYMXYlki4IuB0/img.gif?width=400&amp;amp;height=203&amp;amp;face=0_0_400_203,https://scrap.kakaocdn.net/dn/lRvyB/dJMb88e84Rx/BNI790t4aQcMGrKGszOEI0/img.png?width=1392&amp;amp;height=523&amp;amp;face=0_0_1392_523&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/114&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/114&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dWdB9W/dJMb84qgXWC/Giz2KwYRqTn2WeK2KDaatK/img.gif?width=400&amp;amp;height=203&amp;amp;face=0_0_400_203,https://scrap.kakaocdn.net/dn/cm53lH/dJMb83SrmsD/w26ooHE74oYMXYlki4IuB0/img.gif?width=400&amp;amp;height=203&amp;amp;face=0_0_400_203,https://scrap.kakaocdn.net/dn/lRvyB/dJMb88e84Rx/BNI790t4aQcMGrKGszOEI0/img.png?width=1392&amp;amp;height=523&amp;amp;face=0_0_1392_523');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;UI 위젯 설계와 실시간 데이터 연동하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;UI 위젯 설계와 실시간 데이터 연동하기 | [언리얼 엔진 C++ (Unreal Engine C++)] UMG (User Widget) 위젯 기초 디자인 이해하기 1️⃣ HUD (Heads-Up Display)란?HUD는 게임 내에서 플레이어에게 정보를 제공하기 위&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://devcol.tistory.com/115&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Unreal Engine/UE 기초] - 게임 흐름에 맞춘 메뉴 UI 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781250833047&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;게임 흐름에 맞춘 메뉴 UI 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;게임 흐름에 맞춘 메뉴 UI 구현하기 게임 메뉴 UI 디자인하기 1️⃣ 메뉴 위젯 생성하고 버튼 추가하기그동안은 게임 중에 나오는 위젯을 설계했다면, 이번에는 게임을 일시적으로 중단하고 시작&quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/115&quot; data-og-url=&quot;https://devcol.tistory.com/115&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cnypNL/dJMb8VND17O/NES9Px6kak22EKADxEVxG0/img.png?width=800&amp;amp;height=381&amp;amp;face=382_181_484_283,https://scrap.kakaocdn.net/dn/crNzY2/dJMb8XSedNs/k5yo5UCKTeLvl14bEeQngk/img.png?width=800&amp;amp;height=381&amp;amp;face=382_181_484_283,https://scrap.kakaocdn.net/dn/dtHOID/dJMb8YXT4P6/yMLb5wLLfILhxfidutrQG1/img.png?width=1661&amp;amp;height=767&amp;amp;face=0_0_1661_767&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/115&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/115&quot;&gt; &amp;lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cnypNL/dJMb8VND&lt;/a&gt;&lt;/figure&gt;</description>
      <category>Unreal Engine/UE 기초</category>
      <category>C++</category>
      <category>Devlog</category>
      <category>Programming</category>
      <category>UE</category>
      <category>UE5</category>
      <category>Unreal engine</category>
      <category>게임 개발</category>
      <category>기초</category>
      <category>언리얼 엔진</category>
      <category>프로그래밍</category>
      <author>DevCol</author>
      <guid isPermaLink="true">https://devcol.tistory.com/117</guid>
      <comments>https://devcol.tistory.com/117#entry117comment</comments>
      <pubDate>Fri, 12 Jun 2026 17:03:12 +0900</pubDate>
    </item>
    <item>
      <title>UI 애니메이션 효과 및 3D 위젯 UI 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]</title>
      <link>https://devcol.tistory.com/116</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;UI 애니메이션 효과 및 3D 위젯 UI 구현하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a1&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;UI&amp;nbsp;애니메이션&amp;nbsp;효과&amp;nbsp;디자인하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣ &lt;b&gt;UMG와 Animation에 대해 이해하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;언리얼 엔진에서는 &lt;b&gt;UI&lt;/b&gt;를 만들 때 주로 &lt;b&gt;UMG&lt;/b&gt; (언리얼 모션 그래픽스, Unreal Motion Graphics)를 사용합니다. UMG에는 &lt;b&gt;Animation&lt;/b&gt; 기능이 탑재되어 있어, 예를 들어 버튼이 클릭될 때 색이 바뀌거나, 텍스트가 화면 위로 등장했다가 사라지는 등 다양한 연출을 쉽게 구현할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Animation 패널&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;UMG&lt;/b&gt; 에디터 내에서 메뉴 상단에서 Window - Animations를 클릭하면 애니메이션을 다루는 창이 뜹니다.&lt;/li&gt;
&lt;li&gt;UMG 에디터 왼쪽 하단 (기본 레이아웃 기준)에 위치한 패널입니다.&lt;/li&gt;
&lt;li&gt;여기서 새 애니메이션을 생성하거나, 이미 만든 애니메이션을 선택해 &lt;b&gt;타임라인&lt;/b&gt;을 확인할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;348&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3GKbQ/dJMcafGXRNS/jwks7Hzpae6WK59PYk8wE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3GKbQ/dJMcafGXRNS/jwks7Hzpae6WK59PYk8wE1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3GKbQ/dJMcafGXRNS/jwks7Hzpae6WK59PYk8wE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3GKbQ%2FdJMcafGXRNS%2Fjwks7Hzpae6WK59PYk8wE1%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;900&quot; height=&quot;348&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;348&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt;Keyframe(키 프레임)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 시간대에 UI 속성(크기, 위치, 투명도, 색상 등)을 어떻게 바꿀지를 기록하는 지점입니다.&lt;/li&gt;
&lt;li&gt;여러 개의 키 프레임을 연결하여 하나의 애니메이션 타임라인을 완성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZM64d/dJMcaiwTdSx/n2PoLOMGeQw6hvEs7WbEm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZM64d/dJMcaiwTdSx/n2PoLOMGeQw6hvEs7WbEm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZM64d/dJMcaiwTdSx/n2PoLOMGeQw6hvEs7WbEm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZM64d%2FdJMcaiwTdSx%2Fn2PoLOMGeQw6hvEs7WbEm1%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;900&quot; height=&quot;225&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;225&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;500&quot; data-origin-height=&quot;219&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cyS37v/dJMcaaezXp0/QYxFE2mu95XR6oJC92prM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cyS37v/dJMcaaezXp0/QYxFE2mu95XR6oJC92prM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cyS37v/dJMcaaezXp0/QYxFE2mu95XR6oJC92prM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcyS37v%2FdJMcaaezXp0%2FQYxFE2mu95XR6oJC92prM1%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;500&quot; height=&quot;219&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;219&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;UMG 위젯 애니메이팅 UE 공식 문서: &lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/animating-umg-widgets-in-unreal-engine?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dev.epicgames.com/documentation/unreal-engine/animating-umg-widgets-in-unreal-engine?lang=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781211914604&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Animating UMG Widgets in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&quot; data-og-description=&quot;How to create animated UI elements in UMG in Unreal Engine.&quot; data-og-host=&quot;dev.epicgames.com&quot; data-og-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/animating-umg-widgets-in-unreal-engine?lang=ko&quot; data-og-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/animating-umg-widgets-in-unreal-engine&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/rd2vM/dJMb8ZvJOo4/UrUb0nsHn81pX0PhIWbrA0/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/ThZ4q/dJMb8RkaqYQ/eHVkJlAV32xKooIUwnGxJK/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/eV0Ac/dJMb8RkaqYS/65RMek9vBTCJX4Him0MCb1/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/animating-umg-widgets-in-unreal-engine?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/animating-umg-widgets-in-unreal-engine?lang=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/rd2vM/dJMb8ZvJOo4/UrUb0nsHn81pX0PhIWbrA0/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/ThZ4q/dJMb8RkaqYQ/eHVkJlAV32xKooIUwnGxJK/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/eV0Ac/dJMb8RkaqYS/65RMek9vBTCJX4Him0MCb1/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Animating UMG Widgets in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;How to create animated UI elements in UMG in Unreal Engine.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.epicgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;UMG UI 디자이너 퀵스타트 가이드 UE 공식 문서: &lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/umg-ui-designer-quick-start-guide-in-unreal-engine?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dev.epicgames.com/documentation/unreal-engine/umg-ui-designer-quick-start-guide-in-unreal-engine?lang=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781211859875&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;UMG UI Designer Quick Start Guide in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&quot; data-og-description=&quot;Getting started with using Unreal Motion Graphics in Unreal Engine.&quot; data-og-host=&quot;dev.epicgames.com&quot; data-og-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/umg-ui-designer-quick-start-guide-in-unreal-engine?lang=ko&quot; data-og-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/umg-ui-designer-quick-start-guide-in-unreal-engine&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/f3aeP/dJMb9iIPbBk/htQCf7dIXPXAWYbxhexffk/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/brx2Tn/dJMb9hC9sEi/dCpqVgfsb1itCDRBhRmmD1/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/5eWSw/dJMb9bwaw8o/kcC0NYspFnUAZGxhjQn9p0/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/umg-ui-designer-quick-start-guide-in-unreal-engine?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/umg-ui-designer-quick-start-guide-in-unreal-engine?lang=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/f3aeP/dJMb9iIPbBk/htQCf7dIXPXAWYbxhexffk/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/brx2Tn/dJMb9hC9sEi/dCpqVgfsb1itCDRBhRmmD1/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/5eWSw/dJMb9bwaw8o/kcC0NYspFnUAZGxhjQn9p0/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;UMG UI Designer Quick Start Guide in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Getting started with using Unreal Motion Graphics in Unreal Engine.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.epicgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2️⃣ &lt;b&gt;Text 위젯에 애니메이션 적용하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이제 실제로 &lt;b&gt;&amp;ldquo;Game Over&amp;rdquo;&lt;/b&gt; 텍스트를 사용해 화면에 서서히 떠올랐다가 사라지는 연출을 만들어 봅시다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;위젯 블루프린트 내에서 텍스트 배치하기&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;WBP_MainMenu를 열어서 디자이너 화면에 TextBlock 하나를 추가해 이름을 GameOverText 라고 하고, 또 하나 TextBlock을 추가해 이름을 TotalScoreText 라고 합시다.&lt;/li&gt;
&lt;li&gt;두 TextBlock 모두 기본 Text를 설정해줍니다. (Content - Text 카테고리에 입력)&lt;/li&gt;
&lt;li&gt;평소에는 GameOverText와 TotalScoreText를 &lt;b&gt;Hidden&lt;/b&gt; (또는 Opacity=0) 상태로 배치합니다.&lt;/li&gt;
&lt;li&gt;이 텍스트가 게임 시작 시 바로 보이지 않도록, TextBlock의 &lt;b&gt;Visibility&lt;/b&gt;를 Hidden 으로 설정해 둡니다. 우리는 애니메이션으로 텍스트를 천천히 보이게 할 것이므로, 기본 상태를 숨기는 편이 좋습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;애니메이션 트랙 생성&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;에디터 왼쪽 하단의 &lt;b&gt;Animation&lt;/b&gt; 패널에서 + Animation 버튼을 클릭해 새 애니메이션을 만듭니다. &lt;b&gt;&amp;ldquo;Anim_TimeOver&amp;rdquo;&lt;/b&gt; 라고 이름을 붙입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;899&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eKxXpJ/dJMcaf7W9FO/GnD3uK9zg3KTjjUAo7kPj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eKxXpJ/dJMcaf7W9FO/GnD3uK9zg3KTjjUAo7kPj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eKxXpJ/dJMcaf7W9FO/GnD3uK9zg3KTjjUAo7kPj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeKxXpJ%2FdJMcaf7W9FO%2FGnD3uK9zg3KTjjUAo7kPj1%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;1170&quot; height=&quot;899&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;899&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아래쪽&amp;nbsp;타임라인&amp;nbsp;영역에서&amp;nbsp;Track을&amp;nbsp;추가할&amp;nbsp;수&amp;nbsp;있는데,&amp;nbsp;여기서&amp;nbsp;+&amp;nbsp;Add&amp;nbsp;를&amp;nbsp;클릭하고&amp;nbsp;GameOverText를&amp;nbsp;선택합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zbVEE/dJMcajvNfze/ZsEQRyj8QJtxl9Qn0XwA11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zbVEE/dJMcajvNfze/ZsEQRyj8QJtxl9Qn0XwA11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zbVEE/dJMcajvNfze/ZsEQRyj8QJtxl9Qn0XwA11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzbVEE%2FdJMcajvNfze%2FZsEQRyj8QJtxl9Qn0XwA11%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;576&quot; height=&quot;280&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;280&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Keyframe (키 프레임) 설정&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;추가된 GameOverText에서 옆에 희미하게 보이는 + 버튼을 누르면 추가할 수 있는 트랙들이 있습니다. 여기서 &lt;b&gt;Render Opacity&lt;/b&gt; (투명도)를 트랙에 추가하여, 이 값이 시간에 따라 어떻게 변하는지 기록할 수 있도록 설정합니다.&lt;/li&gt;
&lt;li&gt;시간 바를 옮기면서 각각 Render Opacity 값을 변경하면 자동으로 트랙에 Key가 등록됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;771&quot; data-origin-height=&quot;391&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/R2k3f/dJMcabxJuZj/DRIzt9qXXBzgPgARJUBwt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/R2k3f/dJMcabxJuZj/DRIzt9qXXBzgPgARJUBwt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/R2k3f/dJMcabxJuZj/DRIzt9qXXBzgPgARJUBwt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FR2k3f%2FdJMcabxJuZj%2FDRIzt9qXXBzgPgARJUBwt1%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;771&quot; height=&quot;391&quot; data-origin-width=&quot;771&quot; data-origin-height=&quot;391&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3️⃣ &lt;b&gt;애니메이션을 Blueprint 재생 함수로 묶어두기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;우리는 이 애니메이션을 재생하기 위해서는 그 동안의 작성한 게임 로직들 즉, C++에서 UMG의 애니메이션 재생이라는 흐름이 필요합니다. C++에서 블루프린트의 함수를 호출해야하는 반대 상황인것입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이벤트 그래프&lt;/b&gt;에서 PlayGameOverAnim &lt;b&gt;Function&lt;/b&gt;을 만들어줍니다.&lt;/li&gt;
&lt;li&gt;시작시 GameOverText을 visible로 처리하고, Play Animation을 연결합니다. 즉, &amp;ldquo;PlayTimeOverAnim&amp;rdquo;을 호출하면 &amp;ldquo;Anim_TimeOver&amp;rdquo; 애니메이션이 재생되도록 구성합니다.&lt;/li&gt;
&lt;li&gt;애니메이션 재생이 끝나면 자연스럽게 점수가 뜰 수 있도록, TotalScoreText 를 visible 처리를 하도록 연결해줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1027&quot; data-origin-height=&quot;339&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Uqt3M/dJMcahxZz3G/YQY0H62TiTmnc6sXmcMKuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Uqt3M/dJMcahxZz3G/YQY0H62TiTmnc6sXmcMKuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Uqt3M/dJMcahxZz3G/YQY0H62TiTmnc6sXmcMKuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUqt3M%2FdJMcahxZz3G%2FYQY0H62TiTmnc6sXmcMKuk%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;1027&quot; height=&quot;339&quot; data-origin-width=&quot;1027&quot; data-origin-height=&quot;339&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a4&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;게임 오버 UI 애니메이션 효과 추가하기&lt;/h3&gt;
&lt;pre id=&quot;code_1781216426205&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;MainPlayerController.h&quot;
#include &quot;EnhancedInputSubsystems.h&quot;
#include &quot;EnhancedInputSubsystems.h&quot; // Enhanced Input System의 Local Player Subsystem을 사용하기 위해 포함
#include &quot;MainGameState.h&quot;
#include &quot;MainGameInstance.h&quot;
#include &quot;Blueprint/UserWidget.h&quot;
#include &quot;Kismet/GameplayStatics.h&quot;
#include &quot;Components/TextBlock.h&quot;

// 어차피 블루프린트 상에서 전부 다 초기화를 하기 때문에 여기서는 전부 다 nullptr 처리
AMainPlayerController::AMainPlayerController()
	: InputMappingContext(nullptr),
	  MoveAction(nullptr),
	  JumpAction(nullptr),
	  LookAction(nullptr),
	  SprintAction(nullptr),
	  HUDWidgetClass(nullptr),
	  HUDWidgetInstance(nullptr),
	  MainMenuWidgetClass(nullptr),
	  MainMenuWidgetInstance(nullptr)

{
}

void AMainPlayerController::BeginPlay()
{
	Super::BeginPlay();

	// GetLocalPlayer():현재 PlayerController에 연결된 Local Player 객체를 가져옴     
	// Local Player 는 그 플레이어의 입력이나 화면 뷰 같은 것을 관리하는 어떤 객체
	if (ULocalPlayer* LocalPlayer = GetLocalPlayer())
	{
		// Local Player에서 EnhancedInputLocalPlayerSubsystem을 획득
		// UEnhancedInputLocalPlayerSubsystem: 입력 시스템을 관리 (IMC 추가 혹은 삭제하는 역할)
		if (UEnhancedInputLocalPlayerSubsystem* Subsystem =
			LocalPlayer-&amp;gt;GetSubsystem&amp;lt;UEnhancedInputLocalPlayerSubsystem&amp;gt;())
		{
			if (InputMappingContext)
			{
				// Subsystem을 통해 우리가 할당한 IMC를 활성화
				// 우선순위(Priority)는 0이 가장 높은 우선순위
				Subsystem-&amp;gt;AddMappingContext(InputMappingContext, 0);
			}
		}
	}

	FString CurrentMapName = GetWorld()-&amp;gt;GetMapName();
	if (CurrentMapName.Contains(&quot;MenuLevel&quot;))
	{
		ShowMainMenu(false);
	}


	/*// HUD 위젯 생성 및 표시
	if (HUDWidgetClass)
	{
		HUDWidgetInstance = CreateWidget&amp;lt;UUserWidget&amp;gt;(this, HUDWidgetClass);
		if (HUDWidgetInstance)
		{
			HUDWidgetInstance-&amp;gt;AddToViewport();
		}
	}

	AMainGameState* MainGameState = GetWorld() ? GetWorld()-&amp;gt;GetGameState&amp;lt;AMainGameState&amp;gt;() : nullptr;
	if (MainGameState)
	{
		MainGameState-&amp;gt;UpdateHUD();
	}*/
}

UUserWidget* AMainPlayerController::GetHUDWidget() const
{
	return HUDWidgetInstance;
}


// 메뉴 UI 표시
void AMainPlayerController::ShowMainMenu(bool bIsRestart)
{
	// HUD가 켜져 있다면 닫기
	if (HUDWidgetInstance)
	{
		HUDWidgetInstance-&amp;gt;RemoveFromParent();
		HUDWidgetInstance = nullptr;
	}

	// 이미 메뉴가 떠 있으면 제거
	if (MainMenuWidgetInstance)
	{
		MainMenuWidgetInstance-&amp;gt;RemoveFromParent();
		MainMenuWidgetInstance = nullptr;
	}

	// 메뉴 UI 생성
	if (MainMenuWidgetClass)
	{
		MainMenuWidgetInstance = CreateWidget&amp;lt;UUserWidget&amp;gt;(this, MainMenuWidgetClass);
		if (MainMenuWidgetInstance)
		{
			MainMenuWidgetInstance-&amp;gt;AddToViewport();

			bShowMouseCursor = true;
			SetInputMode(FInputModeUIOnly());
		}

		if (UTextBlock* ButtonText = Cast&amp;lt;UTextBlock&amp;gt;(
			MainMenuWidgetInstance-&amp;gt;GetWidgetFromName(TEXT(&quot;StartButtonText&quot;))))
		{
			if (bIsRestart)
			{
				ButtonText-&amp;gt;SetText(FText::FromString(TEXT(&quot;Restart&quot;)));
				
				
			}
			else
			{
				ButtonText-&amp;gt;SetText(FText::FromString(TEXT(&quot;Start&quot;)));
			}
		}
		
		if (bIsRestart)
		{
			UFunction* PlayAnimFunc = MainMenuWidgetInstance-&amp;gt;FindFunction(FName(&quot;PlayGameOverAnim&quot;));
			if (PlayAnimFunc)
			{
				MainMenuWidgetInstance-&amp;gt;ProcessEvent(PlayAnimFunc, nullptr);
			}

			if (UTextBlock* TotalScoreText = Cast&amp;lt;UTextBlock&amp;gt;(MainMenuWidgetInstance-&amp;gt;GetWidgetFromName(&quot;TotalScoreText&quot;)))
			{
				if (UMainGameInstance* MainGameInstance = Cast&amp;lt;UMainGameInstance&amp;gt;(UGameplayStatics::GetGameInstance(this)))
				{
					TotalScoreText-&amp;gt;SetText(FText::FromString(
						FString::Printf(TEXT(&quot;Total Score: %i&quot;), MainGameInstance-&amp;gt;TotalScore)
					));
				}
			}
		}
	}
}

// 게임 HUD 표시
void AMainPlayerController::ShowGameHUD()
{
	// HUD가 켜져 있다면 닫기
	if (HUDWidgetInstance)
	{
		HUDWidgetInstance-&amp;gt;RemoveFromParent();
		HUDWidgetInstance = nullptr;
	}

	// 이미 메뉴가 떠 있으면 제거
	if (MainMenuWidgetInstance)
	{
		MainMenuWidgetInstance-&amp;gt;RemoveFromParent();
		MainMenuWidgetInstance = nullptr;
	}

	if (HUDWidgetClass)
	{
		HUDWidgetInstance = CreateWidget&amp;lt;UUserWidget&amp;gt;(this, HUDWidgetClass);
		if (HUDWidgetInstance)
		{
			HUDWidgetInstance-&amp;gt;AddToViewport();

			bShowMouseCursor = false;
			SetInputMode(FInputModeGameOnly());

			AMainGameState* MainGameState = GetWorld() ? GetWorld()-&amp;gt;GetGameState&amp;lt;AMainGameState&amp;gt;() : nullptr;
			if (MainGameState)
			{
				MainGameState-&amp;gt;UpdateHUD();
			}
		}
	}
}

// 게임 시작 - BasicLevel 오픈, GameInstance 데이터 리셋
void AMainPlayerController::StartGame()
{
	if (UMainGameInstance* MainGameInstance = Cast&amp;lt;UMainGameInstance&amp;gt;(UGameplayStatics::GetGameInstance(this)))
	{
		MainGameInstance-&amp;gt;CurrentLevelIndex = 0;
		MainGameInstance-&amp;gt;TotalScore = 0;
	}

	UGameplayStatics::OpenLevel(GetWorld(), FName(&quot;BasicLevel&quot;));
	SetPause(false);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style2&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a4&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;WidgetComponent로 캐릭터 체력 표시하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣ &lt;b&gt;WidgetComponent 개념 이해하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;WidgetComponent란?&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UMG (언리얼 모션 그래픽스)로 만든 위젯 (텍스트, 이미지, 버튼 등)을 &lt;b&gt;3D 월드&lt;/b&gt;에 붙일 수 있게 해주는 컴포넌트입니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예: &amp;ldquo;NPC 머리 위 체력바&amp;rdquo;, &amp;ldquo;아이템 위에 &amp;lsquo;F 키를 누르세요&amp;rsquo; 텍스트&amp;rdquo; 등이 가능해집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;언리얼 엔진에서 &lt;b&gt;WidgetComponent&lt;/b&gt;를 사용하면, 2D로만 보이던 UI를 공간 내 특정 위치에 붙여 놓고, 카메라 각도에 따라 회전하거나 크기가 달라지는 모습을 만들 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;WidgetComponent&lt;/b&gt;는 Actor에 부착(Attach)할 수 있는 컴포넌트이며, 특정 UUserWidget(UMG Blueprint 클래스)을 3D 상에 표시하게 해 줍니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;보통은 SetWidgetSpace(EWidgetSpace::World)로 설정하여, 월드 공간에 UI가 존재하게 만듭니다.&lt;/li&gt;
&lt;li&gt;초기 상태에서 SetVisibility(false)로 해 두고, 플레이어가 가까이 왔을 때 SetVisibility(true)로 변경하여 표시할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2️⃣ &lt;b&gt;Widget Blueprint 준비하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Contents Browser에&lt;/b&gt;서 UI - Widgets 폴더에서 우클릭하고 User Interface &amp;gt; Widget Blueprint로 Parent는 User Widget을 선택해서 새 위젯 블루프린트를 하나 만듭니다. 이름으로 WBP_HP 라고 하겠습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3️⃣ &lt;b&gt;Character 클래스에 WidgetComponent 추가하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UI 는 보통 2D 인데 3D 화를 시켜서 사용할 경우 2가지 모드가 있습니다: 스크린 vs 월드
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스크린: UI 가 화면에 고정 되어 있음. (플레이어의 카메라 방향과 상관없이 항상 정면에서 보인다)&lt;/li&gt;
&lt;li&gt;월드: 월드의 캐릭터 움직임에 따라서 글씨도 같이 돌아가게 됩니다.&lt;/li&gt;
&lt;li&gt;여기서는 스크린으로 하겠습니다: OverheadWidget-&amp;gt;SetWidgetSpace(EWidgetSpace::Screen);&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781217975004&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pragma once

#include &quot;CoreMinimal.h&quot;
#include &quot;GameFramework/Character.h&quot;
#include &quot;MainCharacter.generated.h&quot;

// 미리 선언
// 전방 선언(Forward Declaration) 
class USpringArmComponent; // 스프링 암 관련 클래스 헤더
class UCameraComponent; // 카메라 관련 클래스 전방 선언
class UWidgetComponent;

// Enhanced Input에서 액션 값을 받을 때 사용하는 구조체
struct FInputActionValue;

UCLASS()
class BC_CH3_ASSIGNMENT_5_API AMainCharacter : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	AMainCharacter();
	
	virtual void BeginPlay() override;
	
	
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = &quot;Camera&quot;)
	USpringArmComponent* SpringArmComp  = nullptr;
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = &quot;Camera&quot;)
	UCameraComponent* CameraComp = nullptr;
	
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = &quot;UI&quot;)
	UWidgetComponent* OverheadWidget = nullptr;
	
	// 현재 체력을 가져오는 함수
	UFUNCTION(BlueprintPure, Category = &quot;Health&quot;)
	float GetHealth() const;
		
	// 체력을 회복시키는 함수
	UFUNCTION(BlueprintCallable, Category = &quot;Health&quot;)
	void AddHealth(float Amount);
	
protected:
	
	// === Variables ===
	// 최대 체력
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Health&quot;)
	float  MaxHealth;
	// 현재 체력
	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = &quot;Health&quot;)
	float  Health;
	
	// = Movements
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Movement&quot;)
	float NormalSpeed; // 기본 걷기 속도
	
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Movement&quot;)
	float SprintSpeedMultiplier;  // &quot;기본 속도&quot; 대비 몇 배로 빠르게 달릴지
	
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = &quot;Movement&quot;)
	float SprintSpeed; 	// 실제 스프린트 속도 SprintSpeed= NormalSpeed * SprintSpeedMultiplier
	
	
	// =====	
	
	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;	
	
	UFUNCTION()
	void Move(const FInputActionValue&amp;amp; value);
	
	UFUNCTION()
	void Look(const FInputActionValue&amp;amp; value);
	
	// on off 의 형태의 것들은 그냥 나눠 주는 것이 좋다
	// 왜냐하면 이전에는 세세하게 처리하기가 상당이 까다로웠는데
	// EnhancedInputSystem은 그것들을 매우 편하게 변경해주었기 때문에 왠만하면 나눠 주는 것이 좋다
	UFUNCTION()
	void StartJump(const FInputActionValue&amp;amp; value);
	UFUNCTION()
	void StopJump(const FInputActionValue&amp;amp; value);
	
	UFUNCTION()
	void StartSprint(const FInputActionValue&amp;amp; value);
	UFUNCTION()
	void StopSprint(const FInputActionValue&amp;amp; value);
	
	
	// 사망 처리 함수 (체력이 0 이하가 되었을 때 호출)
	UFUNCTION(BlueprintCallable, Category = &quot;Health&quot;)
	virtual void OnDeath();
	
	void UpdateOverheadHP();

	// 데미지 처리 함수 - 외부로부터 데미지를 받을 때 호출됨
	// 또는 AActor의 TakeDamage()를 오버라이드
	virtual float TakeDamage(
		float DamageAmount,
		struct FDamageEvent const&amp;amp; DamageEvent, // Damage 관련 추가 정보 (예: Skill 속성에 따른 반응) 
		AController* EventInstigator, //데미지를 발생 시킨 주체
		AActor* DamageCauser // 데미지를 일으킨 오브젝트
		) override;
	
};&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1781217986947&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;MainCharacter.h&quot;
#include &quot;EnhancedInputComponent.h&quot;
//#include &quot;InputActionValue.h&quot;
#include &quot;MainPlayerController.h&quot;

// 카메라, 스프링 암 실제 구현이 필요한 경우라서 include
// 전방 선언(Forward Declaration) 한것 여기서 (실질적으로 사용하는곳) 포함
#include &quot;Camera/CameraComponent.h&quot;
#include &quot;GameFramework/SpringArmComponent.h&quot; 

//
#include &quot;GameFramework/CharacterMovementComponent.h&quot; // GetCharacterMovement() 사용을 위해
#include &quot;GameFramework/Actor.h&quot;
#include &quot;Components/WidgetComponent.h&quot;
#include &quot;Components/TextBlock.h&quot;
//#include &quot;Kismet/GameplayStatics.h&quot;

AMainCharacter::AMainCharacter()
{ 	
	PrimaryActorTick.bCanEverTick = false;	
	
	// (1) 스프링 암 생성
	SpringArmComp = CreateDefaultSubobject&amp;lt;USpringArmComponent&amp;gt;(TEXT(&quot;SpringArm&quot;));
	// 스프링 암을 루트 컴포넌트 (CapsuleComponent)에 부착
	SpringArmComp-&amp;gt;SetupAttachment(RootComponent);
	// 캐릭터와 카메라 사이의 거리 기본값 300으로 설정
	SpringArmComp-&amp;gt;TargetArmLength = 300.0f;  
	// 컨트롤러 회전에 따라 스프링 암도 회전하도록 설정
	SpringArmComp-&amp;gt;bUsePawnControlRotation = true;  
	
	
	//

	// (2) 카메라 컴포넌트 생성
	CameraComp = CreateDefaultSubobject&amp;lt;UCameraComponent&amp;gt;(TEXT(&quot;Camera&quot;));
	// 스프링 암의 소켓 위치에 카메라를 부착
	CameraComp-&amp;gt;SetupAttachment(SpringArmComp, USpringArmComponent::SocketName);
	// 카메라는 스프링 암의 회전을 따르므로 PawnControlRotation은 꺼둠
	CameraComp-&amp;gt;bUsePawnControlRotation = false;
	
	OverheadWidget = CreateDefaultSubobject&amp;lt;UWidgetComponent&amp;gt;(TEXT(&quot;OverheadWidget&quot;));
	OverheadWidget-&amp;gt;SetupAttachment(GetMesh());
	OverheadWidget-&amp;gt;SetWidgetSpace(EWidgetSpace::Screen);
	
	
	// Movements &amp;amp; Sprint Speed	
	NormalSpeed = 600.0f;
	SprintSpeedMultiplier = 1.75f;
	SprintSpeed = NormalSpeed * SprintSpeedMultiplier;

	
	// #include &quot;GameFramework/CharacterMovementComponent.h&quot; 추가해야함
	// MaxWalkSpeed 변경시 캐릭터 이동속도가 즉시 변경
	GetCharacterMovement()-&amp;gt;MaxWalkSpeed = NormalSpeed;
	
	
	// 초기 체력 설정
	MaxHealth = 100.0f;
	Health = MaxHealth;
}

void AMainCharacter::BeginPlay()
{
	Super::BeginPlay();
	UpdateOverheadHP();
}

// Called to bind functionality to input
void AMainCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
	// Enhanced InputComponent로 캐스팅
    if (UEnhancedInputComponent* EnhancedInput = Cast&amp;lt;UEnhancedInputComponent&amp;gt;(PlayerInputComponent))
    {
        // IA를 가져오기 위해 현재 소유 중인 Controller를 AMainPlayerController로 캐스팅
        if (AMainPlayerController* PlayerController = Cast&amp;lt;AMainPlayerController&amp;gt;(GetController()))
        {
        	// null check
            if (PlayerController-&amp;gt;MoveAction)
            {
                // IA_Move 액션 키를 &quot;키를 누르고 있는 동안&quot; Move() 호출
                EnhancedInput-&amp;gt;BindAction(
                    PlayerController-&amp;gt;MoveAction,
                    ETriggerEvent::Triggered,
                    this,
                    &amp;amp;AMainCharacter::Move
                );
            }
            
            if (PlayerController-&amp;gt;JumpAction)
            {
                // IA_Jump 액션 키를 &quot;키를 누르고 있는 동안&quot; StartJump() 호출
                EnhancedInput-&amp;gt;BindAction(
                    PlayerController-&amp;gt;JumpAction,
                    ETriggerEvent::Triggered,
                    this,
                    &amp;amp;AMainCharacter::StartJump
                );
                
                // IA_Jump 액션 키에서 &quot;손을 뗀 순간&quot; StopJump() 호출
                EnhancedInput-&amp;gt;BindAction(
                    PlayerController-&amp;gt;JumpAction,
                    ETriggerEvent::Completed,
                    this,
                    &amp;amp;AMainCharacter::StopJump
                );
            }
            
            if (PlayerController-&amp;gt;LookAction)
            {
                // IA_Look 액션 마우스가 &quot;움직일 때&quot; Look() 호출
                EnhancedInput-&amp;gt;BindAction(
                    PlayerController-&amp;gt;LookAction,
                    ETriggerEvent::Triggered,
                    this,
                    &amp;amp;AMainCharacter::Look
                );
            }
            
            if (PlayerController-&amp;gt;SprintAction)
            {
                // IA_Sprint 액션 키를 &quot;누르고 있는 동안&quot; StartSprint() 호출
                EnhancedInput-&amp;gt;BindAction(
                    PlayerController-&amp;gt;SprintAction,
                    ETriggerEvent::Triggered,                   
                    this, 
                    &amp;amp;AMainCharacter::StartSprint
                );
                // IA_Sprint 액션 키에서 &quot;손을 뗀 순간&quot; StopSprint() 호출
                EnhancedInput-&amp;gt;BindAction(
                    PlayerController-&amp;gt;SprintAction, 
                    ETriggerEvent::Completed, 
                    this, 
                    &amp;amp;AMainCharacter::StopSprint
                );
            }    
        }
    }

}

void AMainCharacter::Move(const FInputActionValue&amp;amp; value)
{
	// 컨트롤러가 있어야 방향 계산이 가능
	if (!Controller) return;

	// Value는 Axis2D로 설정된 IA_Move의 입력값 (WASD)을 담고 있음
	// 예) (X=1, Y=0) &amp;rarr; 전진 / (X=-1, Y=0) &amp;rarr; 후진 / (X=0, Y=1) &amp;rarr; 오른쪽 / (X=0, Y=-1) &amp;rarr; 왼쪽
	const FVector2D MoveInput = value.Get&amp;lt;FVector2D&amp;gt;();

	// IsNearlyZero
	// 부동소수점들은 딱 0으로 안 떨어 질 수도 있기 때문에 작은 오차들은 0으로 처리 하기 위한 함수
	if (!FMath::IsNearlyZero(MoveInput.X))
	{		
		// 캐릭터가 바라보는 방향(정면)으로 X축 이동
		AddMovementInput(GetActorForwardVector(), MoveInput.X);
	}

	if (!FMath::IsNearlyZero(MoveInput.Y))
	{
		// 캐릭터의 오른쪽 방향으로 Y축 이동
		AddMovementInput(GetActorRightVector(), MoveInput.Y);
	}
}

void AMainCharacter::Look(const FInputActionValue&amp;amp; value)
{
	// 마우스의 X, Y 움직임을 2D 축으로 가져옴
	FVector2D LookInput = value.Get&amp;lt;FVector2D&amp;gt;();

	// X는 좌우 회전 (Yaw), Y는 상하 회전 (Pitch)
	// 좌우 회전
	AddControllerYawInput(LookInput.X);
	
	// 상하 회전
	// IA에서 반전해둔 상태
	// 여기엔 추후 변경 가능한 옵션 추가해주자
	AddControllerPitchInput(LookInput.Y);
}

void AMainCharacter::StartJump(const FInputActionValue&amp;amp; value)
{
	// Jump 함수는 Character가 기본 제공
	if (value.Get&amp;lt;bool&amp;gt;())
	{
		Jump();
	}
}
void AMainCharacter::StopJump(const FInputActionValue&amp;amp; value)
{	
	// StopJumping 함수도 Character가 기본 제공
	if (!value.Get&amp;lt;bool&amp;gt;())
	{
		StopJumping();
	}	
}

void AMainCharacter::StartSprint(const FInputActionValue&amp;amp; value)
{
	// Shift 키를 누른 순간 이 함수가 호출된다고 가정
	// 스프린트 속도를 적용
	if (GetCharacterMovement())
	{
		// 중간에 변경시 
		SprintSpeed = NormalSpeed * SprintSpeedMultiplier;		
		
		GetCharacterMovement()-&amp;gt;MaxWalkSpeed = SprintSpeed;
	}

}
void AMainCharacter::StopSprint(const FInputActionValue&amp;amp; value)
{
	// Shift 키를 뗀 순간 이 함수가 호출
	// 평상시 속도로 복귀
	if (GetCharacterMovement())
	{
		GetCharacterMovement()-&amp;gt;MaxWalkSpeed = NormalSpeed;
	}
}


float AMainCharacter::GetHealth() const
{
	return Health;
}

// 체력 회복 함수
void AMainCharacter::AddHealth(float  Amount)
{
	// 체력을 회복시킴. 최대 체력을 초과하지 않도록 제한함
	Health = FMath::Clamp(Health + Amount, 0.0f, MaxHealth);
	UpdateOverheadHP();
	//UE_LOG(LogTemp, Log, TEXT(&quot;Health increased to: %f&quot;), Health);
	
	/*
	if (GEngine)
	{ 
		GEngine-&amp;gt;AddOnScreenDebugMessage(
				-1, 2.f, FColor::Green,
				 TEXT(&quot;Health Increased to: %f&quot;), Health);
	}*/
}

// 데미지 처리 함수
float  AMainCharacter::TakeDamage(float  DamageAmount, FDamageEvent const&amp;amp; DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
	// 기본 데미지 처리 로직 호출 (필수는 아님)
	int32 ActualDamage = Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);

	// 체력을 데미지만큼 감소시키고, 0 이하로 떨어지지 않도록 Clamp
	Health = FMath::Clamp(Health - DamageAmount, 0.0f, MaxHealth);
	UpdateOverheadHP();
	//UE_LOG(LogTemp, Warning, TEXT(&quot;Health decreased to: %f&quot;), Health);
	/*if (GEngine)
	{ 
		GEngine-&amp;gt;AddOnScreenDebugMessage(
				-1, 2.f, FColor::Yellow,
				 TEXT(&quot;Health decreased to: %f&quot;), Health);
	}
	*/

	// 체력이 0 이하가 되면 사망 처리
	if (Health &amp;lt;= 0.0f)
	{
		OnDeath();
	}

	// 실제 적용된 데미지를 반환
	return ActualDamage;
}

// 사망 처리 함수
void AMainCharacter::OnDeath()
{
	//UE_LOG(LogTemp, Error, TEXT(&quot;Character is Dead!&quot;));
	if (GEngine)
	{ 
		GEngine-&amp;gt;AddOnScreenDebugMessage(
				-1, 2.f, FColor::Red,
				 TEXT(&quot;Character is Dead!&quot;));
	}

	// 사망 후 로직
}

void AMainCharacter::UpdateOverheadHP()
{
	if (!OverheadWidget) return;
	
	UUserWidget* OverheadWidgetInstance = OverheadWidget-&amp;gt;GetUserWidgetObject();
	if (!OverheadWidgetInstance) return;
	
	if (UTextBlock* HPText = Cast&amp;lt;UTextBlock&amp;gt;(OverheadWidgetInstance-&amp;gt;GetWidgetFromName(TEXT(&quot;OverHeadHP&quot;))))
	{
		HPText-&amp;gt;SetText(FText::FromString(FString::Printf(TEXT(&quot;%.0f / %.0f&quot;), Health, MaxHealth)));
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BP_MainCharacter 에 Overhead Widget이 잘 추가 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;453&quot; data-origin-height=&quot;430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zojuC/dJMcafNKV2l/tp7kf8KvZqoGYkwNTZ8duK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zojuC/dJMcafNKV2l/tp7kf8KvZqoGYkwNTZ8duK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zojuC/dJMcafNKV2l/tp7kf8KvZqoGYkwNTZ8duK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzojuC%2FdJMcafNKV2l%2Ftp7kf8KvZqoGYkwNTZ8duK%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;453&quot; height=&quot;430&quot; data-origin-width=&quot;453&quot; data-origin-height=&quot;430&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4️⃣ &lt;b&gt;Character 클래스에서 WidgetComponent 위치 설정&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;BP_MainCharacter 클래스에 들어가서 User Interface 카테고리에서 Widget Class를 WBP_HP로 설정해줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1639&quot; data-origin-height=&quot;619&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YMtzv/dJMcacpV3nM/RqKGzlPSiihmF7odtPk98K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YMtzv/dJMcacpV3nM/RqKGzlPSiihmF7odtPk98K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YMtzv/dJMcacpV3nM/RqKGzlPSiihmF7odtPk98K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYMtzv%2FdJMcacpV3nM%2FRqKGzlPSiihmF7odtPk98K%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;1639&quot; height=&quot;619&quot; data-origin-width=&quot;1639&quot; data-origin-height=&quot;619&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;432&quot; data-origin-height=&quot;107&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xznGj/dJMcahxZAXJ/XipSifaVOFDUKdbKkmLfa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xznGj/dJMcahxZAXJ/XipSifaVOFDUKdbKkmLfa1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xznGj/dJMcahxZAXJ/XipSifaVOFDUKdbKkmLfa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxznGj%2FdJMcahxZAXJ%2FXipSifaVOFDUKdbKkmLfa1%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;432&quot; height=&quot;107&quot; data-origin-width=&quot;432&quot; data-origin-height=&quot;107&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;WBP_HP 를 보면서 위치 조정 할때는 Space를 잠시 World로 하면 됩니다. (수정 후 Screen으로 하셔야 합니다)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5️⃣ &lt;b&gt;캐릭터 사망하였을 시 처리 로직 추가&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1781222785306&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;MainCharacter.h&quot;
#include &quot;EnhancedInputComponent.h&quot;
//#include &quot;InputActionValue.h&quot;
#include &quot;MainPlayerController.h&quot;

// 카메라, 스프링 암 실제 구현이 필요한 경우라서 include
// 전방 선언(Forward Declaration) 한것 여기서 (실질적으로 사용하는곳) 포함
#include &quot;Camera/CameraComponent.h&quot;
#include &quot;GameFramework/SpringArmComponent.h&quot; 

//
#include &quot;MainGameState.h&quot;
#include &quot;GameFramework/CharacterMovementComponent.h&quot; // GetCharacterMovement() 사용을 위해
#include &quot;GameFramework/Actor.h&quot;
#include &quot;Components/WidgetComponent.h&quot;
#include &quot;Components/TextBlock.h&quot;
//#include &quot;Kismet/GameplayStatics.h&quot;

AMainCharacter::AMainCharacter()
{ 	
	PrimaryActorTick.bCanEverTick = false;	
	
	// (1) 스프링 암 생성
	SpringArmComp = CreateDefaultSubobject&amp;lt;USpringArmComponent&amp;gt;(TEXT(&quot;SpringArm&quot;));
	// 스프링 암을 루트 컴포넌트 (CapsuleComponent)에 부착
	SpringArmComp-&amp;gt;SetupAttachment(RootComponent);
	// 캐릭터와 카메라 사이의 거리 기본값 300으로 설정
	SpringArmComp-&amp;gt;TargetArmLength = 300.0f;  
	// 컨트롤러 회전에 따라 스프링 암도 회전하도록 설정
	SpringArmComp-&amp;gt;bUsePawnControlRotation = true;  
	
	
	//

	// (2) 카메라 컴포넌트 생성
	CameraComp = CreateDefaultSubobject&amp;lt;UCameraComponent&amp;gt;(TEXT(&quot;Camera&quot;));
	// 스프링 암의 소켓 위치에 카메라를 부착
	CameraComp-&amp;gt;SetupAttachment(SpringArmComp, USpringArmComponent::SocketName);
	// 카메라는 스프링 암의 회전을 따르므로 PawnControlRotation은 꺼둠
	CameraComp-&amp;gt;bUsePawnControlRotation = false;
	
	OverheadWidget = CreateDefaultSubobject&amp;lt;UWidgetComponent&amp;gt;(TEXT(&quot;OverheadWidget&quot;));
	OverheadWidget-&amp;gt;SetupAttachment(GetMesh());
	OverheadWidget-&amp;gt;SetWidgetSpace(EWidgetSpace::Screen);
	
	
	// Movements &amp;amp; Sprint Speed	
	NormalSpeed = 600.0f;
	SprintSpeedMultiplier = 1.75f;
	SprintSpeed = NormalSpeed * SprintSpeedMultiplier;

	
	// #include &quot;GameFramework/CharacterMovementComponent.h&quot; 추가해야함
	// MaxWalkSpeed 변경시 캐릭터 이동속도가 즉시 변경
	GetCharacterMovement()-&amp;gt;MaxWalkSpeed = NormalSpeed;
	
	
	// 초기 체력 설정
	MaxHealth = 100.0f;
	Health = MaxHealth;
}

void AMainCharacter::BeginPlay()
{
	Super::BeginPlay();
	UpdateOverheadHP();
}

// Called to bind functionality to input
void AMainCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
	// Enhanced InputComponent로 캐스팅
    if (UEnhancedInputComponent* EnhancedInput = Cast&amp;lt;UEnhancedInputComponent&amp;gt;(PlayerInputComponent))
    {
        // IA를 가져오기 위해 현재 소유 중인 Controller를 AMainPlayerController로 캐스팅
        if (AMainPlayerController* PlayerController = Cast&amp;lt;AMainPlayerController&amp;gt;(GetController()))
        {
        	// null check
            if (PlayerController-&amp;gt;MoveAction)
            {
                // IA_Move 액션 키를 &quot;키를 누르고 있는 동안&quot; Move() 호출
                EnhancedInput-&amp;gt;BindAction(
                    PlayerController-&amp;gt;MoveAction,
                    ETriggerEvent::Triggered,
                    this,
                    &amp;amp;AMainCharacter::Move
                );
            }
            
            if (PlayerController-&amp;gt;JumpAction)
            {
                // IA_Jump 액션 키를 &quot;키를 누르고 있는 동안&quot; StartJump() 호출
                EnhancedInput-&amp;gt;BindAction(
                    PlayerController-&amp;gt;JumpAction,
                    ETriggerEvent::Triggered,
                    this,
                    &amp;amp;AMainCharacter::StartJump
                );
                
                // IA_Jump 액션 키에서 &quot;손을 뗀 순간&quot; StopJump() 호출
                EnhancedInput-&amp;gt;BindAction(
                    PlayerController-&amp;gt;JumpAction,
                    ETriggerEvent::Completed,
                    this,
                    &amp;amp;AMainCharacter::StopJump
                );
            }
            
            if (PlayerController-&amp;gt;LookAction)
            {
                // IA_Look 액션 마우스가 &quot;움직일 때&quot; Look() 호출
                EnhancedInput-&amp;gt;BindAction(
                    PlayerController-&amp;gt;LookAction,
                    ETriggerEvent::Triggered,
                    this,
                    &amp;amp;AMainCharacter::Look
                );
            }
            
            if (PlayerController-&amp;gt;SprintAction)
            {
                // IA_Sprint 액션 키를 &quot;누르고 있는 동안&quot; StartSprint() 호출
                EnhancedInput-&amp;gt;BindAction(
                    PlayerController-&amp;gt;SprintAction,
                    ETriggerEvent::Triggered,                   
                    this, 
                    &amp;amp;AMainCharacter::StartSprint
                );
                // IA_Sprint 액션 키에서 &quot;손을 뗀 순간&quot; StopSprint() 호출
                EnhancedInput-&amp;gt;BindAction(
                    PlayerController-&amp;gt;SprintAction, 
                    ETriggerEvent::Completed, 
                    this, 
                    &amp;amp;AMainCharacter::StopSprint
                );
            }    
        }
    }

}

void AMainCharacter::Move(const FInputActionValue&amp;amp; value)
{
	// 컨트롤러가 있어야 방향 계산이 가능
	if (!Controller) return;

	// Value는 Axis2D로 설정된 IA_Move의 입력값 (WASD)을 담고 있음
	// 예) (X=1, Y=0) &amp;rarr; 전진 / (X=-1, Y=0) &amp;rarr; 후진 / (X=0, Y=1) &amp;rarr; 오른쪽 / (X=0, Y=-1) &amp;rarr; 왼쪽
	const FVector2D MoveInput = value.Get&amp;lt;FVector2D&amp;gt;();

	// IsNearlyZero
	// 부동소수점들은 딱 0으로 안 떨어 질 수도 있기 때문에 작은 오차들은 0으로 처리 하기 위한 함수
	if (!FMath::IsNearlyZero(MoveInput.X))
	{		
		// 캐릭터가 바라보는 방향(정면)으로 X축 이동
		AddMovementInput(GetActorForwardVector(), MoveInput.X);
	}

	if (!FMath::IsNearlyZero(MoveInput.Y))
	{
		// 캐릭터의 오른쪽 방향으로 Y축 이동
		AddMovementInput(GetActorRightVector(), MoveInput.Y);
	}
}

void AMainCharacter::Look(const FInputActionValue&amp;amp; value)
{
	// 마우스의 X, Y 움직임을 2D 축으로 가져옴
	FVector2D LookInput = value.Get&amp;lt;FVector2D&amp;gt;();

	// X는 좌우 회전 (Yaw), Y는 상하 회전 (Pitch)
	// 좌우 회전
	AddControllerYawInput(LookInput.X);
	
	// 상하 회전
	// IA에서 반전해둔 상태
	// 여기엔 추후 변경 가능한 옵션 추가해주자
	AddControllerPitchInput(LookInput.Y);
}

void AMainCharacter::StartJump(const FInputActionValue&amp;amp; value)
{
	// Jump 함수는 Character가 기본 제공
	if (value.Get&amp;lt;bool&amp;gt;())
	{
		Jump();
	}
}
void AMainCharacter::StopJump(const FInputActionValue&amp;amp; value)
{	
	// StopJumping 함수도 Character가 기본 제공
	if (!value.Get&amp;lt;bool&amp;gt;())
	{
		StopJumping();
	}	
}

void AMainCharacter::StartSprint(const FInputActionValue&amp;amp; value)
{
	// Shift 키를 누른 순간 이 함수가 호출된다고 가정
	// 스프린트 속도를 적용
	if (GetCharacterMovement())
	{
		// 중간에 변경시 
		SprintSpeed = NormalSpeed * SprintSpeedMultiplier;		
		
		GetCharacterMovement()-&amp;gt;MaxWalkSpeed = SprintSpeed;
	}

}
void AMainCharacter::StopSprint(const FInputActionValue&amp;amp; value)
{
	// Shift 키를 뗀 순간 이 함수가 호출
	// 평상시 속도로 복귀
	if (GetCharacterMovement())
	{
		GetCharacterMovement()-&amp;gt;MaxWalkSpeed = NormalSpeed;
	}
}


float AMainCharacter::GetHealth() const
{
	return Health;
}

// 체력 회복 함수
void AMainCharacter::AddHealth(float  Amount)
{
	// 체력을 회복시킴. 최대 체력을 초과하지 않도록 제한함
	Health = FMath::Clamp(Health + Amount, 0.0f, MaxHealth);
	UpdateOverheadHP();
	//UE_LOG(LogTemp, Log, TEXT(&quot;Health increased to: %f&quot;), Health);
	
	/*
	if (GEngine)
	{ 
		GEngine-&amp;gt;AddOnScreenDebugMessage(
				-1, 2.f, FColor::Green,
				 TEXT(&quot;Health Increased to: %f&quot;), Health);
	}*/
}

// 데미지 처리 함수
float  AMainCharacter::TakeDamage(float  DamageAmount, FDamageEvent const&amp;amp; DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
	// 기본 데미지 처리 로직 호출 (필수는 아님)
	int32 ActualDamage = Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);

	// 체력을 데미지만큼 감소시키고, 0 이하로 떨어지지 않도록 Clamp
	Health = FMath::Clamp(Health - DamageAmount, 0.0f, MaxHealth);
	UpdateOverheadHP();
	//UE_LOG(LogTemp, Warning, TEXT(&quot;Health decreased to: %f&quot;), Health);
	/*if (GEngine)
	{ 
		GEngine-&amp;gt;AddOnScreenDebugMessage(
				-1, 2.f, FColor::Yellow,
				 TEXT(&quot;Health decreased to: %f&quot;), Health);
	}
	*/

	// 체력이 0 이하가 되면 사망 처리
	if (Health &amp;lt;= 0.0f)
	{
		OnDeath();
	}

	// 실제 적용된 데미지를 반환
	return ActualDamage;
}

// 사망 처리 함수
void AMainCharacter::OnDeath()
{
	//UE_LOG(LogTemp, Error, TEXT(&quot;Character is Dead!&quot;));
	/*if (GEngine)
	{ 
		GEngine-&amp;gt;AddOnScreenDebugMessage(
				-1, 2.f, FColor::Red,
				 TEXT(&quot;Character is Dead!&quot;));
	}*/
	
	AMainGameState* MainGameState = GetWorld() ? GetWorld()-&amp;gt;GetGameState&amp;lt;AMainGameState&amp;gt;() : nullptr;
	if (MainGameState)
	{
		MainGameState-&amp;gt;OnGameOver();
	}
}

void AMainCharacter::UpdateOverheadHP()
{
	if (!OverheadWidget) return;
	
	UUserWidget* OverheadWidgetInstance = OverheadWidget-&amp;gt;GetUserWidgetObject();
	if (!OverheadWidgetInstance) return;
	
	if (UTextBlock* HPText = Cast&amp;lt;UTextBlock&amp;gt;(OverheadWidgetInstance-&amp;gt;GetWidgetFromName(TEXT(&quot;OverHeadHP&quot;))))
	{
		HPText-&amp;gt;SetText(FText::FromString(FString::Printf(TEXT(&quot;%.0f / %.0f&quot;), Health, MaxHealth)));
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1781222819607&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;MainGameState.h&quot;
#include &quot;MainGameInstance.h&quot;
#include &quot;MainPlayerController.h&quot;
#include &quot;Kismet/GameplayStatics.h&quot;
#include &quot;SpawnVolume.h&quot;
#include &quot;CoinItem.h&quot;
#include &quot;Components/TextBlock.h&quot;
#include &quot;Blueprint/UserWidget.h&quot;

AMainGameState::AMainGameState()
{
	Score = 0;
	SpawnedCoinCount = 0;
	CollectedCoinCount = 0;
	LevelDuration = 3.0f; // 한 레벨당 30초
	CurrentLevelIndex = 0;
	MaxLevels = 3;
}

void AMainGameState::BeginPlay()
{
	Super::BeginPlay();

	// 게임 시작 시 첫 레벨부터 진행
	StartLevel();
	
	//UpdateHUD();
	
	GetWorldTimerManager().SetTimer(
			HUDUpdateTimerHandle,
			this,
			&amp;amp;AMainGameState::UpdateHUD,
			0.1f,
			true
		);
}

int32 AMainGameState::GetScore() const
{
	return Score;
}

void AMainGameState::AddScore(int32 Amount)
{
	if (UGameInstance* GameInstance = GetGameInstance())
	{
		UMainGameInstance* MainGameInstance = Cast&amp;lt;UMainGameInstance&amp;gt;(GameInstance);
		if (MainGameInstance)
		{
			MainGameInstance-&amp;gt;AddToScore(Amount);
		}
	}
}


void AMainGameState::StartLevel()
{
	if (APlayerController* PlayerController = GetWorld()-&amp;gt;GetFirstPlayerController())
	{
		if (AMainPlayerController* MainPlayerController = Cast&amp;lt;AMainPlayerController&amp;gt;(PlayerController))
		{
			MainPlayerController-&amp;gt;ShowGameHUD();
		}
	}

	
	if (UGameInstance* GameInstance = GetGameInstance())
	{
		UMainGameInstance* MainGameInstance = Cast&amp;lt;UMainGameInstance&amp;gt;(GameInstance);
		if (MainGameInstance)
		{
			CurrentLevelIndex = MainGameInstance-&amp;gt;CurrentLevelIndex;
		}
	}

	// 레벨 시작 시, 코인 개수 초기화
	SpawnedCoinCount = 0;
	CollectedCoinCount = 0;
	// 현재 맵에 배치된 모든 SpawnVolume을 찾아 아이템 40개를 스폰
	TArray&amp;lt;AActor*&amp;gt; FoundVolumes;
	UGameplayStatics::GetAllActorsOfClass(GetWorld(), ASpawnVolume::StaticClass(), FoundVolumes);
	const int32 ItemToSpawn = 40;

	for (int32 i = 0; i &amp;lt; ItemToSpawn; i++)
	{
		if (FoundVolumes.Num() &amp;gt; 0)
		{
			ASpawnVolume* SpawnVolume = Cast&amp;lt;ASpawnVolume&amp;gt;(FoundVolumes[0]);
			if (SpawnVolume)
			{
				AActor* SpawnedActor = SpawnVolume-&amp;gt;SpawnRandomItem();
				// 만약 스폰된 액터가 코인 타입이라면 SpawnedCoinCount 증가
				if (SpawnedActor &amp;amp;&amp;amp; SpawnedActor-&amp;gt;IsA(ACoinItem::StaticClass()))
				{
					SpawnedCoinCount++;
				}
			}
		}
	}
	// 30초 후에 OnLevelTimeUp()가 호출되도록 타이머 설정
	GetWorldTimerManager().SetTimer(
		LevelTimerHandle,
		this,
		&amp;amp;AMainGameState::OnLevelTimeUp,
		LevelDuration,
		false
	);
	/*UE_LOG(LogTemp, Warning, TEXT(&quot;Level %d Start!, Spawned %d coin&quot;),
	       CurrentLevelIndex + 1,
	       SpawnedCoinCount);*/
}

void AMainGameState::OnLevelTimeUp()
{
	// 시간이 다 되면 레벨을 종료
	EndLevel();
}

void AMainGameState::OnCoinCollected()
{
	CollectedCoinCount++;

	/*UE_LOG(LogTemp, Warning, TEXT(&quot;Coin Collected: %d / %d&quot;),
	       CollectedCoinCount,
	       SpawnedCoinCount)*/

	// 현재 레벨에서 스폰된 코인을 전부 주웠다면 즉시 레벨 종료
	if (SpawnedCoinCount &amp;gt; 0 &amp;amp;&amp;amp; CollectedCoinCount &amp;gt;= SpawnedCoinCount)
	{
		EndLevel();
	}
}

void AMainGameState::EndLevel()
{	
	
	// 타이머 해제
	GetWorldTimerManager().ClearTimer(LevelTimerHandle);
	// 다음 레벨 인덱스로
	//CurrentLevelIndex++;
	
	if (UGameInstance* GameInstance = GetGameInstance())
	{
		UMainGameInstance* MainGameInstance = Cast&amp;lt;UMainGameInstance&amp;gt;(GameInstance);
		if (MainGameInstance)
		{
			AddScore(Score);
			CurrentLevelIndex++;
			MainGameInstance-&amp;gt;CurrentLevelIndex = CurrentLevelIndex;
		}
	}

	// 모든 레벨을 다 돌았다면 게임 오버 처리
	if (CurrentLevelIndex &amp;gt;= MaxLevels)
	{
		OnGameOver();
		return;
	}

	// 레벨 맵 이름이 있다면 해당 맵 불러오기
	if (LevelMapNames.IsValidIndex(CurrentLevelIndex))
	{
		UGameplayStatics::OpenLevel(GetWorld(), LevelMapNames[CurrentLevelIndex]);
	}
	else
	{
		// 맵 이름이 없으면 게임오버
		OnGameOver();
	}
}

void AMainGameState::OnGameOver()
{
	if (APlayerController* PlayerController = GetWorld()-&amp;gt;GetFirstPlayerController())
	{
		if (AMainPlayerController* MainPlayerController = Cast&amp;lt;AMainPlayerController&amp;gt;(PlayerController))
		{
			MainPlayerController-&amp;gt;SetPause(true);
			MainPlayerController-&amp;gt;ShowMainMenu(true);
		}
	}
	
	//UpdateHUD();
	//UE_LOG(LogTemp, Warning, TEXT(&quot;Game Over!!&quot;));
	
}

void AMainGameState::UpdateHUD()
{
	if (APlayerController* PlayerController = GetWorld()-&amp;gt;GetFirstPlayerController())
	{
		AMainPlayerController* MainPlayerController = Cast&amp;lt;AMainPlayerController&amp;gt;(PlayerController);
		{
			if (UUserWidget* HUDWidget = MainPlayerController-&amp;gt;GetHUDWidget())
			{
				// requires
				// #include &quot;Components/TextBlock.h&quot;
				// #include &quot;Blueprint/UserWidget.h&quot;
				
				//추후 변경 방안 
				// UPROPERTY(meta = (BindWidget))
				// class UButton* MyAwesomeButton;
				if (UTextBlock* TimeText = Cast&amp;lt;UTextBlock&amp;gt;(HUDWidget-&amp;gt;GetWidgetFromName(TEXT(&quot;Time&quot;))))
				{
					float RemainingTime = GetWorldTimerManager().GetTimerRemaining(LevelTimerHandle);
					TimeText-&amp;gt;SetText(FText::FromString(FString::Printf(TEXT(&quot;Time: %.1f&quot;), RemainingTime)));
				}
				
				//
				if (UTextBlock* ScoreText = Cast&amp;lt;UTextBlock&amp;gt;(HUDWidget-&amp;gt;GetWidgetFromName(TEXT(&quot;Score&quot;))))
				{
					if (UGameInstance* GameInstance = GetGameInstance())
					{
						UMainGameInstance* MainGameInstance = Cast&amp;lt;UMainGameInstance&amp;gt;(GameInstance);
						if (MainGameInstance)
						{
							ScoreText-&amp;gt;SetText(FText::FromString(FString::Printf(TEXT(&quot;Score: %i&quot;), MainGameInstance-&amp;gt;TotalScore)));
						}
					}
				}
				
				if (UTextBlock* LevelIndexText = Cast&amp;lt;UTextBlock&amp;gt;(HUDWidget-&amp;gt;GetWidgetFromName(TEXT(&quot;Level&quot;))))
				{
					LevelIndexText-&amp;gt;SetText(FText::FromString(FString::Printf(TEXT(&quot;Level: %d&quot;), CurrentLevelIndex + 1)));
				}
			}
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1781222840255&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;MainPlayerController.h&quot;
#include &quot;EnhancedInputSubsystems.h&quot;
#include &quot;EnhancedInputSubsystems.h&quot; // Enhanced Input System의 Local Player Subsystem을 사용하기 위해 포함
#include &quot;MainGameState.h&quot;
#include &quot;MainGameInstance.h&quot;
#include &quot;Blueprint/UserWidget.h&quot;
#include &quot;Kismet/GameplayStatics.h&quot;
#include &quot;Components/TextBlock.h&quot;

// 어차피 블루프린트 상에서 전부 다 초기화를 하기 때문에 여기서는 전부 다 nullptr 처리
AMainPlayerController::AMainPlayerController()
	: InputMappingContext(nullptr),
	  MoveAction(nullptr),
	  JumpAction(nullptr),
	  LookAction(nullptr),
	  SprintAction(nullptr),
	  HUDWidgetClass(nullptr),
	  HUDWidgetInstance(nullptr),
	  MainMenuWidgetClass(nullptr),
	  MainMenuWidgetInstance(nullptr)

{
}

void AMainPlayerController::BeginPlay()
{
	Super::BeginPlay();

	// GetLocalPlayer():현재 PlayerController에 연결된 Local Player 객체를 가져옴     
	// Local Player 는 그 플레이어의 입력이나 화면 뷰 같은 것을 관리하는 어떤 객체
	if (ULocalPlayer* LocalPlayer = GetLocalPlayer())
	{
		// Local Player에서 EnhancedInputLocalPlayerSubsystem을 획득
		// UEnhancedInputLocalPlayerSubsystem: 입력 시스템을 관리 (IMC 추가 혹은 삭제하는 역할)
		if (UEnhancedInputLocalPlayerSubsystem* Subsystem =
			LocalPlayer-&amp;gt;GetSubsystem&amp;lt;UEnhancedInputLocalPlayerSubsystem&amp;gt;())
		{
			if (InputMappingContext)
			{
				// Subsystem을 통해 우리가 할당한 IMC를 활성화
				// 우선순위(Priority)는 0이 가장 높은 우선순위
				Subsystem-&amp;gt;AddMappingContext(InputMappingContext, 0);
			}
		}
	}

	FString CurrentMapName = GetWorld()-&amp;gt;GetMapName();
	if (CurrentMapName.Contains(&quot;MenuLevel&quot;))
	{
		ShowMainMenu(false);
	}


	/*// HUD 위젯 생성 및 표시
	if (HUDWidgetClass)
	{
		HUDWidgetInstance = CreateWidget&amp;lt;UUserWidget&amp;gt;(this, HUDWidgetClass);
		if (HUDWidgetInstance)
		{
			HUDWidgetInstance-&amp;gt;AddToViewport();
		}
	}

	AMainGameState* MainGameState = GetWorld() ? GetWorld()-&amp;gt;GetGameState&amp;lt;AMainGameState&amp;gt;() : nullptr;
	if (MainGameState)
	{
		MainGameState-&amp;gt;UpdateHUD();
	}*/
}

UUserWidget* AMainPlayerController::GetHUDWidget() const
{
	return HUDWidgetInstance;
}


// 메뉴 UI 표시
void AMainPlayerController::ShowMainMenu(bool bIsRestart)
{
	// HUD가 켜져 있다면 닫기
	if (HUDWidgetInstance)
	{
		HUDWidgetInstance-&amp;gt;RemoveFromParent();
		HUDWidgetInstance = nullptr;
	}

	// 이미 메뉴가 떠 있으면 제거
	if (MainMenuWidgetInstance)
	{
		MainMenuWidgetInstance-&amp;gt;RemoveFromParent();
		MainMenuWidgetInstance = nullptr;
	}

	// 메뉴 UI 생성
	if (MainMenuWidgetClass)
	{
		MainMenuWidgetInstance = CreateWidget&amp;lt;UUserWidget&amp;gt;(this, MainMenuWidgetClass);
		if (MainMenuWidgetInstance)
		{
			MainMenuWidgetInstance-&amp;gt;AddToViewport();

			bShowMouseCursor = true;
			SetInputMode(FInputModeUIOnly());
		}

		if (UTextBlock* ButtonText = Cast&amp;lt;UTextBlock&amp;gt;(
			MainMenuWidgetInstance-&amp;gt;GetWidgetFromName(TEXT(&quot;StartButtonText&quot;))))
		{
			if (bIsRestart)
			{
				ButtonText-&amp;gt;SetText(FText::FromString(TEXT(&quot;Restart&quot;)));
				
				
			}
			else
			{
				ButtonText-&amp;gt;SetText(FText::FromString(TEXT(&quot;Start&quot;)));
			}
		}
		
		if (bIsRestart)
		{
			UFunction* PlayAnimFunc = MainMenuWidgetInstance-&amp;gt;FindFunction(FName(&quot;PlayGameOverAnim&quot;));
			if (PlayAnimFunc)
			{
				MainMenuWidgetInstance-&amp;gt;ProcessEvent(PlayAnimFunc, nullptr);
			}

			if (UTextBlock* TotalScoreText = Cast&amp;lt;UTextBlock&amp;gt;(MainMenuWidgetInstance-&amp;gt;GetWidgetFromName(&quot;TotalScoreText&quot;)))
			{
				if (UMainGameInstance* MainGameInstance = Cast&amp;lt;UMainGameInstance&amp;gt;(UGameplayStatics::GetGameInstance(this)))
				{
					TotalScoreText-&amp;gt;SetText(FText::FromString(
						FString::Printf(TEXT(&quot;Total Score: %i&quot;), MainGameInstance-&amp;gt;TotalScore)
					));
				}
			}
		}
	}
}

// 게임 HUD 표시
void AMainPlayerController::ShowGameHUD()
{
	// HUD가 켜져 있다면 닫기
	if (HUDWidgetInstance)
	{
		HUDWidgetInstance-&amp;gt;RemoveFromParent();
		HUDWidgetInstance = nullptr;
	}

	// 이미 메뉴가 떠 있으면 제거
	if (MainMenuWidgetInstance)
	{
		MainMenuWidgetInstance-&amp;gt;RemoveFromParent();
		MainMenuWidgetInstance = nullptr;
	}

	if (HUDWidgetClass)
	{
		HUDWidgetInstance = CreateWidget&amp;lt;UUserWidget&amp;gt;(this, HUDWidgetClass);
		if (HUDWidgetInstance)
		{
			HUDWidgetInstance-&amp;gt;AddToViewport();

			bShowMouseCursor = false;
			SetInputMode(FInputModeGameOnly());

			AMainGameState* MainGameState = GetWorld() ? GetWorld()-&amp;gt;GetGameState&amp;lt;AMainGameState&amp;gt;() : nullptr;
			if (MainGameState)
			{
				MainGameState-&amp;gt;UpdateHUD();
			}
		}
	}
}

// 게임 시작 - BasicLevel 오픈, GameInstance 데이터 리셋
void AMainPlayerController::StartGame()
{
	if (UMainGameInstance* MainGameInstance = Cast&amp;lt;UMainGameInstance&amp;gt;(UGameplayStatics::GetGameInstance(this)))
	{
		MainGameInstance-&amp;gt;CurrentLevelIndex = 0;
		MainGameInstance-&amp;gt;TotalScore = 0;
	}

	UGameplayStatics::OpenLevel(GetWorld(), FName(&quot;BasicLevel&quot;));
	SetPause(false);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style2&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;204&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxInpZ/dJMcai4Et4P/NHd1rV4yxCRqBjIVmE7ht0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxInpZ/dJMcai4Et4P/NHd1rV4yxCRqBjIVmE7ht0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxInpZ/dJMcai4Et4P/NHd1rV4yxCRqBjIVmE7ht0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bxInpZ/dJMcai4Et4P/NHd1rV4yxCRqBjIVmE7ht0/img.gif&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;500&quot; height=&quot;255&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;204&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;h3 id=&quot;a4&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;0&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&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;h3 id=&quot;a5&quot; style=&quot;background: linear-gradient(to right, #00a0e9, #e4007f); color: #ffffff; font-weight: bold; margin: 0.5em 0em; padding: 15px 20px; border-radius: 20px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;Conclustion&lt;/span&gt;&lt;/b&gt;&lt;/h3&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #5b63fb; font-weight: bold; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;추천&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UMG 위젯 애니메이팅 UE 공식 문서: &lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/animating-umg-widgets-in-unreal-engine?lang=ko&quot;&gt;https://dev.epicgames.com/documentation/unreal-engine/animating-umg-widgets-in-unreal-engine?lang=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781211915095&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Animating UMG Widgets in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&quot; data-og-description=&quot;How to create animated UI elements in UMG in Unreal Engine.&quot; data-og-host=&quot;dev.epicgames.com&quot; data-og-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/animating-umg-widgets-in-unreal-engine?lang=ko&quot; data-og-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/animating-umg-widgets-in-unreal-engine&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/rd2vM/dJMb8ZvJOo4/UrUb0nsHn81pX0PhIWbrA0/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/ThZ4q/dJMb8RkaqYQ/eHVkJlAV32xKooIUwnGxJK/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/eV0Ac/dJMb8RkaqYS/65RMek9vBTCJX4Him0MCb1/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/animating-umg-widgets-in-unreal-engine?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/animating-umg-widgets-in-unreal-engine?lang=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/rd2vM/dJMb8ZvJOo4/UrUb0nsHn81pX0PhIWbrA0/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/ThZ4q/dJMb8RkaqYQ/eHVkJlAV32xKooIUwnGxJK/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/eV0Ac/dJMb8RkaqYS/65RMek9vBTCJX4Him0MCb1/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Animating UMG Widgets in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;How to create animated UI elements in UMG in Unreal Engine.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.epicgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UMG UI 디자이너 퀵스타트 가이드 UE 공식 문서: &lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/umg-ui-designer-quick-start-guide-in-unreal-engine?lang=ko&quot;&gt;https://dev.epicgames.com/documentation/unreal-engine/umg-ui-designer-quick-start-guide-in-unreal-engine?lang=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781211869580&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;UMG UI Designer Quick Start Guide in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&quot; data-og-description=&quot;Getting started with using Unreal Motion Graphics in Unreal Engine.&quot; data-og-host=&quot;dev.epicgames.com&quot; data-og-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/umg-ui-designer-quick-start-guide-in-unreal-engine?lang=ko&quot; data-og-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/umg-ui-designer-quick-start-guide-in-unreal-engine&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/f3aeP/dJMb9iIPbBk/htQCf7dIXPXAWYbxhexffk/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/brx2Tn/dJMb9hC9sEi/dCpqVgfsb1itCDRBhRmmD1/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/5eWSw/dJMb9bwaw8o/kcC0NYspFnUAZGxhjQn9p0/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/umg-ui-designer-quick-start-guide-in-unreal-engine?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/umg-ui-designer-quick-start-guide-in-unreal-engine?lang=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/f3aeP/dJMb9iIPbBk/htQCf7dIXPXAWYbxhexffk/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/brx2Tn/dJMb9hC9sEi/dCpqVgfsb1itCDRBhRmmD1/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/5eWSw/dJMb9bwaw8o/kcC0NYspFnUAZGxhjQn9p0/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;UMG UI Designer Quick Start Guide in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Getting started with using Unreal Motion Graphics in Unreal Engine.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.epicgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/107&quot;&gt;[Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781222923708&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;인터페이스 기반 아이템 클래스 설계하기 인터페이스 이해하기1️⃣ 인터페이스란?인터페이스 (Interface)란 클래스 (또는 오브젝트)가 반드시 구현해야 할 함수 목록만을 미리 정의해 두고, 실제 &quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/107&quot; data-og-url=&quot;https://devcol.tistory.com/107&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/i8Eu8/dJMb86O97yQ/KrdVAwlbKoqPioBFaTZrp1/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/RHrb0/dJMb81f00nk/GXBARX8wUIPEhZfFsbJ0w0/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/dXIyx2/dJMb896b3nW/NsulI0BwU9V1lIiWOJWOTk/img.png?width=997&amp;amp;height=544&amp;amp;face=0_0_997_544&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/107&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/107&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/i8Eu8/dJMb86O97yQ/KrdVAwlbKoqPioBFaTZrp1/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/RHrb0/dJMb81f00nk/GXBARX8wUIPEhZfFsbJ0w0/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/dXIyx2/dJMb896b3nW/NsulI0BwU9V1lIiWOJWOTk/img.png?width=997&amp;amp;height=544&amp;amp;face=0_0_997_544');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스 기반 아이템 클래스 설계하기 인터페이스 이해하기1️⃣ 인터페이스란?인터페이스 (Interface)란 클래스 (또는 오브젝트)가 반드시 구현해야 할 함수 목록만을 미리 정의해 두고, 실제&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://devcol.tistory.com/108&quot;&gt;[Unreal Engine/UE 기초] - 충돌 이벤트로 획득되는 아이템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781222925392&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;충돌 이벤트로 획득되는 아이템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;충돌 이벤트로 획득되는 아이템 구현하기 이전 포스팅에서는 클래스 구조만 짜고 로직은 비여있던 상태.이전 포스팅: [Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼 &quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/108&quot; data-og-url=&quot;https://devcol.tistory.com/108&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/usseC/dJMb88e84Rw/q2vM2cRV1xYSSwwGwMCYu1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/lg8Ak/dJMb84qgXWz/DNq0qEzBG0sApFbp7nw8k0/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/ulNRY/dJMb83Srmsy/4jxZqnPrqkOy4bgB8aksmK/img.png?width=1596&amp;amp;height=489&amp;amp;face=0_0_1596_489&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/108&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/108&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/usseC/dJMb88e84Rw/q2vM2cRV1xYSSwwGwMCYu1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/lg8Ak/dJMb84qgXWz/DNq0qEzBG0sApFbp7nw8k0/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/ulNRY/dJMb83Srmsy/4jxZqnPrqkOy4bgB8aksmK/img.png?width=1596&amp;amp;height=489&amp;amp;face=0_0_1596_489');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;충돌 이벤트로 획득되는 아이템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;충돌 이벤트로 획득되는 아이템 구현하기 이전 포스팅에서는 클래스 구조만 짜고 로직은 비여있던 상태.이전 포스팅: [Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://devcol.tistory.com/109&quot;&gt;[Unreal Engine/UE 기초] - 아이템 스폰 및 레벨 데이터 관리하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781222926904&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;아이템 스폰 및 레벨 데이터 관리하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;아이템 스폰 및 레벨 데이터 관리하기 랜덤 위치에 아이템 스폰하기 1️⃣ 레벨 셋팅하기Resources 폴더에 Maps 폴더에는 3개의 레벨이 이미 존재합니다. 각각 난이도에 따라서 크기가 다른 맵이고, &quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/109&quot; data-og-url=&quot;https://devcol.tistory.com/109&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bb7rOB/dJMb9lMjLJO/5kTyg5YcZObBNMipdSgoKK/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/bab4de/dJMb9cBQjCV/WVs1kCtDKwGDGpLGykbOb1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/bjzwRD/dJMb9iaZqLR/5u93kLFlxAX5jUZeK1Tjp0/img.png?width=943&amp;amp;height=571&amp;amp;face=0_0_943_571&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/109&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/109&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bb7rOB/dJMb9lMjLJO/5kTyg5YcZObBNMipdSgoKK/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/bab4de/dJMb9cBQjCV/WVs1kCtDKwGDGpLGykbOb1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/bjzwRD/dJMb9iaZqLR/5u93kLFlxAX5jUZeK1Tjp0/img.png?width=943&amp;amp;height=571&amp;amp;face=0_0_943_571');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;아이템 스폰 및 레벨 데이터 관리하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;아이템 스폰 및 레벨 데이터 관리하기 랜덤 위치에 아이템 스폰하기 1️⃣ 레벨 셋팅하기Resources 폴더에 Maps 폴더에는 3개의 레벨이 이미 존재합니다. 각각 난이도에 따라서 크기가 다른 맵이고,&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://devcol.tistory.com/110&quot;&gt;[Unreal Engine/UE 기초] - 캐릭터 체력 및 점수 관리 시스템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781222928199&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;캐릭터 체력 및 점수 관리 시스템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;캐릭터 체력 및 점수 관리 시스템 구현하기 캐릭터 체력 시스템 구현하기 1️⃣ 캐릭터 클래스에 체력 변수 및 함수 선언PlayerState를 쓰지 않는 이유PlayerState: 각 플레이어마다의 어떤 정보를 관&quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/110&quot; data-og-url=&quot;https://devcol.tistory.com/110&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/to8Hp/dJMb84qgXWB/XkF0sv4nkNFVMwPN3RxyiK/img.png?width=773&amp;amp;height=359&amp;amp;face=0_0_773_359,https://scrap.kakaocdn.net/dn/in3Hi/dJMb86O97yR/xLKESERIx6levctoUfRwE1/img.png?width=773&amp;amp;height=359&amp;amp;face=0_0_773_359,https://scrap.kakaocdn.net/dn/bul1bf/dJMb82MLv19/7XshaErT4bI4caYIunjHmK/img.png?width=915&amp;amp;height=558&amp;amp;face=0_0_915_558&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/110&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/110&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/to8Hp/dJMb84qgXWB/XkF0sv4nkNFVMwPN3RxyiK/img.png?width=773&amp;amp;height=359&amp;amp;face=0_0_773_359,https://scrap.kakaocdn.net/dn/in3Hi/dJMb86O97yR/xLKESERIx6levctoUfRwE1/img.png?width=773&amp;amp;height=359&amp;amp;face=0_0_773_359,https://scrap.kakaocdn.net/dn/bul1bf/dJMb82MLv19/7XshaErT4bI4caYIunjHmK/img.png?width=915&amp;amp;height=558&amp;amp;face=0_0_915_558');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;캐릭터 체력 및 점수 관리 시스템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;캐릭터 체력 및 점수 관리 시스템 구현하기 캐릭터 체력 시스템 구현하기 1️⃣ 캐릭터 클래스에 체력 변수 및 함수 선언PlayerState를 쓰지 않는 이유PlayerState: 각 플레이어마다의 어떤 정보를 관&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://devcol.tistory.com/111&quot;&gt;[Unreal Engine/UE 기초] - 게임 루프 설계를 통한 게임 흐름 제어하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781222930028&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;게임 루프 설계를 통한 게임 흐름 제어하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;게임 루프 설계를 통한 게임 흐름 제어하기 GameState를 이용한 게임 루프 구현하기 게임루프: 보통 게임의 핵심적인 흐름을 얘기합니다. 즉 게임이 시작할 때부터 종료까지 수행하는 단계들게임&quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/111&quot; data-og-url=&quot;https://devcol.tistory.com/111&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/m3HSO/dJMb8Yp3LZc/oDKcOSmHa6KQokX0K8otyK/img.png?width=800&amp;amp;height=566&amp;amp;face=0_0_800_566,https://scrap.kakaocdn.net/dn/bezEhJ/dJMb8TCh97F/a38cyWkwwklT9XZIOkmAI0/img.png?width=800&amp;amp;height=566&amp;amp;face=0_0_800_566,https://scrap.kakaocdn.net/dn/dBmfWn/dJMb8Yp3LZb/ZKEpbaswdrCszr1LfiKXDk/img.png?width=1167&amp;amp;height=827&amp;amp;face=0_0_1167_827&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/111&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/111&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/m3HSO/dJMb8Yp3LZc/oDKcOSmHa6KQokX0K8otyK/img.png?width=800&amp;amp;height=566&amp;amp;face=0_0_800_566,https://scrap.kakaocdn.net/dn/bezEhJ/dJMb8TCh97F/a38cyWkwwklT9XZIOkmAI0/img.png?width=800&amp;amp;height=566&amp;amp;face=0_0_800_566,https://scrap.kakaocdn.net/dn/dBmfWn/dJMb8Yp3LZb/ZKEpbaswdrCszr1LfiKXDk/img.png?width=1167&amp;amp;height=827&amp;amp;face=0_0_1167_827');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;게임 루프 설계를 통한 게임 흐름 제어하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;게임 루프 설계를 통한 게임 흐름 제어하기 GameState를 이용한 게임 루프 구현하기 게임루프: 보통 게임의 핵심적인 흐름을 얘기합니다. 즉 게임이 시작할 때부터 종료까지 수행하는 단계들게임&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/114&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; [Unreal Engine/UE 기초] - UI 위젯 설계와 실시간 데이터 연동하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781222931089&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;UI 위젯 설계와 실시간 데이터 연동하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;UI 위젯 설계와 실시간 데이터 연동하기 | [언리얼 엔진 C++ (Unreal Engine C++)] UMG (User Widget) 위젯 기초 디자인 이해하기 1️⃣ HUD (Heads-Up Display)란?HUD는 게임 내에서 플레이어에게 정보를 제공하기 위&quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/114&quot; data-og-url=&quot;https://devcol.tistory.com/114&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dWdB9W/dJMb84qgXWC/Giz2KwYRqTn2WeK2KDaatK/img.gif?width=400&amp;amp;height=203&amp;amp;face=0_0_400_203,https://scrap.kakaocdn.net/dn/cm53lH/dJMb83SrmsD/w26ooHE74oYMXYlki4IuB0/img.gif?width=400&amp;amp;height=203&amp;amp;face=0_0_400_203,https://scrap.kakaocdn.net/dn/lRvyB/dJMb88e84Rx/BNI790t4aQcMGrKGszOEI0/img.png?width=1392&amp;amp;height=523&amp;amp;face=0_0_1392_523&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/114&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/114&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dWdB9W/dJMb84qgXWC/Giz2KwYRqTn2WeK2KDaatK/img.gif?width=400&amp;amp;height=203&amp;amp;face=0_0_400_203,https://scrap.kakaocdn.net/dn/cm53lH/dJMb83SrmsD/w26ooHE74oYMXYlki4IuB0/img.gif?width=400&amp;amp;height=203&amp;amp;face=0_0_400_203,https://scrap.kakaocdn.net/dn/lRvyB/dJMb88e84Rx/BNI790t4aQcMGrKGszOEI0/img.png?width=1392&amp;amp;height=523&amp;amp;face=0_0_1392_523');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;UI 위젯 설계와 실시간 데이터 연동하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;UI 위젯 설계와 실시간 데이터 연동하기 | [언리얼 엔진 C++ (Unreal Engine C++)] UMG (User Widget) 위젯 기초 디자인 이해하기 1️⃣ HUD (Heads-Up Display)란?HUD는 게임 내에서 플레이어에게 정보를 제공하기 위&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://devcol.tistory.com/115&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Unreal Engine/UE 기초] - 게임 흐름에 맞춘 메뉴 UI 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781222934136&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;게임 흐름에 맞춘 메뉴 UI 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;게임 흐름에 맞춘 메뉴 UI 구현하기 게임 메뉴 UI 디자인하기 1️⃣ 메뉴 위젯 생성하고 버튼 추가하기그동안은 게임 중에 나오는 위젯을 설계했다면, 이번에는 게임을 일시적으로 중단하고 시작&quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/115&quot; data-og-url=&quot;https://devcol.tistory.com/115&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cnypNL/dJMb8VND17O/NES9Px6kak22EKADxEVxG0/img.png?width=800&amp;amp;height=381&amp;amp;face=382_181_484_283,https://scrap.kakaocdn.net/dn/crNzY2/dJMb8XSedNs/k5yo5UCKTeLvl14bEeQngk/img.png?width=800&amp;amp;height=381&amp;amp;face=382_181_484_283,https://scrap.kakaocdn.net/dn/dtHOID/dJMb8YXT4P6/yMLb5wLLfILhxfidutrQG1/img.png?width=1661&amp;amp;height=767&amp;amp;face=0_0_1661_767&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/115&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/115&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cnypNL/dJMb8VND17O/NES9Px6kak22EKADxEVxG0/img.png?width=800&amp;amp;height=381&amp;amp;face=382_181_484_283,https://scrap.kakaocdn.net/dn/crNzY2/dJMb8XSedNs/k5yo5UCKTeLvl14bEeQngk/img.png?width=800&amp;amp;height=381&amp;amp;face=382_181_484_283,https://scrap.kakaocdn.net/dn/dtHOID/dJMb8YXT4P6/yMLb5wLLfILhxfidutrQG1/img.png?width=1661&amp;amp;height=767&amp;amp;face=0_0_1661_767');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;게임 흐름에 맞춘 메뉴 UI 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;게임 흐름에 맞춘 메뉴 UI 구현하기 게임 메뉴 UI 디자인하기 1️⃣ 메뉴 위젯 생성하고 버튼 추가하기그동안은 게임 중에 나오는 위젯을 설계했다면, 이번에는 게임을 일시적으로 중단하고 시작&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/pages/Unreal-Engine-%EC%96%B8%EB%A6%AC%EC%96%BC-%EC%97%94%EC%A7%84&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;[페이지] Unreal Engine | 언리얼 엔진&lt;/b&gt;&lt;/a&gt;&lt;/h4&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;</description>
      <category>Unreal Engine/UE 기초</category>
      <category>C++</category>
      <category>Devlog</category>
      <category>Programming</category>
      <category>UE</category>
      <category>UE5</category>
      <category>Unreal engine</category>
      <category>게임 개발</category>
      <category>기초</category>
      <category>언리얼 엔진</category>
      <category>프로그래밍</category>
      <author>DevCol</author>
      <guid isPermaLink="true">https://devcol.tistory.com/116</guid>
      <comments>https://devcol.tistory.com/116#entry116comment</comments>
      <pubDate>Fri, 12 Jun 2026 09:09:07 +0900</pubDate>
    </item>
    <item>
      <title>게임 흐름에 맞춘 메뉴 UI 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]</title>
      <link>https://devcol.tistory.com/115</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt;게임 흐름에 맞춘 메뉴 UI 구현하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a1&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;게임&amp;nbsp;메뉴&amp;nbsp;UI&amp;nbsp;디자인하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣ &lt;b&gt;메뉴 위젯 생성하고 버튼 추가하기&lt;/b&gt;&lt;/h2&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;b&gt;Content Browser에서 UI - Widgets 폴더에서 마우스 우클릭&lt;/b&gt; &amp;rarr; &lt;b&gt;User Interface&lt;/b&gt; &amp;rarr; &lt;b&gt;Widget Blueprint&lt;/b&gt; 선택합니다. 새로 생성되는 위젯의 이름은 &lt;b&gt;WBP_MainMenu&lt;/b&gt;라고 지어 주세요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;더블 클릭&lt;/b&gt;하여 열면, 중앙에 &lt;b&gt;Designer 탭&lt;/b&gt;, 오른쪽에 &lt;b&gt;Details 탭&lt;/b&gt;, 왼쪽에는 &lt;b&gt;Hierarchy &amp;amp; Palette&lt;/b&gt;가 보입니다.&lt;/li&gt;
&lt;li&gt;Canvas Panel을 놓아서 기본적인 바탕을 마련합니다.&lt;/li&gt;
&lt;li&gt;그 아래에 Border을 생성해서 바탕을 투명도를 주고 검정색 바탕화면으로 지정해줍니다. 그래서 게임 실행 시 레벨의 모습이 잘 보이지 않도록 설정합니다.&lt;/li&gt;
&lt;li&gt;Common&amp;nbsp;-&amp;nbsp;Button&amp;nbsp;위젯을&amp;nbsp;각각&amp;nbsp;Start&amp;nbsp;버튼&amp;nbsp;하나만&amp;nbsp;Canvas&amp;nbsp;Panel&amp;nbsp;아래에&amp;nbsp;둡니다.&amp;nbsp;Button의&amp;nbsp;이름은&amp;nbsp;StartButton으로&amp;nbsp;변경해줍니다.&lt;/li&gt;
&lt;li&gt;Alignment를&amp;nbsp;(0.5,&amp;nbsp;0.5)로&amp;nbsp;놓고&amp;nbsp;X,&amp;nbsp;Y의&amp;nbsp;위치를&amp;nbsp;화면&amp;nbsp;크기의&amp;nbsp;절반으로&amp;nbsp;두면&amp;nbsp;가운데에&amp;nbsp;딱&amp;nbsp;배치될&amp;nbsp;수&amp;nbsp;있습니다.&lt;/li&gt;
&lt;li&gt;혹은 그냥 Anchors 를 정 중앙으로 하면 됩니다. (Ctrl+Shift+ 원하는 Anchor 위치 선택하면 반영됩니다)&lt;/li&gt;
&lt;li&gt;각&amp;nbsp;버튼마다&amp;nbsp;Common&amp;nbsp;-&amp;nbsp;Text를&amp;nbsp;끌어다&amp;nbsp;놓습니다.&amp;nbsp;왼쪽&amp;nbsp;하단에&amp;nbsp;Hierarchy창에&amp;nbsp;드래그&amp;nbsp;앤&amp;nbsp;드랍을&amp;nbsp;하면&amp;nbsp;편합니다.&amp;nbsp;Text의&amp;nbsp;이름은&amp;nbsp;StartButtonText로&amp;nbsp;지정해줍니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;634&quot; data-origin-height=&quot;359&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mZJ02/dJMcac4t6qk/tkkh3J7lbYKYlZs5Q6AiYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mZJ02/dJMcac4t6qk/tkkh3J7lbYKYlZs5Q6AiYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mZJ02/dJMcac4t6qk/tkkh3J7lbYKYlZs5Q6AiYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmZJ02%2FdJMcac4t6qk%2Ftkkh3J7lbYKYlZs5Q6AiYK%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;634&quot; height=&quot;359&quot; data-origin-width=&quot;634&quot; data-origin-height=&quot;359&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;1611&quot; data-origin-height=&quot;769&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p02Wk/dJMcabYRSZe/xx0AfK6PvWX2VC8KH60NyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p02Wk/dJMcabYRSZe/xx0AfK6PvWX2VC8KH60NyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p02Wk/dJMcabYRSZe/xx0AfK6PvWX2VC8KH60NyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp02Wk%2FdJMcabYRSZe%2Fxx0AfK6PvWX2VC8KH60NyK%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;1611&quot; height=&quot;769&quot; data-origin-width=&quot;1611&quot; data-origin-height=&quot;769&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;1632&quot; data-origin-height=&quot;674&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dfgiQH/dJMcagMEGTR/OjXTfNbFofRvwak6SBURH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dfgiQH/dJMcagMEGTR/OjXTfNbFofRvwak6SBURH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dfgiQH/dJMcagMEGTR/OjXTfNbFofRvwak6SBURH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdfgiQH%2FdJMcagMEGTR%2FOjXTfNbFofRvwak6SBURH1%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;1632&quot; height=&quot;674&quot; data-origin-width=&quot;1632&quot; data-origin-height=&quot;674&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2️⃣ &lt;b&gt;메뉴 레벨 생성하고 설정하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;흔히 게임 개발 시 &lt;b&gt;메뉴 전용 맵&lt;/b&gt;을 만들어, 그 맵에서는 메뉴만 띄우도록 하고, 실제 게임이 시작되면 게임 레벨로 넘어가게 합니다.&lt;/li&gt;
&lt;li&gt;이 방식을 쓰면 &amp;ldquo;Menu UI와 Game Level&amp;rdquo;이 완전히 분리되어, 구조가 좀 더 명확해집니다.&lt;/li&gt;
&lt;li&gt;File - New Level 을 선택하고 Basic 템플릿으로 생성을 합니다. Maps 폴더에 MenuLevel이라는 이름으로 저장을 해줍니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단축키: Ctrl+N&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Editor&amp;nbsp;-&amp;nbsp;Project&amp;nbsp;Settings에&amp;nbsp;들어가서&amp;nbsp;Maps&amp;nbsp;&amp;amp;&amp;nbsp;Modes에서&amp;nbsp;Default&amp;nbsp;Maps를&amp;nbsp;MenuLevel로&amp;nbsp;지정해서&amp;nbsp;저장해주도록&amp;nbsp;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1101&quot; data-origin-height=&quot;638&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDyDqi/dJMcagsirz1/EEkZozZzfFABBgO6rlPsa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDyDqi/dJMcagsirz1/EEkZozZzfFABBgO6rlPsa0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDyDqi/dJMcagsirz1/EEkZozZzfFABBgO6rlPsa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDyDqi%2FdJMcagsirz1%2FEEkZozZzfFABBgO6rlPsa0%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;1101&quot; height=&quot;638&quot; data-origin-width=&quot;1101&quot; data-origin-height=&quot;638&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a4&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;게임 흐름 내에 메뉴 UI 배치하기&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;우선, 우리가 만든 이 메뉴 위젯 (&lt;b&gt;WBP_MainMenu&lt;/b&gt;)을 다양한 상황에서 &lt;b&gt;표시&lt;/b&gt;하고, &lt;b&gt;숨기고&lt;/b&gt;, &lt;b&gt;다시 띄우는&lt;/b&gt; 로직을 단계별로 구현해야 합니다.
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;플레이 버튼을 누르면 Menu UI가 가장 먼저 뜨기&lt;/li&gt;
&lt;li&gt;&lt;b&gt;게임 시작 시&lt;/b&gt; 자동으로 HUD를 띄우기&lt;/li&gt;
&lt;li&gt;메뉴가 나타날 때마다, &lt;b&gt;UI 입력 모드&lt;/b&gt;로 전환하여 버튼 클릭에 집중하게 만드는 방식으로 수정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;게임이 종료되면&lt;/b&gt; 메뉴가 다시 뜨도록 만들기&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣ &lt;b&gt;PlayerController에 기본 위젯 오픈 함수 구현&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위젯을 &lt;b&gt;어디서&lt;/b&gt; 만들고 관리할지는 프로젝트마다 다른데, 일반적으로 &lt;b&gt;PlayerController&lt;/b&gt;가 &lt;b&gt;UI&lt;/b&gt;를 다루기 좋습니다. 게임 모드도 가능하지만, 멀티플레이를 고려하면 PlayerController가 UI 담당이 좀 더 자연스러운 편입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;게임 입력 vs UI 입력&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;게임 플레이 중 메뉴가 활성화되면, &lt;b&gt;UI만&lt;/b&gt; 입력을 받도록 하거나, &lt;b&gt;UI + 게임&lt;/b&gt; 둘 다 입력을 받도록 할 수 있습니다.&lt;/li&gt;
&lt;li&gt;이때 UI에 &lt;b&gt;마우스 포커스&lt;/b&gt;가 가도록 만들려면 &lt;b&gt;SetInputMode&lt;/b&gt; 계열 함수를 사용해야 합니다. &lt;b&gt;SetInputMode&lt;/b&gt; 계열 함수를 통해 PlayerController가 어느 입력을 우선으로 처리할지 결정합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;UI 전용 입력 모드&lt;/b&gt;로 전환하면, 플레이어의 마우스 입력과 키 입력이 먼저 &lt;b&gt;UI&lt;/b&gt;로 전달됩니다. 캐릭터 이동이나 시야 회전 등 게임 월드 입력은 &lt;b&gt;잠시 비활성화&lt;/b&gt;되고, 버튼 클릭에 집중할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;FInputModeUIOnly&lt;/b&gt; 구조체 생성 &amp;rarr; &lt;b&gt;SetWidgetToFocus&lt;/b&gt;로 포커스할 UI 위젯 지정&lt;/li&gt;
&lt;li&gt;SetInputMode(InputMode) 호출 &amp;rarr; 이제 마우스 클릭이나 키 입력이 &lt;b&gt;UI&lt;/b&gt;를 먼저 처&lt;/li&gt;
&lt;li&gt;bShowMouseCursor = true로 마우스 커서를 보이게 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;빌드한 후, BP_SpartaPlayerController 에서 MainMenuWidgetClass에 WBP_MainMenu 를 할당해줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781209289967&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pragma once

#include &quot;CoreMinimal.h&quot;
#include &quot;GameFramework/PlayerController.h&quot;
#include &quot;MainPlayerController.generated.h&quot;

// Declaration
class UInputMappingContext; // IMC 관련 전방 선언
class UInputAction; // IA 관련 전방 선언


// Enhanced Input에서 액션 값을 받을 때 사용하는 구조체
struct FInputActionValue;

UCLASS()
class BC_CH3_ASSIGNMENT_5_API AMainPlayerController : public APlayerController
{
	GENERATED_BODY()

public:
	AMainPlayerController();

	// 에디터에서 세팅할 IMC
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=&quot;Input&quot;)
	UInputMappingContext* InputMappingContext;

	// IA
	// IA_Move를 지정할 변수
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=&quot;Input&quot;)
	UInputAction* MoveAction;
	// IA_Jump를 지정할 변수
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=&quot;Input&quot;)
	UInputAction* JumpAction;
	// IA_Look를 지정할 변수
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=&quot;Input&quot;)
	UInputAction* LookAction;
	// IA_Sprint를 지정할 변수
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Input&quot;)
	UInputAction* SprintAction;

	// UMG 위젯 클래스를 에디터에서 할당받을 변수
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;HUD&quot;)
	TSubclassOf&amp;lt;UUserWidget&amp;gt; HUDWidgetClass;
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = &quot;HUD&quot;)
	UUserWidget* HUDWidgetInstance;

	UFUNCTION(BlueprintPure, Category = &quot;HUD&quot;)
	UUserWidget* GetHUDWidget() const;

	// HUD 표시
	UFUNCTION(BlueprintCallable, Category = &quot;HUD&quot;)
	void ShowGameHUD();


	// 메뉴 UI
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Menu&quot;)
	TSubclassOf&amp;lt;UUserWidget&amp;gt; MainMenuWidgetClass;
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = &quot;Menu&quot;)
	UUserWidget* MainMenuWidgetInstance;

	// 메인 메뉴 표시
	UFUNCTION(BlueprintCallable, Category = &quot;Menu&quot;)
	void ShowMainMenu(bool bIsRestart);
	// 게임 시작
	UFUNCTION(BlueprintCallable, Category = &quot;Menu&quot;)
	void StartGame();

protected:
	virtual void BeginPlay() override;

	/*
	
	//UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=&quot;Input&quot;, meta=(AllowPrivateAccess=&quot;true&quot;))
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Input&quot;)
	UInputAction* ToggleInventoryAction;
	
	bool bIsInventoryOpen;
	
	UFUNCTION(BlueprintCallable)
	void ToggleInventory();
	
	void ActivateCharacterInput();
	void ActivateUIInput();
	*/
};&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1781209302149&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;MainPlayerController.h&quot;
#include &quot;EnhancedInputSubsystems.h&quot;
#include &quot;EnhancedInputSubsystems.h&quot; // Enhanced Input System의 Local Player Subsystem을 사용하기 위해 포함
#include &quot;MainGameState.h&quot;
#include &quot;MainGameInstance.h&quot;
#include &quot;Blueprint/UserWidget.h&quot;
#include &quot;Kismet/GameplayStatics.h&quot;
#include &quot;Components/TextBlock.h&quot;

// 어차피 블루프린트 상에서 전부 다 초기화를 하기 때문에 여기서는 전부 다 nullptr 처리
AMainPlayerController::AMainPlayerController()
	: InputMappingContext(nullptr),
	  MoveAction(nullptr),
	  JumpAction(nullptr),
	  LookAction(nullptr),
	  SprintAction(nullptr),
	  HUDWidgetClass(nullptr),
	  HUDWidgetInstance(nullptr),
	  MainMenuWidgetClass(nullptr),
	  MainMenuWidgetInstance(nullptr)

{
}

void AMainPlayerController::BeginPlay()
{
	Super::BeginPlay();

	// GetLocalPlayer():현재 PlayerController에 연결된 Local Player 객체를 가져옴     
	// Local Player 는 그 플레이어의 입력이나 화면 뷰 같은 것을 관리하는 어떤 객체
	if (ULocalPlayer* LocalPlayer = GetLocalPlayer())
	{
		// Local Player에서 EnhancedInputLocalPlayerSubsystem을 획득
		// UEnhancedInputLocalPlayerSubsystem: 입력 시스템을 관리 (IMC 추가 혹은 삭제하는 역할)
		if (UEnhancedInputLocalPlayerSubsystem* Subsystem =
			LocalPlayer-&amp;gt;GetSubsystem&amp;lt;UEnhancedInputLocalPlayerSubsystem&amp;gt;())
		{
			if (InputMappingContext)
			{
				// Subsystem을 통해 우리가 할당한 IMC를 활성화
				// 우선순위(Priority)는 0이 가장 높은 우선순위
				Subsystem-&amp;gt;AddMappingContext(InputMappingContext, 0);
			}
		}
	}

	// HUD 위젯 생성 및 표시
	if (HUDWidgetClass)
	{
		HUDWidgetInstance = CreateWidget&amp;lt;UUserWidget&amp;gt;(this, HUDWidgetClass);
		if (HUDWidgetInstance)
		{
			HUDWidgetInstance-&amp;gt;AddToViewport();
		}
	}

	AMainGameState* MainGameState = GetWorld() ? GetWorld()-&amp;gt;GetGameState&amp;lt;AMainGameState&amp;gt;() : nullptr;
	if (MainGameState)
	{
		MainGameState-&amp;gt;UpdateHUD();
	}
}

UUserWidget* AMainPlayerController::GetHUDWidget() const
{
	return HUDWidgetInstance;
}


// 메뉴 UI 표시
void AMainPlayerController::ShowMainMenu(bool bIsRestart)
{
	// HUD가 켜져 있다면 닫기
	if (HUDWidgetInstance)
	{
		HUDWidgetInstance-&amp;gt;RemoveFromParent();
		HUDWidgetInstance = nullptr;
	}

	// 이미 메뉴가 떠 있으면 제거
	if (MainMenuWidgetInstance)
	{
		MainMenuWidgetInstance-&amp;gt;RemoveFromParent();
		MainMenuWidgetInstance = nullptr;
	}

	// 메뉴 UI 생성
	if (MainMenuWidgetClass)
	{
		MainMenuWidgetInstance = CreateWidget&amp;lt;UUserWidget&amp;gt;(this, MainMenuWidgetClass);
		if (MainMenuWidgetInstance)
		{
			MainMenuWidgetInstance-&amp;gt;AddToViewport();

			bShowMouseCursor = true;
			SetInputMode(FInputModeUIOnly());
		}

		if (UTextBlock* ButtonText = Cast&amp;lt;UTextBlock&amp;gt;(
			MainMenuWidgetInstance-&amp;gt;GetWidgetFromName(TEXT(&quot;StartButtonText&quot;))))
		{
			if (bIsRestart)
			{
				ButtonText-&amp;gt;SetText(FText::FromString(TEXT(&quot;Restart&quot;)));
			}
			else
			{
				ButtonText-&amp;gt;SetText(FText::FromString(TEXT(&quot;Start&quot;)));
			}
		}
	}
}

// 게임 HUD 표시
void AMainPlayerController::ShowGameHUD()
{
	// HUD가 켜져 있다면 닫기
	if (HUDWidgetInstance)
	{
		HUDWidgetInstance-&amp;gt;RemoveFromParent();
		HUDWidgetInstance = nullptr;
	}

	// 이미 메뉴가 떠 있으면 제거
	if (MainMenuWidgetInstance)
	{
		MainMenuWidgetInstance-&amp;gt;RemoveFromParent();
		MainMenuWidgetInstance = nullptr;
	}

	if (HUDWidgetClass)
	{
		HUDWidgetInstance = CreateWidget&amp;lt;UUserWidget&amp;gt;(this, HUDWidgetClass);
		if (HUDWidgetInstance)
		{
			HUDWidgetInstance-&amp;gt;AddToViewport();

			bShowMouseCursor = false;
			SetInputMode(FInputModeGameOnly());

			AMainGameState* MainGameState = GetWorld() ? GetWorld()-&amp;gt;GetGameState&amp;lt;AMainGameState&amp;gt;() : nullptr;
			if (MainGameState)
			{
				MainGameState-&amp;gt;UpdateHUD();
			}
		}
	}
}

// 게임 시작 - BasicLevel 오픈, GameInstance 데이터 리셋
void AMainPlayerController::StartGame()
{
	if (UMainGameInstance* MainGameInstance = Cast&amp;lt;UMainGameInstance&amp;gt;(UGameplayStatics::GetGameInstance(this)))
	{
		MainGameInstance-&amp;gt;CurrentLevelIndex = 0;
		MainGameInstance-&amp;gt;TotalScore = 0;
	}

	UGameplayStatics::OpenLevel(GetWorld(), FName(&quot;BasicLevel&quot;));
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2️⃣ &lt;b&gt;GameState에서 게임 흐름에 따라 UI 호출&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1781210579001&quot; class=&quot;dts&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;#include &quot;MainGameState.h&quot;
#include &quot;MainGameInstance.h&quot;
#include &quot;MainPlayerController.h&quot;
#include &quot;Kismet/GameplayStatics.h&quot;
#include &quot;SpawnVolume.h&quot;
#include &quot;CoinItem.h&quot;
#include &quot;Components/TextBlock.h&quot;
#include &quot;Blueprint/UserWidget.h&quot;

AMainGameState::AMainGameState()
{
	Score = 0;
	SpawnedCoinCount = 0;
	CollectedCoinCount = 0;
	LevelDuration = 30.0f; // 한 레벨당 30초
	CurrentLevelIndex = 0;
	MaxLevels = 3;
}

void AMainGameState::BeginPlay()
{
	Super::BeginPlay();

	// 게임 시작 시 첫 레벨부터 진행
	StartLevel();
	
	UpdateHUD();
	
	GetWorldTimerManager().SetTimer(
			HUDUpdateTimerHandle,
			this,
			&amp;amp;AMainGameState::UpdateHUD,
			0.1f,
			true
		);
}

int32 AMainGameState::GetScore() const
{
	return Score;
}

void AMainGameState::AddScore(int32 Amount)
{
	if (UGameInstance* GameInstance = GetGameInstance())
	{
		UMainGameInstance* MainGameInstance = Cast&amp;lt;UMainGameInstance&amp;gt;(GameInstance);
		if (MainGameInstance)
		{
			MainGameInstance-&amp;gt;AddToScore(Amount);
		}
	}
}


void AMainGameState::StartLevel()
{
	if (APlayerController* PlayerController = GetWorld()-&amp;gt;GetFirstPlayerController())
	{
		if (AMainPlayerController* SpartaPlayerController = Cast&amp;lt;AMainPlayerController&amp;gt;(PlayerController))
		{
			SpartaPlayerController-&amp;gt;ShowGameHUD();
		}
	}

	
	if (UGameInstance* GameInstance = GetGameInstance())
	{
		UMainGameInstance* MainGameInstance = Cast&amp;lt;UMainGameInstance&amp;gt;(GameInstance);
		if (MainGameInstance)
		{
			CurrentLevelIndex = MainGameInstance-&amp;gt;CurrentLevelIndex;
		}
	}

	// 레벨 시작 시, 코인 개수 초기화
	SpawnedCoinCount = 0;
	CollectedCoinCount = 0;
	// 현재 맵에 배치된 모든 SpawnVolume을 찾아 아이템 40개를 스폰
	TArray&amp;lt;AActor*&amp;gt; FoundVolumes;
	UGameplayStatics::GetAllActorsOfClass(GetWorld(), ASpawnVolume::StaticClass(), FoundVolumes);
	const int32 ItemToSpawn = 40;

	for (int32 i = 0; i &amp;lt; ItemToSpawn; i++)
	{
		if (FoundVolumes.Num() &amp;gt; 0)
		{
			ASpawnVolume* SpawnVolume = Cast&amp;lt;ASpawnVolume&amp;gt;(FoundVolumes[0]);
			if (SpawnVolume)
			{
				AActor* SpawnedActor = SpawnVolume-&amp;gt;SpawnRandomItem();
				// 만약 스폰된 액터가 코인 타입이라면 SpawnedCoinCount 증가
				if (SpawnedActor &amp;amp;&amp;amp; SpawnedActor-&amp;gt;IsA(ACoinItem::StaticClass()))
				{
					SpawnedCoinCount++;
				}
			}
		}
	}
	// 30초 후에 OnLevelTimeUp()가 호출되도록 타이머 설정
	GetWorldTimerManager().SetTimer(
		LevelTimerHandle,
		this,
		&amp;amp;AMainGameState::OnLevelTimeUp,
		LevelDuration,
		false
	);
	/*UE_LOG(LogTemp, Warning, TEXT(&quot;Level %d Start!, Spawned %d coin&quot;),
	       CurrentLevelIndex + 1,
	       SpawnedCoinCount);*/
}

void AMainGameState::OnLevelTimeUp()
{
	// 시간이 다 되면 레벨을 종료
	EndLevel();
}

void AMainGameState::OnCoinCollected()
{
	CollectedCoinCount++;

	/*UE_LOG(LogTemp, Warning, TEXT(&quot;Coin Collected: %d / %d&quot;),
	       CollectedCoinCount,
	       SpawnedCoinCount)*/

	// 현재 레벨에서 스폰된 코인을 전부 주웠다면 즉시 레벨 종료
	if (SpawnedCoinCount &amp;gt; 0 &amp;amp;&amp;amp; CollectedCoinCount &amp;gt;= SpawnedCoinCount)
	{
		EndLevel();
	}
}

void AMainGameState::EndLevel()
{	
	
	// 타이머 해제
	GetWorldTimerManager().ClearTimer(LevelTimerHandle);
	// 다음 레벨 인덱스로
	//CurrentLevelIndex++;
	
	if (UGameInstance* GameInstance = GetGameInstance())
	{
		UMainGameInstance* MainGameInstance = Cast&amp;lt;UMainGameInstance&amp;gt;(GameInstance);
		if (MainGameInstance)
		{
			AddScore(Score);
			CurrentLevelIndex++;
			MainGameInstance-&amp;gt;CurrentLevelIndex = CurrentLevelIndex;
		}
	}

	// 모든 레벨을 다 돌았다면 게임 오버 처리
	if (CurrentLevelIndex &amp;gt;= MaxLevels)
	{
		OnGameOver();
		return;
	}

	// 레벨 맵 이름이 있다면 해당 맵 불러오기
	if (LevelMapNames.IsValidIndex(CurrentLevelIndex))
	{
		UGameplayStatics::OpenLevel(GetWorld(), LevelMapNames[CurrentLevelIndex]);
	}
	else
	{
		// 맵 이름이 없으면 게임오버
		OnGameOver();
	}
}

void AMainGameState::OnGameOver()
{
	if (APlayerController* PlayerController = GetWorld()-&amp;gt;GetFirstPlayerController())
	{
		if (AMainPlayerController* SpartaPlayerController = Cast&amp;lt;AMainPlayerController&amp;gt;(PlayerController))
		{
			SpartaPlayerController-&amp;gt;ShowMainMenu(true);
		}
	}
	
	//UpdateHUD();
	//UE_LOG(LogTemp, Warning, TEXT(&quot;Game Over!!&quot;));
	
}

void AMainGameState::UpdateHUD()
{
	if (APlayerController* PlayerController = GetWorld()-&amp;gt;GetFirstPlayerController())
	{
		AMainPlayerController* MainPlayerController = Cast&amp;lt;AMainPlayerController&amp;gt;(PlayerController);
		{
			if (UUserWidget* HUDWidget = MainPlayerController-&amp;gt;GetHUDWidget())
			{
				// requires
				// #include &quot;Components/TextBlock.h&quot;
				// #include &quot;Blueprint/UserWidget.h&quot;
				
				//추후 변경 방안 
				// UPROPERTY(meta = (BindWidget))
				// class UButton* MyAwesomeButton;
				if (UTextBlock* TimeText = Cast&amp;lt;UTextBlock&amp;gt;(HUDWidget-&amp;gt;GetWidgetFromName(TEXT(&quot;Time&quot;))))
				{
					float RemainingTime = GetWorldTimerManager().GetTimerRemaining(LevelTimerHandle);
					TimeText-&amp;gt;SetText(FText::FromString(FString::Printf(TEXT(&quot;Time: %.1f&quot;), RemainingTime)));
				}
				
				//
				if (UTextBlock* ScoreText = Cast&amp;lt;UTextBlock&amp;gt;(HUDWidget-&amp;gt;GetWidgetFromName(TEXT(&quot;Score&quot;))))
				{
					if (UGameInstance* GameInstance = GetGameInstance())
					{
						UMainGameInstance* MainGameInstance = Cast&amp;lt;UMainGameInstance&amp;gt;(GameInstance);
						if (MainGameInstance)
						{
							ScoreText-&amp;gt;SetText(FText::FromString(FString::Printf(TEXT(&quot;Score: %i&quot;), MainGameInstance-&amp;gt;TotalScore)));
						}
					}
				}
				
				if (UTextBlock* LevelIndexText = Cast&amp;lt;UTextBlock&amp;gt;(HUDWidget-&amp;gt;GetWidgetFromName(TEXT(&quot;Level&quot;))))
				{
					LevelIndexText-&amp;gt;SetText(FText::FromString(FString::Printf(TEXT(&quot;Level: %d&quot;), CurrentLevelIndex + 1)));
				}
			}
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3️⃣ &lt;b&gt;Start 버튼 클릭 이벤트에 함수 바인딩&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BP_MainPlayerController Setting:Menu -&amp;gt; WBP_MainMenu&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;753&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjNleU/dJMcajoVOlO/hKFCAfpwcxMTDzruRKkrA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjNleU/dJMcajoVOlO/hKFCAfpwcxMTDzruRKkrA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjNleU/dJMcajoVOlO/hKFCAfpwcxMTDzruRKkrA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjNleU%2FdJMcajoVOlO%2FhKFCAfpwcxMTDzruRKkrA1%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;948&quot; height=&quot;753&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;753&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;b&gt;Designer 탭&lt;/b&gt;에서 StartButton 버튼을 선택하고, &lt;b&gt;Details&lt;/b&gt; 패널에서 맨 위쪽에 버튼 이름을 지정해주는 부분이 있습니다. 그 옆에 Is Variable에 체크를 해줍니다. 그러면 맨 하단에 Events 들이 활성화되는 것을 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WBP_MainMenu Setting:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Buttion set Is Variable true&lt;/li&gt;
&lt;li&gt;OnClicked&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1661&quot; data-origin-height=&quot;767&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kClJa/dJMcahxZyOg/bSKrrPb3pyVxm2yjPxmI7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kClJa/dJMcahxZyOg/bSKrrPb3pyVxm2yjPxmI7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kClJa/dJMcahxZyOg/bSKrrPb3pyVxm2yjPxmI7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkClJa%2FdJMcahxZyOg%2FbSKrrPb3pyVxm2yjPxmI7k%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;1661&quot; height=&quot;767&quot; data-origin-width=&quot;1661&quot; data-origin-height=&quot;767&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;966&quot; data-origin-height=&quot;293&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ogb5J/dJMcaiKmV6T/jh9i0XgDBWoZ4CyIKGaRwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ogb5J/dJMcaiKmV6T/jh9i0XgDBWoZ4CyIKGaRwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ogb5J/dJMcaiKmV6T/jh9i0XgDBWoZ4CyIKGaRwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOgb5J%2FdJMcaiKmV6T%2Fjh9i0XgDBWoZ4CyIKGaRwk%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;966&quot; height=&quot;293&quot; data-origin-width=&quot;966&quot; data-origin-height=&quot;293&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;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style2&quot; data-ke-type=&quot;horizontalRule&quot; /&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;h3 style=&quot;padding: 0.3em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #5b63fb; font-weight: bold; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;추천&lt;/span&gt;&lt;/h3&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;a href=&quot;https://devcol.tistory.com/107&quot;&gt;[Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781211357495&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;인터페이스 기반 아이템 클래스 설계하기 인터페이스 이해하기1️⃣ 인터페이스란?인터페이스 (Interface)란 클래스 (또는 오브젝트)가 반드시 구현해야 할 함수 목록만을 미리 정의해 두고, 실제 &quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/107&quot; data-og-url=&quot;https://devcol.tistory.com/107&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/i8Eu8/dJMb86O97yQ/KrdVAwlbKoqPioBFaTZrp1/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/RHrb0/dJMb81f00nk/GXBARX8wUIPEhZfFsbJ0w0/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/dXIyx2/dJMb896b3nW/NsulI0BwU9V1lIiWOJWOTk/img.png?width=997&amp;amp;height=544&amp;amp;face=0_0_997_544&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/107&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/107&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/i8Eu8/dJMb86O97yQ/KrdVAwlbKoqPioBFaTZrp1/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/RHrb0/dJMb81f00nk/GXBARX8wUIPEhZfFsbJ0w0/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/dXIyx2/dJMb896b3nW/NsulI0BwU9V1lIiWOJWOTk/img.png?width=997&amp;amp;height=544&amp;amp;face=0_0_997_544');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스 기반 아이템 클래스 설계하기 인터페이스 이해하기1️⃣ 인터페이스란?인터페이스 (Interface)란 클래스 (또는 오브젝트)가 반드시 구현해야 할 함수 목록만을 미리 정의해 두고, 실제&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://devcol.tistory.com/108&quot;&gt;[Unreal Engine/UE 기초] - 충돌 이벤트로 획득되는 아이템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781211363080&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;충돌 이벤트로 획득되는 아이템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;충돌 이벤트로 획득되는 아이템 구현하기 이전 포스팅에서는 클래스 구조만 짜고 로직은 비여있던 상태.이전 포스팅: [Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼 &quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/108&quot; data-og-url=&quot;https://devcol.tistory.com/108&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/usseC/dJMb88e84Rw/q2vM2cRV1xYSSwwGwMCYu1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/lg8Ak/dJMb84qgXWz/DNq0qEzBG0sApFbp7nw8k0/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/ulNRY/dJMb83Srmsy/4jxZqnPrqkOy4bgB8aksmK/img.png?width=1596&amp;amp;height=489&amp;amp;face=0_0_1596_489&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/108&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/108&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/usseC/dJMb88e84Rw/q2vM2cRV1xYSSwwGwMCYu1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/lg8Ak/dJMb84qgXWz/DNq0qEzBG0sApFbp7nw8k0/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/ulNRY/dJMb83Srmsy/4jxZqnPrqkOy4bgB8aksmK/img.png?width=1596&amp;amp;height=489&amp;amp;face=0_0_1596_489');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;충돌 이벤트로 획득되는 아이템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;충돌 이벤트로 획득되는 아이템 구현하기 이전 포스팅에서는 클래스 구조만 짜고 로직은 비여있던 상태.이전 포스팅: [Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://devcol.tistory.com/109&quot;&gt;[Unreal Engine/UE 기초] - 아이템 스폰 및 레벨 데이터 관리하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781211361626&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;아이템 스폰 및 레벨 데이터 관리하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;아이템 스폰 및 레벨 데이터 관리하기 랜덤 위치에 아이템 스폰하기 1️⃣ 레벨 셋팅하기Resources 폴더에 Maps 폴더에는 3개의 레벨이 이미 존재합니다. 각각 난이도에 따라서 크기가 다른 맵이고, &quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/109&quot; data-og-url=&quot;https://devcol.tistory.com/109&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bb7rOB/dJMb9lMjLJO/5kTyg5YcZObBNMipdSgoKK/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/bab4de/dJMb9cBQjCV/WVs1kCtDKwGDGpLGykbOb1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/bjzwRD/dJMb9iaZqLR/5u93kLFlxAX5jUZeK1Tjp0/img.png?width=943&amp;amp;height=571&amp;amp;face=0_0_943_571&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/109&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/109&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bb7rOB/dJMb9lMjLJO/5kTyg5YcZObBNMipdSgoKK/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/bab4de/dJMb9cBQjCV/WVs1kCtDKwGDGpLGykbOb1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/bjzwRD/dJMb9iaZqLR/5u93kLFlxAX5jUZeK1Tjp0/img.png?width=943&amp;amp;height=571&amp;amp;face=0_0_943_571');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;아이템 스폰 및 레벨 데이터 관리하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;아이템 스폰 및 레벨 데이터 관리하기 랜덤 위치에 아이템 스폰하기 1️⃣ 레벨 셋팅하기Resources 폴더에 Maps 폴더에는 3개의 레벨이 이미 존재합니다. 각각 난이도에 따라서 크기가 다른 맵이고,&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://devcol.tistory.com/110&quot;&gt;[Unreal Engine/UE 기초] - 캐릭터 체력 및 점수 관리 시스템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781211362700&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;캐릭터 체력 및 점수 관리 시스템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;캐릭터 체력 및 점수 관리 시스템 구현하기 캐릭터 체력 시스템 구현하기 1️⃣ 캐릭터 클래스에 체력 변수 및 함수 선언PlayerState를 쓰지 않는 이유PlayerState: 각 플레이어마다의 어떤 정보를 관&quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/110&quot; data-og-url=&quot;https://devcol.tistory.com/110&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/to8Hp/dJMb84qgXWB/XkF0sv4nkNFVMwPN3RxyiK/img.png?width=773&amp;amp;height=359&amp;amp;face=0_0_773_359,https://scrap.kakaocdn.net/dn/in3Hi/dJMb86O97yR/xLKESERIx6levctoUfRwE1/img.png?width=773&amp;amp;height=359&amp;amp;face=0_0_773_359,https://scrap.kakaocdn.net/dn/bul1bf/dJMb82MLv19/7XshaErT4bI4caYIunjHmK/img.png?width=915&amp;amp;height=558&amp;amp;face=0_0_915_558&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/110&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/110&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/to8Hp/dJMb84qgXWB/XkF0sv4nkNFVMwPN3RxyiK/img.png?width=773&amp;amp;height=359&amp;amp;face=0_0_773_359,https://scrap.kakaocdn.net/dn/in3Hi/dJMb86O97yR/xLKESERIx6levctoUfRwE1/img.png?width=773&amp;amp;height=359&amp;amp;face=0_0_773_359,https://scrap.kakaocdn.net/dn/bul1bf/dJMb82MLv19/7XshaErT4bI4caYIunjHmK/img.png?width=915&amp;amp;height=558&amp;amp;face=0_0_915_558');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;캐릭터 체력 및 점수 관리 시스템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;캐릭터 체력 및 점수 관리 시스템 구현하기 캐릭터 체력 시스템 구현하기 1️⃣ 캐릭터 클래스에 체력 변수 및 함수 선언PlayerState를 쓰지 않는 이유PlayerState: 각 플레이어마다의 어떤 정보를 관&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://devcol.tistory.com/111&quot;&gt;[Unreal Engine/UE 기초] - 게임 루프 설계를 통한 게임 흐름 제어하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781211361659&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;게임 루프 설계를 통한 게임 흐름 제어하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;게임 루프 설계를 통한 게임 흐름 제어하기 GameState를 이용한 게임 루프 구현하기 게임루프: 보통 게임의 핵심적인 흐름을 얘기합니다. 즉 게임이 시작할 때부터 종료까지 수행하는 단계들게임&quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/111&quot; data-og-url=&quot;https://devcol.tistory.com/111&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/m3HSO/dJMb8Yp3LZc/oDKcOSmHa6KQokX0K8otyK/img.png?width=800&amp;amp;height=566&amp;amp;face=0_0_800_566,https://scrap.kakaocdn.net/dn/bezEhJ/dJMb8TCh97F/a38cyWkwwklT9XZIOkmAI0/img.png?width=800&amp;amp;height=566&amp;amp;face=0_0_800_566,https://scrap.kakaocdn.net/dn/dBmfWn/dJMb8Yp3LZb/ZKEpbaswdrCszr1LfiKXDk/img.png?width=1167&amp;amp;height=827&amp;amp;face=0_0_1167_827&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/111&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/111&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/m3HSO/dJMb8Yp3LZc/oDKcOSmHa6KQokX0K8otyK/img.png?width=800&amp;amp;height=566&amp;amp;face=0_0_800_566,https://scrap.kakaocdn.net/dn/bezEhJ/dJMb8TCh97F/a38cyWkwwklT9XZIOkmAI0/img.png?width=800&amp;amp;height=566&amp;amp;face=0_0_800_566,https://scrap.kakaocdn.net/dn/dBmfWn/dJMb8Yp3LZb/ZKEpbaswdrCszr1LfiKXDk/img.png?width=1167&amp;amp;height=827&amp;amp;face=0_0_1167_827');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;게임 루프 설계를 통한 게임 흐름 제어하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;게임 루프 설계를 통한 게임 흐름 제어하기 GameState를 이용한 게임 루프 구현하기 게임루프: 보통 게임의 핵심적인 흐름을 얘기합니다. 즉 게임이 시작할 때부터 종료까지 수행하는 단계들게임&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/114&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; [Unreal Engine/UE 기초] - UI 위젯 설계와 실시간 데이터 연동하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781211367135&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;UI 위젯 설계와 실시간 데이터 연동하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;UI 위젯 설계와 실시간 데이터 연동하기 | [언리얼 엔진 C++ (Unreal Engine C++)] UMG (User Widget) 위젯 기초 디자인 이해하기 1️⃣ HUD (Heads-Up Display)란?HUD는 게임 내에서 플레이어에게 정보를 제공하기 위&quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/114&quot; data-og-url=&quot;https://devcol.tistory.com/114&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dWdB9W/dJMb84qgXWC/Giz2KwYRqTn2WeK2KDaatK/img.gif?width=400&amp;amp;height=203&amp;amp;face=0_0_400_203,https://scrap.kakaocdn.net/dn/cm53lH/dJMb83SrmsD/w26ooHE74oYMXYlki4IuB0/img.gif?width=400&amp;amp;height=203&amp;amp;face=0_0_400_203,https://scrap.kakaocdn.net/dn/lRvyB/dJMb88e84Rx/BNI790t4aQcMGrKGszOEI0/img.png?width=1392&amp;amp;height=523&amp;amp;face=0_0_1392_523&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/114&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/114&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dWdB9W/dJMb84qgXWC/Giz2KwYRqTn2WeK2KDaatK/img.gif?width=400&amp;amp;height=203&amp;amp;face=0_0_400_203,https://scrap.kakaocdn.net/dn/cm53lH/dJMb83SrmsD/w26ooHE74oYMXYlki4IuB0/img.gif?width=400&amp;amp;height=203&amp;amp;face=0_0_400_203,https://scrap.kakaocdn.net/dn/lRvyB/dJMb88e84Rx/BNI790t4aQcMGrKGszOEI0/img.png?width=1392&amp;amp;height=523&amp;amp;face=0_0_1392_523');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;UI 위젯 설계와 실시간 데이터 연동하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;UI 위젯 설계와 실시간 데이터 연동하기 | [언리얼 엔진 C++ (Unreal Engine C++)] UMG (User Widget) 위젯 기초 디자인 이해하기 1️⃣ HUD (Heads-Up Display)란?HUD는 게임 내에서 플레이어에게 정보를 제공하기 위&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/pages/Unreal-Engine-%EC%96%B8%EB%A6%AC%EC%96%BC-%EC%97%94%EC%A7%84&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;[페이지] Unreal Engine | 언리얼 엔진&lt;/b&gt;&lt;/a&gt;&lt;/h4&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;</description>
      <category>Unreal Engine/UE 기초</category>
      <category>C++</category>
      <category>Devlog</category>
      <category>Programming</category>
      <category>UE</category>
      <category>UE5</category>
      <category>Unreal engine</category>
      <category>게임 개발</category>
      <category>기초</category>
      <category>언리얼 엔진</category>
      <category>프로그래밍</category>
      <author>DevCol</author>
      <guid isPermaLink="true">https://devcol.tistory.com/115</guid>
      <comments>https://devcol.tistory.com/115#entry115comment</comments>
      <pubDate>Fri, 12 Jun 2026 05:57:31 +0900</pubDate>
    </item>
    <item>
      <title>UI 위젯 설계와 실시간 데이터 연동하기 | [언리얼 엔진 C++ (Unreal Engine C++)]</title>
      <link>https://devcol.tistory.com/114</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt;UI 위젯 설계와 실시간 데이터 연동하기&lt;/span&gt; | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a1&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;UMG&amp;nbsp;(User&amp;nbsp;Widget)&amp;nbsp;위젯&amp;nbsp;기초&amp;nbsp;디자인&amp;nbsp;이해하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣ HUD (Heads-Up Display)란?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HUD는 게임 내에서 &lt;b&gt;플레이어에게 정보를 제공하기 위한 화면&lt;/b&gt;을 말합니다. 일반적으로 게임 중 화면의 일부에 배치되며, 플레이어가 현재 게임 상황을 이해하는 데 필요한 체력, 미니맵, 퀘스트 업데이트와 같은 데이터를 제공합니다.&lt;/li&gt;
&lt;li&gt;언리얼 엔진에서는 다음과 같은 &lt;b&gt;HUD 시스템이 있습니다&lt;/b&gt;.
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Canvas 기반 HUD&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AHUD 클래스를 상속하여 구현&lt;/li&gt;
&lt;li&gt;기본적인 2D 그리기 작업(텍스트, 이미지 등) 가능&lt;/li&gt;
&lt;li&gt;레거시 방식으로 간주되며, 간단한 HUD에 적합&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;UMG (Unreal Motion Graphics)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;언리얼 엔진의 &lt;b&gt;Widget Blueprint&lt;/b&gt;를 이용한 UI 시스템&lt;/li&gt;
&lt;li&gt;더 직관적이고 강력한 HUD 디자인 가능&lt;/li&gt;
&lt;li&gt;다양한 위젯(Text, Button, Image 등)을 사용하여 HUD를 제작&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;우리는 여기서 UMG 방식을 따르도록 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유저 인터페이스 및 HUD 관련 UE 공식 문서: &lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/user-interfaces-and-huds-in-unreal-engine?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dev.epicgames.com/documentation/unreal-engine/user-interfaces-and-huds-in-unreal-engine?lang=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781175805445&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;User Interfaces and HUDs in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&quot; data-og-description=&quot;Guides and information for artists and programmers creating user interfaces such as menus and HUDs in Unreal Engine&quot; data-og-host=&quot;dev.epicgames.com&quot; data-og-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/user-interfaces-and-huds-in-unreal-engine?lang=ko&quot; data-og-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/user-interfaces-and-huds-in-unreal-engine&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/WAnxR/dJMb9lMjJQ5/bmDYHdb5PASRPeKkAvEgqK/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/ggGPR/dJMb9iIPbAY/kluDdrqr2DnXdiz4DkYA4k/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/DRnjx/dJMb9eTXO8J/Zmna3GIoKvnmRyPyKws8R1/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/user-interfaces-and-huds-in-unreal-engine?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/user-interfaces-and-huds-in-unreal-engine?lang=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/WAnxR/dJMb9lMjJQ5/bmDYHdb5PASRPeKkAvEgqK/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/ggGPR/dJMb9iIPbAY/kluDdrqr2DnXdiz4DkYA4k/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/DRnjx/dJMb9eTXO8J/Zmna3GIoKvnmRyPyKws8R1/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;User Interfaces and HUDs in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Guides and information for artists and programmers creating user interfaces such as menus and HUDs in Unreal Engine&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.epicgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UMG UI 디자이너 퀵스타트 가이드 UE 공식 문서: &lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/umg-ui-designer-quick-start-guide-in-unreal-engine?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dev.epicgames.com/documentation/unreal-engine/umg-ui-designer-quick-start-guide-in-unreal-engine?lang=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781175870796&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;UMG UI Designer Quick Start Guide in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&quot; data-og-description=&quot;Getting started with using Unreal Motion Graphics in Unreal Engine.&quot; data-og-host=&quot;dev.epicgames.com&quot; data-og-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/umg-ui-designer-quick-start-guide-in-unreal-engine?lang=ko&quot; data-og-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/umg-ui-designer-quick-start-guide-in-unreal-engine&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/f3aeP/dJMb9iIPbBk/htQCf7dIXPXAWYbxhexffk/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/brx2Tn/dJMb9hC9sEi/dCpqVgfsb1itCDRBhRmmD1/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/5eWSw/dJMb9bwaw8o/kcC0NYspFnUAZGxhjQn9p0/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/umg-ui-designer-quick-start-guide-in-unreal-engine?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/umg-ui-designer-quick-start-guide-in-unreal-engine?lang=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/f3aeP/dJMb9iIPbBk/htQCf7dIXPXAWYbxhexffk/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/brx2Tn/dJMb9hC9sEi/dCpqVgfsb1itCDRBhRmmD1/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/5eWSw/dJMb9bwaw8o/kcC0NYspFnUAZGxhjQn9p0/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;UMG UI Designer Quick Start Guide in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Getting started with using Unreal Motion Graphics in Unreal Engine.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.epicgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2️⃣ 위젯 블루프린트 (Widget Blueprint)란?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Widget Blueprint&lt;/b&gt;란?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;언리얼 엔진에서 &lt;b&gt;UI (User Interface)를 시각적으로 설계&lt;/b&gt;할 수 있도록 제공되는 에디터용 블루프린트입니다.&lt;/li&gt;
&lt;li&gt;개발자는 이 블루프린트 안에서 &lt;b&gt;Text Block&lt;/b&gt;, &lt;b&gt;Button&lt;/b&gt;, &lt;b&gt;Image&lt;/b&gt; 등 다양한 UI 요소를 &lt;b&gt;드래그 앤 드롭&lt;/b&gt;으로 간편하게 배치할 수 있습니다.&lt;/li&gt;
&lt;li&gt;이렇게 만든 &lt;b&gt;Widget Blueprint&lt;/b&gt;는 게임 화면에 표시되는 UI가 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Widget Blueprint 생성 경로&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Content Browser에서 Contents 하위에 UI 폴더를 만들고, 그 하위에 또 Widget 폴더를 만듭니다.&lt;/li&gt;
&lt;li&gt;Widget 폴더에서 우클릭하고 User Interface - Widget Blueprint를 선택하고 부모 클래스로 User Widget을 선택해 줍니다. 그리고 WBP_HUD 라는 이름으로 생성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;311&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1BEG6/dJMcaaMnnHJ/Iao4VK54L3kXXFZTMV11q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1BEG6/dJMcaaMnnHJ/Iao4VK54L3kXXFZTMV11q0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1BEG6/dJMcaaMnnHJ/Iao4VK54L3kXXFZTMV11q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1BEG6%2FdJMcaaMnnHJ%2FIao4VK54L3kXXFZTMV11q0%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;670&quot; height=&quot;311&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;311&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;605&quot; data-origin-height=&quot;462&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFB6wC/dJMcabq0B3k/eywMTrp1W9HICS4gH0hX3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFB6wC/dJMcabq0B3k/eywMTrp1W9HICS4gH0hX3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFB6wC/dJMcabq0B3k/eywMTrp1W9HICS4gH0hX3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFB6wC%2FdJMcabq0B3k%2FeywMTrp1W9HICS4gH0hX3k%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;605&quot; height=&quot;462&quot; data-origin-width=&quot;605&quot; data-origin-height=&quot;462&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt;Widget Blueprint 열기&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;생성된 위젯을 &lt;b&gt;더블 클릭&lt;/b&gt;하면, 오른쪽 상단에 &lt;b&gt;Designer 탭&lt;/b&gt;과 &lt;b&gt;Graph 탭&lt;/b&gt;이 있는 것을 확인할 수 있습니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Designer 탭&lt;/b&gt;: UI를 배치하는 공간입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Graph 탭&lt;/b&gt;: 블루프린트 이벤트 그래프(로직)을 작성하는 공간입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1392&quot; data-origin-height=&quot;523&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dtUTpT/dJMcafUuvEH/97YzEPdgd4N5HxCzh5J3tK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dtUTpT/dJMcafUuvEH/97YzEPdgd4N5HxCzh5J3tK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dtUTpT/dJMcafUuvEH/97YzEPdgd4N5HxCzh5J3tK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdtUTpT%2FdJMcafUuvEH%2F97YzEPdgd4N5HxCzh5J3tK%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;1392&quot; height=&quot;523&quot; data-origin-width=&quot;1392&quot; data-origin-height=&quot;523&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3️⃣ &lt;b&gt;UI 요소 (UI Elements&lt;/b&gt;)란?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;UI Elements (UI 요소)란?&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;언리얼 엔진에서 제공하는 다양한 UI 구성 요소를 말합니다. 왼쪽 상단에 보면 Palette 탭이 있으며, 여기에는 다양한 UI 요소들을 제공합니다.&lt;/li&gt;
&lt;li&gt;예를 들어, &lt;b&gt;Text Block (텍스트 표시용)&lt;/b&gt;, &lt;b&gt;Button (버튼)&lt;/b&gt;, &lt;b&gt;Progress Bar (게이지 표시)&lt;/b&gt; 등이 있습니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Text Block&lt;/b&gt;: 캐릭터 체력, Score(점수), Time(남은 시간) 등 텍스트를 보여줄 때&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Button&lt;/b&gt;: &amp;ldquo;Start Game&amp;rdquo;, &amp;ldquo;Quit Game&amp;rdquo; 등 클릭 이벤트가 필요한 메뉴 버튼&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Progress Bar&lt;/b&gt;: 체력 게이지나 로딩 게이지 등을 시각적으로 표시할 때&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;208&quot; data-origin-height=&quot;412&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pMkYc/dJMcaccmi2q/XfYS3wM5AL5GCoJtbct0A0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pMkYc/dJMcaccmi2q/XfYS3wM5AL5GCoJtbct0A0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pMkYc/dJMcaccmi2q/XfYS3wM5AL5GCoJtbct0A0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpMkYc%2FdJMcaccmi2q%2FXfYS3wM5AL5GCoJtbct0A0%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;208&quot; height=&quot;412&quot; data-origin-width=&quot;208&quot; data-origin-height=&quot;412&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4️⃣ &lt;b&gt;점수, 시간, 레벨 표시를 위한 UI Widget 디자인하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Widget Blueprint의 Designer 탭에서 배치&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;마우스로 &lt;b&gt;드래그 앤 드롭&lt;/b&gt;하여 원하는 위치에 배치할 수 있습니다. &lt;b&gt;Details 패널&lt;/b&gt;에서 해당 요소의 크기, 색상, 폰트, 정렬 방식 등을 원하는 대로 수정할 수 있습니다.&lt;/li&gt;
&lt;li&gt;우선, Palette에서 Panel 중 Canvas Panel을 찾아서 클릭합니다. &lt;b&gt;Canvas Panel은&lt;/b&gt; 모든 UI 요소를 포함할 수 있는 &amp;ldquo;큰 도화지&amp;rdquo; 같은 역할을 합니다. UI 요소들을 자유롭게 배치할 수 있는 가장 기본적인 레이아웃 패널이기도 합니다.&lt;/li&gt;
&lt;li&gt;Canvas Panel을 드래그 앤 드롭하여 Designer Tab에 끌어다 놓습니다. 그러면 왼쪽 아래 Hierarchy 탭을 보면 Canvas Panel이 가장 루트로 생성된 것을 확인할 수 있습니다.&lt;/li&gt;
&lt;li&gt;오른쪽 상단에 보면, Screen Size를 결정할 수 있는 부분이 있는데 여기서 가장 대중적인 화면 크기인 1920 x 1080 (16:9 Full HD) 사이즈로 설정하기 선택해줍니다.(구버전은 21.5-24&quot; monitor 라고 나옵니다)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1491&quot; data-origin-height=&quot;592&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DbzrS/dJMcadWCSrE/2XBn2QKv97AJMWMA4T40M0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DbzrS/dJMcadWCSrE/2XBn2QKv97AJMWMA4T40M0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DbzrS/dJMcadWCSrE/2XBn2QKv97AJMWMA4T40M0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDbzrS%2FdJMcadWCSrE%2F2XBn2QKv97AJMWMA4T40M0%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;1491&quot; height=&quot;592&quot; data-origin-width=&quot;1491&quot; data-origin-height=&quot;592&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다음으로 Palette에서 Common 리스트 중에서 Text를 선택 &amp;rarr; Canvas Panel 위로 드래그 앤 드롭합니다&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;511&quot; data-origin-height=&quot;295&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbI4vG/dJMcacpVXdW/Nxno3mtxqf6H8AEnZaMbKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbI4vG/dJMcacpVXdW/Nxno3mtxqf6H8AEnZaMbKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbI4vG/dJMcacpVXdW/Nxno3mtxqf6H8AEnZaMbKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbI4vG%2FdJMcacpVXdW%2FNxno3mtxqf6H8AEnZaMbKK%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;511&quot; height=&quot;295&quot; data-origin-width=&quot;511&quot; data-origin-height=&quot;295&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;원하는 Font 에셋 만들기&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;우리는 폰트 스타일을 적용하기 위해서는 콘텐츠 폴더에 Font를 import 해야합니다. 미리 &lt;b&gt;.ttf&lt;/b&gt;나 &lt;b&gt;.otf&lt;/b&gt; 확장자를 가진 폰트 파일을 다운로드 받습니다.&lt;/li&gt;
&lt;li&gt;Contents - UI - Fonts 폴더를 미리 만들어둡니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;마우스 우클릭&lt;/b&gt; &amp;rarr; &lt;b&gt;Import to &amp;lsquo;/Game/UI/Fonts&amp;rsquo;를&lt;/b&gt; 클릭하면 파일 선택 창에서 .ttf나 .otf 폰트 파일을 선택하면, 언리얼 엔진 내로 임포트가 진행됩니다.&lt;/li&gt;
&lt;li&gt;임포트가 완료되면, 콘텐츠 브라우저에 &lt;b&gt;새로운 폰트 에셋&lt;/b&gt;이 생깁니다.&lt;/li&gt;
&lt;li&gt;이렇게 생성된 Font Asset을 Font Family를 지정할 때 이 에셋을 적용할 수 있습니다. 언리얼엔진에서는 기본적으로 Roboto 폰트 스타일만은 제공합니다.&lt;/li&gt;
&lt;li&gt;이번 프로젝트에서는 무료폰트인 함렛을 사용했습니다. : &lt;a href=&quot;https://github.com/hyper-type/hahmlet&quot;&gt;https://github.com/hyper-type/hahmlet&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1781193073124&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - hyper-type/hahmlet: Hahmlet font by Minjoo Ham and Mark Fr&amp;ouml;mberg aka Hypertype&quot; data-og-description=&quot;Hahmlet font by Minjoo Ham and Mark Fr&amp;ouml;mberg aka Hypertype - hyper-type/hahmlet&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/hyper-type/hahmlet&quot; data-og-url=&quot;https://github.com/hyper-type/hahmlet&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/4UGQm/dJMb8WeH9ed/aBHWuCRYcIWkR0pQDIWRDk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bsIaYn/dJMb8U811em/EVVQWQEp60nJzSKBDEpiP1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/0FATz/dJMb8RkaqsL/EJlDtFp4SNx4mXvWLkpenK/img.png?width=4096&amp;amp;height=3101&amp;amp;face=0_0_4096_3101&quot;&gt;&lt;a href=&quot;https://github.com/hyper-type/hahmlet&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/hyper-type/hahmlet&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/4UGQm/dJMb8WeH9ed/aBHWuCRYcIWkR0pQDIWRDk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bsIaYn/dJMb8U811em/EVVQWQEp60nJzSKBDEpiP1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/0FATz/dJMb8RkaqsL/EJlDtFp4SNx4mXvWLkpenK/img.png?width=4096&amp;amp;height=3101&amp;amp;face=0_0_4096_3101');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - hyper-type/hahmlet: Hahmlet font by Minjoo Ham and Mark Fr&amp;ouml;mberg aka Hypertype&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Hahmlet font by Minjoo Ham and Mark Fr&amp;ouml;mberg aka Hypertype - hyper-type/hahmlet&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://noonnu.cc/&quot;&gt;https://noonnu.cc/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781193155198&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;눈누&quot; data-og-description=&quot;상업적 이용 가능한 한글 폰트를 쉽게 찾아보세요.&quot; data-og-host=&quot;noonnu.cc&quot; data-og-source-url=&quot;https://noonnu.cc/&quot; data-og-url=&quot;https://noonnu.cc/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/3oqPi/dJMb8YXTZoO/KaYFEiSKvzT864pQrGTZC1/img.png?width=1200&amp;amp;height=628&amp;amp;face=0_0_1200_628,https://scrap.kakaocdn.net/dn/bd9ptT/dJMb8WMxXKu/fD6Ur5IRfQhpzaP3lH8kiK/img.png?width=1200&amp;amp;height=628&amp;amp;face=0_0_1200_628,https://scrap.kakaocdn.net/dn/cIL96h/dJMb8XSd8p5/rvEkHqoieRW0lqeuiAmyCk/img.jpg?width=3230&amp;amp;height=328&amp;amp;face=0_0_3230_328&quot;&gt;&lt;a href=&quot;https://noonnu.cc/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://noonnu.cc/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/3oqPi/dJMb8YXTZoO/KaYFEiSKvzT864pQrGTZC1/img.png?width=1200&amp;amp;height=628&amp;amp;face=0_0_1200_628,https://scrap.kakaocdn.net/dn/bd9ptT/dJMb8WMxXKu/fD6Ur5IRfQhpzaP3lH8kiK/img.png?width=1200&amp;amp;height=628&amp;amp;face=0_0_1200_628,https://scrap.kakaocdn.net/dn/cIL96h/dJMb8XSd8p5/rvEkHqoieRW0lqeuiAmyCk/img.jpg?width=3230&amp;amp;height=328&amp;amp;face=0_0_3230_328');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;눈누&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;상업적 이용 가능한 한글 폰트를 쉽게 찾아보세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;noonnu.cc&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a4&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;HUD Widget을 생성해 화면에 표시하기&lt;/h3&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣ &lt;b&gt;PlayerController에서 HUD 생성 로직 추가하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Widget (HUD나 UI 요소)은 보통 &lt;b&gt;PlayerController&lt;/b&gt;에서 구현하게 됩니다. 그 이유는 &lt;b&gt;Widget이 플레이어의 입력과 상호작용하며 화면에 표시되는 요소&lt;/b&gt;이기 때문입니다.&lt;/li&gt;
&lt;li&gt;MainPlayerController.h &amp;amp; .cpp 작성후 꼭!!! Project.Buid.cs 파일 에서 코드를 수정해 줘야 빌드가 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MainPlayerController.h&lt;/p&gt;
&lt;pre id=&quot;code_1781193372976&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pragma once

#include &quot;CoreMinimal.h&quot;
#include &quot;GameFramework/PlayerController.h&quot;
#include &quot;MainPlayerController.generated.h&quot;

// Declaration
class UInputMappingContext;  // IMC 관련 전방 선언
class UInputAction;// IA 관련 전방 선언


// Enhanced Input에서 액션 값을 받을 때 사용하는 구조체
struct FInputActionValue;

UCLASS()
class BC_CH3_ASSIGNMENT_5_API AMainPlayerController : public APlayerController
{
	GENERATED_BODY()

public:
	AMainPlayerController();
	
	// 에디터에서 세팅할 IMC
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=&quot;Input&quot;)
	UInputMappingContext* InputMappingContext;
	
	// IA
	// IA_Move를 지정할 변수
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=&quot;Input&quot;)
	UInputAction* MoveAction;
	// IA_Jump를 지정할 변수
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=&quot;Input&quot;)
	UInputAction* JumpAction;
	// IA_Look를 지정할 변수
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=&quot;Input&quot;)
	UInputAction* LookAction;
	// IA_Sprint를 지정할 변수
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Input&quot;)
	UInputAction* SprintAction;
	
	// UMG 위젯 클래스를 에디터에서 할당받을 변수
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;UI&quot;)
	TSubclassOf&amp;lt;UUserWidget&amp;gt; HUDWidgetClass;
	
	
protected:
	virtual void BeginPlay() override;

	
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;MainPlayerController.cpp&lt;/p&gt;
&lt;pre id=&quot;code_1781193501163&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;MainPlayerController.h&quot;
#include &quot;EnhancedInputSubsystems.h&quot;
#include &quot;EnhancedInputSubsystems.h&quot; // Enhanced Input System의 Local Player Subsystem을 사용하기 위해 포함
#include &quot;Blueprint/UserWidget.h&quot;

// 어차피 블루프린트 상에서 전부 다 초기화를 하기 때문에 여기서는 전부 다 nullptr 처리
AMainPlayerController::AMainPlayerController()
	: InputMappingContext(nullptr),
	  MoveAction(nullptr),
	  JumpAction(nullptr),
	  LookAction(nullptr),
	  SprintAction(nullptr)

{
}

void AMainPlayerController::BeginPlay()
{
	Super::BeginPlay();

	// GetLocalPlayer():현재 PlayerController에 연결된 Local Player 객체를 가져옴     
	// Local Player 는 그 플레이어의 입력이나 화면 뷰 같은 것을 관리하는 어떤 객체
	if (ULocalPlayer* LocalPlayer = GetLocalPlayer())
	{
		// Local Player에서 EnhancedInputLocalPlayerSubsystem을 획득
		// UEnhancedInputLocalPlayerSubsystem: 입력 시스템을 관리 (IMC 추가 혹은 삭제하는 역할)
		if (UEnhancedInputLocalPlayerSubsystem* Subsystem =
			LocalPlayer-&amp;gt;GetSubsystem&amp;lt;UEnhancedInputLocalPlayerSubsystem&amp;gt;())
		{
			if (InputMappingContext)
			{
				// Subsystem을 통해 우리가 할당한 IMC를 활성화
				// 우선순위(Priority)는 0이 가장 높은 우선순위
				Subsystem-&amp;gt;AddMappingContext(InputMappingContext, 0);
			}
		}
	}

	// HUD 위젯 생성 및 표시
	if (HUDWidgetClass)
	{
		UUserWidget* HUDWidget = CreateWidget&amp;lt;UUserWidget&amp;gt;(this, HUDWidgetClass);
		if (HUDWidget)
		{
			HUDWidget-&amp;gt;AddToViewport();
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1210&quot; data-origin-height=&quot;247&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWQV6i/dJMcahxZvw2/eriahzcGy6O3QkUfiLOe9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWQV6i/dJMcahxZvw2/eriahzcGy6O3QkUfiLOe9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWQV6i/dJMcahxZvw2/eriahzcGy6O3QkUfiLOe9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWQV6i%2FdJMcahxZvw2%2FeriahzcGy6O3QkUfiLOe9k%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;1210&quot; height=&quot;247&quot; data-origin-width=&quot;1210&quot; data-origin-height=&quot;247&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;1395&quot; data-origin-height=&quot;659&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dVmGN9/dJMcaiRaG3u/j4U5iBX9Z2rvAf6dDZojk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dVmGN9/dJMcaiRaG3u/j4U5iBX9Z2rvAf6dDZojk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dVmGN9/dJMcaiRaG3u/j4U5iBX9Z2rvAf6dDZojk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdVmGN9%2FdJMcaiRaG3u%2Fj4U5iBX9Z2rvAf6dDZojk0%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;1395&quot; height=&quot;659&quot; data-origin-width=&quot;1395&quot; data-origin-height=&quot;659&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BC_Ch3_Assignment_5.Build.cs&lt;/p&gt;
&lt;pre id=&quot;code_1781193751466&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Copyright Epic Games, Inc. All Rights Reserved.

using UnrealBuildTool;

public class BC_Ch3_Assignment_5 : ModuleRules
{
	public BC_Ch3_Assignment_5(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
	
		PublicDependencyModuleNames.AddRange(new string[]
		{
			&quot;Core&quot;, &quot;CoreUObject&quot;, &quot;Engine&quot;, &quot;InputCore&quot;, &quot;EnhancedInput&quot;,
			&quot;UMG&quot; // 추가
		});

		PrivateDependencyModuleNames.AddRange(new string[] {  });

		// Uncomment if you are using Slate UI
		// PrivateDependencyModuleNames.AddRange(new string[] { &quot;Slate&quot;, &quot;SlateCore&quot; });
		
		// Uncomment if you are using online features
		// PrivateDependencyModuleNames.Add(&quot;OnlineSubsystem&quot;);

		// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;위의 코드를 조금 설명하자면, 현재 프로젝트 내에서 필수적으로 사용하는 엔진 기능들&amp;nbsp; 이라고 보시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;PublicDependencyModuleNames&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Core: 엔진의 기본 기능들&lt;/li&gt;
&lt;li&gt;CoreUObject: 주로 리플렉션 시스템, 가비지 컬렉터&lt;/li&gt;
&lt;li&gt;Engine: 게임엔진의 주요 기능&lt;/li&gt;
&lt;li&gt;InputCore: 입력 시스템&lt;/li&gt;
&lt;li&gt;EnhancedInput: Enhanced Input System&lt;/li&gt;
&lt;li&gt;UMG:Widget Blue Print 관련 모델 (HUD 포함)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;빌드 후, 이전에 만들어 두었던 BP_MainPlayerController에 보시면 UI-&amp;gt;HUDWidget Class 가 생성되었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;982&quot; data-origin-height=&quot;536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXilc1/dJMcag6Tfsv/keA8eJKryZFyjZMjbRBYtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXilc1/dJMcag6Tfsv/keA8eJKryZFyjZMjbRBYtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXilc1/dJMcag6Tfsv/keA8eJKryZFyjZMjbRBYtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXilc1%2FdJMcag6Tfsv%2FkeA8eJKryZFyjZMjbRBYtK%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;982&quot; height=&quot;536&quot; data-origin-width=&quot;982&quot; data-origin-height=&quot;536&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;방금 만든 WBP_HUD 를 지정해 줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;743&quot; data-origin-height=&quot;67&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tluFd/dJMcacQWaYP/D2IRpyncK7QGZ1AVaSUJbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tluFd/dJMcacQWaYP/D2IRpyncK7QGZ1AVaSUJbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tluFd/dJMcacQWaYP/D2IRpyncK7QGZ1AVaSUJbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtluFd%2FdJMcacQWaYP%2FD2IRpyncK7QGZ1AVaSUJbk%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;743&quot; height=&quot;67&quot; data-origin-width=&quot;743&quot; data-origin-height=&quot;67&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Play Mode 와 Play Setting 에 있는 Advanced Setting 으로 가셔서&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;384&quot; data-origin-height=&quot;453&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/coY6fh/dJMcadoJMBp/4ZBX6uXmRsPBj8fes4MMh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/coY6fh/dJMcadoJMBp/4ZBX6uXmRsPBj8fes4MMh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/coY6fh/dJMcadoJMBp/4ZBX6uXmRsPBj8fes4MMh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcoY6fh%2FdJMcadoJMBp%2F4ZBX6uXmRsPBj8fes4MMh1%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;384&quot; height=&quot;453&quot; data-origin-width=&quot;384&quot; data-origin-height=&quot;453&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뷰표트 세팅을 아까와 동일하게 1920 X 1080으로 변경해 줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;815&quot; data-origin-height=&quot;196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chj9ls/dJMcab5A1QU/sN4OnVwUc9eOWdug1ZWDQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chj9ls/dJMcab5A1QU/sN4OnVwUc9eOWdug1ZWDQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chj9ls/dJMcab5A1QU/sN4OnVwUc9eOWdug1ZWDQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fchj9ls%2FdJMcab5A1QU%2FsN4OnVwUc9eOWdug1ZWDQ1%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;815&quot; height=&quot;196&quot; data-origin-width=&quot;815&quot; data-origin-height=&quot;196&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;이제 플레이해보면 UI&amp;nbsp; 가 적용된 모습이 보입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;836&quot; data-origin-height=&quot;436&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mTPa9/dJMcahLvMWo/92Y09f3AVhF7SrogkwHI1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mTPa9/dJMcahLvMWo/92Y09f3AVhF7SrogkwHI1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mTPa9/dJMcahLvMWo/92Y09f3AVhF7SrogkwHI1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmTPa9%2FdJMcahLvMWo%2F92Y09f3AVhF7SrogkwHI1K%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;836&quot; height=&quot;436&quot; data-origin-width=&quot;836&quot; data-origin-height=&quot;436&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;혹시라도 UI 가 이상하다면 New Editor Window (PIE) 로 플레이해 보세요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;410&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xXUSz/dJMb99Nqw9V/8sOlkSX8cB7tTvRy5YuIr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xXUSz/dJMb99Nqw9V/8sOlkSX8cB7tTvRy5YuIr0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xXUSz/dJMb99Nqw9V/8sOlkSX8cB7tTvRy5YuIr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxXUSz%2FdJMb99Nqw9V%2F8sOlkSX8cB7tTvRy5YuIr0%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;410&quot; height=&quot;252&quot; data-origin-width=&quot;410&quot; data-origin-height=&quot;252&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;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style2&quot; data-ke-type=&quot;horizontalRule&quot; /&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;h3 id=&quot;a4&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;HUD 위젯과 GameState 데이터 연동하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 바인딩 vs SetText&amp;nbsp;방식으로&amp;nbsp;위젯&amp;nbsp;갱신하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣ &lt;b&gt;GameState에서 점수 데이터 바인딩하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Text Block 선택 &amp;amp; Bind 버튼 클릭&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;언리얼 에디터의 &lt;b&gt;WBP_HUD&lt;/b&gt; (Widget Blueprint)를 엽니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Designer 탭&lt;/b&gt;에서 점수를 표시할 Score를 표시할 Text Block을 하나 선택합니다.&lt;/li&gt;
&lt;li&gt;오른쪽 &lt;b&gt;Details 패널&lt;/b&gt;에서 Text 속성을 찾습니다.&lt;/li&gt;
&lt;li&gt;Text 항목 오른쪽에 있는 &lt;b&gt;Bind&lt;/b&gt; 버튼을 클릭 &amp;rarr; &lt;b&gt;Create Binding&lt;/b&gt;을 선택합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image.png&quot; data-origin-width=&quot;488&quot; data-origin-height=&quot;110&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dTsG5j/dJMcaaFFM43/P9em7CWf7FMJM4jkNXdVS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dTsG5j/dJMcaaFFM43/P9em7CWf7FMJM4jkNXdVS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dTsG5j/dJMcaaFFM43/P9em7CWf7FMJM4jkNXdVS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdTsG5j%2FdJMcaaFFM43%2FP9em7CWf7FMJM4jkNXdVS0%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;488&quot; height=&quot;110&quot; data-filename=&quot;image.png&quot; data-origin-width=&quot;488&quot; data-origin-height=&quot;110&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt;자동 생성된 함수 확인&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Binding 버튼을 클릭하면, &lt;b&gt;Graph 탭&lt;/b&gt; 또는 &lt;b&gt;이벤트 그래프&lt;/b&gt;에 새 블루프린트 함수가 자동 생성됩니다.&lt;/li&gt;
&lt;li&gt;함수 이름은 보통 &amp;ldquo;GetText&amp;rdquo; 같은 식으로 자동으로 정해지는데, 우리는 왼쪽에 Functions 목록에서 함수를 클릭하고 F2를 눌러서 GetScore로 이름을 변경하도록 합시다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GameState에서 Score 읽어오기&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새로 생성된 바인딩 함수 안에서 &lt;b&gt;GameState&lt;/b&gt;를 가져와야 합니다. 블루프린트에서는 아래와 같은 순서로 작업합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image2.png&quot; data-origin-width=&quot;979&quot; data-origin-height=&quot;298&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsDPKV/dJMcahxZvRS/JWoOr6rIF2fF4ojRwQdkh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsDPKV/dJMcahxZvRS/JWoOr6rIF2fF4ojRwQdkh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsDPKV/dJMcahxZvRS/JWoOr6rIF2fF4ojRwQdkh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsDPKV%2FdJMcahxZvRS%2FJWoOr6rIF2fF4ojRwQdkh0%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;979&quot; height=&quot;298&quot; data-filename=&quot;image2.png&quot; data-origin-width=&quot;979&quot; data-origin-height=&quot;298&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;마지막에 가져온 Score를 Format Text를 통해 표시를 만들어준 후 이 문자열을 &lt;b&gt;Return Node&lt;/b&gt;로 반환하면, Text Block에 해당 문자열이 표시됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장점: 초급자에게는&amp;nbsp;Binding&amp;nbsp;방식이&amp;nbsp;코드를&amp;nbsp;많이&amp;nbsp;작성하지&amp;nbsp;않아도&amp;nbsp;되므로&amp;nbsp;더&amp;nbsp;직관적입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단점: UI 복잡해지면 SetText 에 비해서 성능면에서 떨어지게 됩니다.&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2️⃣ SetText 방식으로 위젯 갱신하기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MainGameState 에서 주요 변수들을 관리하고 있기 때문에 여기에서 위젯을 갱신하도록 구현하겠습니다.&lt;/li&gt;
&lt;li&gt;Input을 입력받고 관리하는 쪽은 PlayerController 쪽에서 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781195815443&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pragma once

#include &quot;CoreMinimal.h&quot;
#include &quot;GameFramework/GameState.h&quot;
#include &quot;MainGameState.generated.h&quot;


UCLASS()
class BC_CH3_ASSIGNMENT_5_API AMainGameState : public AGameState
{
	GENERATED_BODY()
	
public:
	AMainGameState();	
	
	virtual void BeginPlay() override;
	
	// === Variables ===
	// 전역 점수를 저장하는 변수
	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category=&quot;Score&quot;)
	int32 Score;

	// 현재 레벨에서 스폰된 코인 개수
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = &quot;Coin&quot;)
	int32 SpawnedCoinCount;
	// 플레이어가 수집한 코인 개수
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = &quot;Coin&quot;)
	int32 CollectedCoinCount;
	// 각 레벨이 유지되는 시간 (초 단위)
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = &quot;Level&quot;)
	float LevelDuration;
	// 현재 진행 중인 레벨 인덱스
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = &quot;Level&quot;)
	int32 CurrentLevelIndex;
	// 전체 레벨의 개수
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = &quot;Level&quot;)
	int32 MaxLevels;
	// 실제 레벨 맵 이름 배열. 여기 있는 인덱스를 차례대로 연동
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = &quot;Level&quot;)
	TArray&amp;lt;FName&amp;gt; LevelMapNames;
	
	// 매 레벨이 끝나기 전까지 시간이 흐르도록 관리하는 타이머
	FTimerHandle LevelTimerHandle;
	
	FTimerHandle HUDUpdateTimerHandle;
	
	
	// === Func ===
	// 현재 점수를 읽는 함수
	UFUNCTION(BlueprintPure, Category=&quot;Score&quot;)
	int32 GetScore() const;
	
	// 점수를 추가해주는 함수
	UFUNCTION(BlueprintCallable, Category=&quot;Score&quot;)
	void AddScore(int32 Amount);
	
	UFUNCTION(BlueprintCallable, Category = &quot;Level&quot;)
	void OnGameOver();
	
	// 레벨을 시작할 때, 아이템 스폰 및 타이머 설정
	void StartLevel();
	// 레벨 제한 시간이 만료되었을 때 호출
	void OnLevelTimeUp();
	// 코인을 주웠을 때 호출
	void OnCoinCollected();
	// 레벨을 강제 종료하고 다음 레벨로 이동
	void EndLevel();
	void UpdateHUD();
	
};&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1781204848426&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;MainGameState.h&quot;
#include &quot;MainGameInstance.h&quot;
#include &quot;MainPlayerController.h&quot;
#include &quot;Kismet/GameplayStatics.h&quot;
#include &quot;SpawnVolume.h&quot;
#include &quot;CoinItem.h&quot;
#include &quot;Components/TextBlock.h&quot;
#include &quot;Blueprint/UserWidget.h&quot;

AMainGameState::AMainGameState()
{
	Score = 0;
	SpawnedCoinCount = 0;
	CollectedCoinCount = 0;
	LevelDuration = 30.0f; // 한 레벨당 30초
	CurrentLevelIndex = 0;
	MaxLevels = 3;
}

void AMainGameState::BeginPlay()
{
	Super::BeginPlay();

	// 게임 시작 시 첫 레벨부터 진행
	StartLevel();
	
	UpdateHUD();
	
	GetWorldTimerManager().SetTimer(
			HUDUpdateTimerHandle,
			this,
			&amp;amp;AMainGameState::UpdateHUD,
			0.1f,
			true
		);
}

int32 AMainGameState::GetScore() const
{
	return Score;
}

void AMainGameState::AddScore(int32 Amount)
{
	if (UGameInstance* GameInstance = GetGameInstance())
	{
		UMainGameInstance* MainGameInstance = Cast&amp;lt;UMainGameInstance&amp;gt;(GameInstance);
		if (MainGameInstance)
		{
			MainGameInstance-&amp;gt;AddToScore(Amount);
		}
	}
}


void AMainGameState::StartLevel()
{
	if (UGameInstance* GameInstance = GetGameInstance())
	{
		UMainGameInstance* MainGameInstance = Cast&amp;lt;UMainGameInstance&amp;gt;(GameInstance);
		if (MainGameInstance)
		{
			CurrentLevelIndex = MainGameInstance-&amp;gt;CurrentLevelIndex;
		}
	}

	// 레벨 시작 시, 코인 개수 초기화
	SpawnedCoinCount = 0;
	CollectedCoinCount = 0;
	// 현재 맵에 배치된 모든 SpawnVolume을 찾아 아이템 40개를 스폰
	TArray&amp;lt;AActor*&amp;gt; FoundVolumes;
	UGameplayStatics::GetAllActorsOfClass(GetWorld(), ASpawnVolume::StaticClass(), FoundVolumes);
	const int32 ItemToSpawn = 40;

	for (int32 i = 0; i &amp;lt; ItemToSpawn; i++)
	{
		if (FoundVolumes.Num() &amp;gt; 0)
		{
			ASpawnVolume* SpawnVolume = Cast&amp;lt;ASpawnVolume&amp;gt;(FoundVolumes[0]);
			if (SpawnVolume)
			{
				AActor* SpawnedActor = SpawnVolume-&amp;gt;SpawnRandomItem();
				// 만약 스폰된 액터가 코인 타입이라면 SpawnedCoinCount 증가
				if (SpawnedActor &amp;amp;&amp;amp; SpawnedActor-&amp;gt;IsA(ACoinItem::StaticClass()))
				{
					SpawnedCoinCount++;
				}
			}
		}
	}
	// 30초 후에 OnLevelTimeUp()가 호출되도록 타이머 설정
	GetWorldTimerManager().SetTimer(
		LevelTimerHandle,
		this,
		&amp;amp;AMainGameState::OnLevelTimeUp,
		LevelDuration,
		false
	);
	UE_LOG(LogTemp, Warning, TEXT(&quot;Level %d Start!, Spawned %d coin&quot;),
	       CurrentLevelIndex + 1,
	       SpawnedCoinCount);
}

void AMainGameState::OnLevelTimeUp()
{
	// 시간이 다 되면 레벨을 종료
	EndLevel();
}

void AMainGameState::OnCoinCollected()
{
	CollectedCoinCount++;

	UE_LOG(LogTemp, Warning, TEXT(&quot;Coin Collected: %d / %d&quot;),
	       CollectedCoinCount,
	       SpawnedCoinCount)

	// 현재 레벨에서 스폰된 코인을 전부 주웠다면 즉시 레벨 종료
	if (SpawnedCoinCount &amp;gt; 0 &amp;amp;&amp;amp; CollectedCoinCount &amp;gt;= SpawnedCoinCount)
	{
		EndLevel();
	}
}

void AMainGameState::EndLevel()
{	
	
	// 타이머 해제
	GetWorldTimerManager().ClearTimer(LevelTimerHandle);
	// 다음 레벨 인덱스로
	//CurrentLevelIndex++;
	
	if (UGameInstance* GameInstance = GetGameInstance())
	{
		UMainGameInstance* MainGameInstance = Cast&amp;lt;UMainGameInstance&amp;gt;(GameInstance);
		if (MainGameInstance)
		{
			AddScore(Score);
			CurrentLevelIndex++;
			MainGameInstance-&amp;gt;CurrentLevelIndex = CurrentLevelIndex;
		}
	}

	// 모든 레벨을 다 돌았다면 게임 오버 처리
	if (CurrentLevelIndex &amp;gt;= MaxLevels)
	{
		OnGameOver();
		return;
	}

	// 레벨 맵 이름이 있다면 해당 맵 불러오기
	if (LevelMapNames.IsValidIndex(CurrentLevelIndex))
	{
		UGameplayStatics::OpenLevel(GetWorld(), LevelMapNames[CurrentLevelIndex]);
	}
	else
	{
		// 맵 이름이 없으면 게임오버
		OnGameOver();
	}
}

void AMainGameState::OnGameOver()
{
	UpdateHUD();
	UE_LOG(LogTemp, Warning, TEXT(&quot;Game Over!!&quot;));
	// 여기서 UI를 띄운다거나, 재시작 기능을 넣을 수도 있음
}

void AMainGameState::UpdateHUD()
{
	if (APlayerController* PlayerController = GetWorld()-&amp;gt;GetFirstPlayerController())
	{
		AMainPlayerController* MainPlayerController = Cast&amp;lt;AMainPlayerController&amp;gt;(PlayerController);
		{
			if (UUserWidget* HUDWidget = MainPlayerController-&amp;gt;GetHUDWidget())
			{
				// requires
				// #include &quot;Components/TextBlock.h&quot;
				// #include &quot;Blueprint/UserWidget.h&quot;
				
				//추후 변경 방안 
				// UPROPERTY(meta = (BindWidget))
				// class UButton* MyAwesomeButton;
				if (UTextBlock* TimeText = Cast&amp;lt;UTextBlock&amp;gt;(HUDWidget-&amp;gt;GetWidgetFromName(TEXT(&quot;Time&quot;))))
				{
					float RemainingTime = GetWorldTimerManager().GetTimerRemaining(LevelTimerHandle);
					TimeText-&amp;gt;SetText(FText::FromString(FString::Printf(TEXT(&quot;Time: %.1f&quot;), RemainingTime)));
				}
				
				//
				if (UTextBlock* ScoreText = Cast&amp;lt;UTextBlock&amp;gt;(HUDWidget-&amp;gt;GetWidgetFromName(TEXT(&quot;Score&quot;))))
				{
					if (UGameInstance* GameInstance = GetGameInstance())
					{
						UMainGameInstance* MainGameInstance = Cast&amp;lt;UMainGameInstance&amp;gt;(GameInstance);
						if (MainGameInstance)
						{
							ScoreText-&amp;gt;SetText(FText::FromString(FString::Printf(TEXT(&quot;Score: %i&quot;), MainGameInstance-&amp;gt;TotalScore)));
						}
					}
				}
				
				if (UTextBlock* LevelIndexText = Cast&amp;lt;UTextBlock&amp;gt;(HUDWidget-&amp;gt;GetWidgetFromName(TEXT(&quot;Level&quot;))))
				{
					LevelIndexText-&amp;gt;SetText(FText::FromString(FString::Printf(TEXT(&quot;Level: %d&quot;), CurrentLevelIndex + 1)));
				}
			}
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;직접 SetText 호출&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;방식은 &lt;b&gt;PlayerController&lt;/b&gt;의 Tick 함수(또는 Timer 이벤트)에서 GameState의 Score를 읽어와서, HUD 위젯에 있는 Text Block에 &lt;b&gt;SetText&lt;/b&gt;를 호출하는 방식입니다.&lt;/li&gt;
&lt;li&gt;이 경우에는 Binding을 쓰지 않고, C++ 혹은 블루프린트 스크립트에서 명시적으로 &amp;ldquo;점수가 바뀔 때마다 UI Text를 갱신&amp;rdquo;하도록 로직을 짭니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SetText를 쓰면, 필요할 때만 UI를 업데이트할 수 있어 퍼포먼스에 유리할 수 있습니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1781204870754&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pragma once

#include &quot;CoreMinimal.h&quot;
#include &quot;GameFramework/PlayerController.h&quot;
#include &quot;MainPlayerController.generated.h&quot;

// Declaration
class UInputMappingContext;  // IMC 관련 전방 선언
class UInputAction;// IA 관련 전방 선언


// Enhanced Input에서 액션 값을 받을 때 사용하는 구조체
struct FInputActionValue;

UCLASS()
class BC_CH3_ASSIGNMENT_5_API AMainPlayerController : public APlayerController
{
	GENERATED_BODY()

public:
	AMainPlayerController();
	
	// 에디터에서 세팅할 IMC
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=&quot;Input&quot;)
	UInputMappingContext* InputMappingContext;
	
	// IA
	// IA_Move를 지정할 변수
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=&quot;Input&quot;)
	UInputAction* MoveAction;
	// IA_Jump를 지정할 변수
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=&quot;Input&quot;)
	UInputAction* JumpAction;
	// IA_Look를 지정할 변수
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=&quot;Input&quot;)
	UInputAction* LookAction;
	// IA_Sprint를 지정할 변수
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Input&quot;)
	UInputAction* SprintAction;
	
	// UMG 위젯 클래스를 에디터에서 할당받을 변수
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;HUD&quot;)
	TSubclassOf&amp;lt;UUserWidget&amp;gt; HUDWidgetClass;
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = &quot;HUD&quot;)
	UUserWidget* HUDWidgetInstance;
		
	UFUNCTION(BlueprintPure, Category = &quot;HUD&quot;)
	UUserWidget* GetHUDWidget() const;
	
protected:
	virtual void BeginPlay() override;
	
	/*
	
	//UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=&quot;Input&quot;, meta=(AllowPrivateAccess=&quot;true&quot;))
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Input&quot;)
	UInputAction* ToggleInventoryAction;
	
	bool bIsInventoryOpen;
	
	UFUNCTION(BlueprintCallable)
	void ToggleInventory();
	
	void ActivateCharacterInput();
	void ActivateUIInput();
	*/
	
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1781204881736&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;MainPlayerController.h&quot;
#include &quot;EnhancedInputSubsystems.h&quot;
#include &quot;EnhancedInputSubsystems.h&quot; // Enhanced Input System의 Local Player Subsystem을 사용하기 위해 포함
#include &quot;MainGameState.h&quot;
#include &quot;Blueprint/UserWidget.h&quot;

// 어차피 블루프린트 상에서 전부 다 초기화를 하기 때문에 여기서는 전부 다 nullptr 처리
AMainPlayerController::AMainPlayerController()
	: InputMappingContext(nullptr),
	  MoveAction(nullptr),
	  JumpAction(nullptr),
	  LookAction(nullptr),
	  SprintAction(nullptr),
	  HUDWidgetClass(nullptr),
	  HUDWidgetInstance(nullptr)

{
}

void AMainPlayerController::BeginPlay()
{
	Super::BeginPlay();

	// GetLocalPlayer():현재 PlayerController에 연결된 Local Player 객체를 가져옴     
	// Local Player 는 그 플레이어의 입력이나 화면 뷰 같은 것을 관리하는 어떤 객체
	if (ULocalPlayer* LocalPlayer = GetLocalPlayer())
	{
		// Local Player에서 EnhancedInputLocalPlayerSubsystem을 획득
		// UEnhancedInputLocalPlayerSubsystem: 입력 시스템을 관리 (IMC 추가 혹은 삭제하는 역할)
		if (UEnhancedInputLocalPlayerSubsystem* Subsystem =
			LocalPlayer-&amp;gt;GetSubsystem&amp;lt;UEnhancedInputLocalPlayerSubsystem&amp;gt;())
		{
			if (InputMappingContext)
			{
				// Subsystem을 통해 우리가 할당한 IMC를 활성화
				// 우선순위(Priority)는 0이 가장 높은 우선순위
				Subsystem-&amp;gt;AddMappingContext(InputMappingContext, 0);
			}
		}
	}

	// HUD 위젯 생성 및 표시
	if (HUDWidgetClass)
	{
		HUDWidgetInstance = CreateWidget&amp;lt;UUserWidget&amp;gt;(this, HUDWidgetClass);
		if (HUDWidgetInstance)
		{
			HUDWidgetInstance-&amp;gt;AddToViewport();
		}
	}
	
	AMainGameState* MainGameState = GetWorld() ? GetWorld()-&amp;gt;GetGameState&amp;lt;AMainGameState&amp;gt;() : nullptr;
	if (MainGameState)
	{
		MainGameState-&amp;gt;UpdateHUD();
	}
}

UUserWidget* AMainPlayerController::GetHUDWidget() const
{
	return HUDWidgetInstance;
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style2&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screen Shot 2026-06-12 04 12 18.gif&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;203&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfm5th/dJMcahxZxKv/YmmaFMuXVrPKe3ryAgK1Mk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfm5th/dJMcahxZxKv/YmmaFMuXVrPKe3ryAgK1Mk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfm5th/dJMcahxZxKv/YmmaFMuXVrPKe3ryAgK1Mk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bfm5th/dJMcahxZxKv/YmmaFMuXVrPKe3ryAgK1Mk/img.gif&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;500&quot; height=&quot;254&quot; data-filename=&quot;Screen Shot 2026-06-12 04 12 18.gif&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;203&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #5b63fb; font-weight: bold; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;추천&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유저 인터페이스 및 HUD 관련 UE 공식 문서: &lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/user-interfaces-and-huds-in-unreal-engine?lang=ko&quot;&gt;https://dev.epicgames.com/documentation/unreal-engine/user-interfaces-and-huds-in-unreal-engine?lang=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781175871865&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;User Interfaces and HUDs in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&quot; data-og-description=&quot;Guides and information for artists and programmers creating user interfaces such as menus and HUDs in Unreal Engine&quot; data-og-host=&quot;dev.epicgames.com&quot; data-og-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/user-interfaces-and-huds-in-unreal-engine?lang=ko&quot; data-og-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/user-interfaces-and-huds-in-unreal-engine&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/WAnxR/dJMb9lMjJQ5/bmDYHdb5PASRPeKkAvEgqK/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/ggGPR/dJMb9iIPbAY/kluDdrqr2DnXdiz4DkYA4k/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/DRnjx/dJMb9eTXO8J/Zmna3GIoKvnmRyPyKws8R1/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/user-interfaces-and-huds-in-unreal-engine?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/user-interfaces-and-huds-in-unreal-engine?lang=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/WAnxR/dJMb9lMjJQ5/bmDYHdb5PASRPeKkAvEgqK/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/ggGPR/dJMb9iIPbAY/kluDdrqr2DnXdiz4DkYA4k/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/DRnjx/dJMb9eTXO8J/Zmna3GIoKvnmRyPyKws8R1/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;User Interfaces and HUDs in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Guides and information for artists and programmers creating user interfaces such as menus and HUDs in Unreal Engine&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.epicgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UMG UI 디자이너 퀵스타트 가이드 UE 공식 문서: &lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/umg-ui-designer-quick-start-guide-in-unreal-engine?lang=ko&quot;&gt;https://dev.epicgames.com/documentation/unreal-engine/umg-ui-designer-quick-start-guide-in-unreal-engine?lang=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781175874144&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;UMG UI Designer Quick Start Guide in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&quot; data-og-description=&quot;Getting started with using Unreal Motion Graphics in Unreal Engine.&quot; data-og-host=&quot;dev.epicgames.com&quot; data-og-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/umg-ui-designer-quick-start-guide-in-unreal-engine?lang=ko&quot; data-og-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/umg-ui-designer-quick-start-guide-in-unreal-engine&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/f3aeP/dJMb9iIPbBk/htQCf7dIXPXAWYbxhexffk/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/brx2Tn/dJMb9hC9sEi/dCpqVgfsb1itCDRBhRmmD1/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/5eWSw/dJMb9bwaw8o/kcC0NYspFnUAZGxhjQn9p0/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/umg-ui-designer-quick-start-guide-in-unreal-engine?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/umg-ui-designer-quick-start-guide-in-unreal-engine?lang=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/f3aeP/dJMb9iIPbBk/htQCf7dIXPXAWYbxhexffk/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/brx2Tn/dJMb9hC9sEi/dCpqVgfsb1itCDRBhRmmD1/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/5eWSw/dJMb9bwaw8o/kcC0NYspFnUAZGxhjQn9p0/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;UMG UI Designer Quick Start Guide in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Getting started with using Unreal Motion Graphics in Unreal Engine.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.epicgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&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;a href=&quot;https://github.com/hyper-type/hahmlet&quot;&gt;https://github.com/hyper-type/hahmlet&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781193104245&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - hyper-type/hahmlet: Hahmlet font by Minjoo Ham and Mark Fr&amp;ouml;mberg aka Hypertype&quot; data-og-description=&quot;Hahmlet font by Minjoo Ham and Mark Fr&amp;ouml;mberg aka Hypertype - hyper-type/hahmlet&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/hyper-type/hahmlet&quot; data-og-url=&quot;https://github.com/hyper-type/hahmlet&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/4UGQm/dJMb8WeH9ed/aBHWuCRYcIWkR0pQDIWRDk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bsIaYn/dJMb8U811em/EVVQWQEp60nJzSKBDEpiP1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/0FATz/dJMb8RkaqsL/EJlDtFp4SNx4mXvWLkpenK/img.png?width=4096&amp;amp;height=3101&amp;amp;face=0_0_4096_3101&quot;&gt;&lt;a href=&quot;https://github.com/hyper-type/hahmlet&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/hyper-type/hahmlet&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/4UGQm/dJMb8WeH9ed/aBHWuCRYcIWkR0pQDIWRDk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bsIaYn/dJMb8U811em/EVVQWQEp60nJzSKBDEpiP1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/0FATz/dJMb8RkaqsL/EJlDtFp4SNx4mXvWLkpenK/img.png?width=4096&amp;amp;height=3101&amp;amp;face=0_0_4096_3101');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - hyper-type/hahmlet: Hahmlet font by Minjoo Ham and Mark Fr&amp;ouml;mberg aka Hypertype&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Hahmlet font by Minjoo Ham and Mark Fr&amp;ouml;mberg aka Hypertype - hyper-type/hahmlet&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://noonnu.cc/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://noonnu.cc/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781193120035&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;눈누&quot; data-og-description=&quot;상업적 이용 가능한 한글 폰트를 쉽게 찾아보세요.&quot; data-og-host=&quot;noonnu.cc&quot; data-og-source-url=&quot;https://noonnu.cc/&quot; data-og-url=&quot;https://noonnu.cc/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/3oqPi/dJMb8YXTZoO/KaYFEiSKvzT864pQrGTZC1/img.png?width=1200&amp;amp;height=628&amp;amp;face=0_0_1200_628,https://scrap.kakaocdn.net/dn/bd9ptT/dJMb8WMxXKu/fD6Ur5IRfQhpzaP3lH8kiK/img.png?width=1200&amp;amp;height=628&amp;amp;face=0_0_1200_628,https://scrap.kakaocdn.net/dn/cIL96h/dJMb8XSd8p5/rvEkHqoieRW0lqeuiAmyCk/img.jpg?width=3230&amp;amp;height=328&amp;amp;face=0_0_3230_328&quot;&gt;&lt;a href=&quot;https://noonnu.cc/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://noonnu.cc/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/3oqPi/dJMb8YXTZoO/KaYFEiSKvzT864pQrGTZC1/img.png?width=1200&amp;amp;height=628&amp;amp;face=0_0_1200_628,https://scrap.kakaocdn.net/dn/bd9ptT/dJMb8WMxXKu/fD6Ur5IRfQhpzaP3lH8kiK/img.png?width=1200&amp;amp;height=628&amp;amp;face=0_0_1200_628,https://scrap.kakaocdn.net/dn/cIL96h/dJMb8XSd8p5/rvEkHqoieRW0lqeuiAmyCk/img.jpg?width=3230&amp;amp;height=328&amp;amp;face=0_0_3230_328');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;눈누&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;상업적 이용 가능한 한글 폰트를 쉽게 찾아보세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;noonnu.cc&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/107&quot;&gt;[Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781205453915&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;인터페이스 기반 아이템 클래스 설계하기 인터페이스 이해하기1️⃣ 인터페이스란?인터페이스 (Interface)란 클래스 (또는 오브젝트)가 반드시 구현해야 할 함수 목록만을 미리 정의해 두고, 실제 &quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/107&quot; data-og-url=&quot;https://devcol.tistory.com/107&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/sA9RM/dJMb9frNEV7/mqumL986okRdsyJE9ASHo1/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/biAScA/dJMb9gxtHkU/Yh7zNXgwmwbeJInju0dqf1/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/ApySg/dJMb87geO5s/dnf4JtgjnftSvuuZiKWhhK/img.png?width=997&amp;amp;height=544&amp;amp;face=0_0_997_544&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/107&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/107&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/sA9RM/dJMb9frNEV7/mqumL986okRdsyJE9ASHo1/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/biAScA/dJMb9gxtHkU/Yh7zNXgwmwbeJInju0dqf1/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/ApySg/dJMb87geO5s/dnf4JtgjnftSvuuZiKWhhK/img.png?width=997&amp;amp;height=544&amp;amp;face=0_0_997_544');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스 기반 아이템 클래스 설계하기 인터페이스 이해하기1️⃣ 인터페이스란?인터페이스 (Interface)란 클래스 (또는 오브젝트)가 반드시 구현해야 할 함수 목록만을 미리 정의해 두고, 실제&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://devcol.tistory.com/108&quot;&gt;[Unreal Engine/UE 기초] - 충돌 이벤트로 획득되는 아이템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781205454858&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;충돌 이벤트로 획득되는 아이템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;충돌 이벤트로 획득되는 아이템 구현하기 이전 포스팅에서는 클래스 구조만 짜고 로직은 비여있던 상태.이전 포스팅: [Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼 &quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/108&quot; data-og-url=&quot;https://devcol.tistory.com/108&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/jmWjD/dJMb82MLsPp/7QMxGqRnfqAFCn6p5k8tkk/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/JFK5Z/dJMb81G5Lvh/TXhxaBoI1kuEALcXwK5ByK/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/bHB478/dJMb9g5jhTi/zCDS1GY8Z9i42g4dal6kB0/img.png?width=1596&amp;amp;height=489&amp;amp;face=0_0_1596_489&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/108&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/108&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/jmWjD/dJMb82MLsPp/7QMxGqRnfqAFCn6p5k8tkk/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/JFK5Z/dJMb81G5Lvh/TXhxaBoI1kuEALcXwK5ByK/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/bHB478/dJMb9g5jhTi/zCDS1GY8Z9i42g4dal6kB0/img.png?width=1596&amp;amp;height=489&amp;amp;face=0_0_1596_489');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;충돌 이벤트로 획득되는 아이템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;충돌 이벤트로 획득되는 아이템 구현하기 이전 포스팅에서는 클래스 구조만 짜고 로직은 비여있던 상태.이전 포스팅: [Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://devcol.tistory.com/109&quot;&gt;[Unreal Engine/UE 기초] - 아이템 스폰 및 레벨 데이터 관리하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781205456107&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;아이템 스폰 및 레벨 데이터 관리하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;아이템 스폰 및 레벨 데이터 관리하기 랜덤 위치에 아이템 스폰하기 1️⃣ 레벨 셋팅하기Resources 폴더에 Maps 폴더에는 3개의 레벨이 이미 존재합니다. 각각 난이도에 따라서 크기가 다른 맵이고, &quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/109&quot; data-og-url=&quot;https://devcol.tistory.com/109&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cLGxfm/dJMb8Yp3Jgs/XodaPA7Bq8Q2bwJcaYrOk1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/b3TL4M/dJMb81f0W7R/XxH3bkz7XP3Dxcl22AJkU1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/c4oxJD/dJMb89ylWzD/GSEuPUkAww5SFszPpPhOs1/img.png?width=940&amp;amp;height=571&amp;amp;face=0_0_940_571&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/109&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/109&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cLGxfm/dJMb8Yp3Jgs/XodaPA7Bq8Q2bwJcaYrOk1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/b3TL4M/dJMb81f0W7R/XxH3bkz7XP3Dxcl22AJkU1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/c4oxJD/dJMb89ylWzD/GSEuPUkAww5SFszPpPhOs1/img.png?width=940&amp;amp;height=571&amp;amp;face=0_0_940_571');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;아이템 스폰 및 레벨 데이터 관리하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;아이템 스폰 및 레벨 데이터 관리하기 랜덤 위치에 아이템 스폰하기 1️⃣ 레벨 셋팅하기Resources 폴더에 Maps 폴더에는 3개의 레벨이 이미 존재합니다. 각각 난이도에 따라서 크기가 다른 맵이고,&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://devcol.tistory.com/110&quot;&gt;[Unreal Engine/UE 기초] - 캐릭터 체력 및 점수 관리 시스템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781205457547&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;캐릭터 체력 및 점수 관리 시스템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;캐릭터 체력 및 점수 관리 시스템 구현하기 캐릭터 체력 시스템 구현하기 1️⃣ 캐릭터 클래스에 체력 변수 및 함수 선언PlayerState를 쓰지 않는 이유PlayerState: 각 플레이어마다의 어떤 정보를 관&quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/110&quot; data-og-url=&quot;https://devcol.tistory.com/110&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bYqXoH/dJMb8WMxYMp/5mzpC6c0dk8y31rndJrJuK/img.png?width=773&amp;amp;height=359&amp;amp;face=0_0_773_359,https://scrap.kakaocdn.net/dn/ectDw4/dJMb9gxtHk0/ZVLADkGrrgLpKlXy7MKsi0/img.png?width=773&amp;amp;height=359&amp;amp;face=0_0_773_359,https://scrap.kakaocdn.net/dn/bEAEtk/dJMb8SpQkZA/PbM36SDF25VGpi0p9ZsKz1/img.png?width=915&amp;amp;height=558&amp;amp;face=0_0_915_558&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/110&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/110&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bYqXoH/dJMb8WMxYMp/5mzpC6c0dk8y31rndJrJuK/img.png?width=773&amp;amp;height=359&amp;amp;face=0_0_773_359,https://scrap.kakaocdn.net/dn/ectDw4/dJMb9gxtHk0/ZVLADkGrrgLpKlXy7MKsi0/img.png?width=773&amp;amp;height=359&amp;amp;face=0_0_773_359,https://scrap.kakaocdn.net/dn/bEAEtk/dJMb8SpQkZA/PbM36SDF25VGpi0p9ZsKz1/img.png?width=915&amp;amp;height=558&amp;amp;face=0_0_915_558');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;캐릭터 체력 및 점수 관리 시스템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;캐릭터 체력 및 점수 관리 시스템 구현하기 캐릭터 체력 시스템 구현하기 1️⃣ 캐릭터 클래스에 체력 변수 및 함수 선언PlayerState를 쓰지 않는 이유PlayerState: 각 플레이어마다의 어떤 정보를 관&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://devcol.tistory.com/111&quot;&gt;[Unreal Engine/UE 기초] - 게임 루프 설계를 통한 게임 흐름 제어하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781205458930&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;게임 루프 설계를 통한 게임 흐름 제어하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;게임 루프 설계를 통한 게임 흐름 제어하기 GameState를 이용한 게임 루프 구현하기 게임루프: 보통 게임의 핵심적인 흐름을 얘기합니다. 즉 게임이 시작할 때부터 종료까지 수행하는 단계들게임&quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/111&quot; data-og-url=&quot;https://devcol.tistory.com/111&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/m3HSO/dJMb8Yp3LZc/oDKcOSmHa6KQokX0K8otyK/img.png?width=800&amp;amp;height=566&amp;amp;face=0_0_800_566,https://scrap.kakaocdn.net/dn/bezEhJ/dJMb8TCh97F/a38cyWkwwklT9XZIOkmAI0/img.png?width=800&amp;amp;height=566&amp;amp;face=0_0_800_566,https://scrap.kakaocdn.net/dn/dBmfWn/dJMb8Yp3LZb/ZKEpbaswdrCszr1LfiKXDk/img.png?width=1167&amp;amp;height=827&amp;amp;face=0_0_1167_827&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/111&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/111&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/m3HSO/dJMb8Yp3LZc/oDKcOSmHa6KQokX0K8otyK/img.png?width=800&amp;amp;height=566&amp;amp;face=0_0_800_566,https://scrap.kakaocdn.net/dn/bezEhJ/dJMb8TCh97F/a38cyWkwwklT9XZIOkmAI0/img.png?width=800&amp;amp;height=566&amp;amp;face=0_0_800_566,https://scrap.kakaocdn.net/dn/dBmfWn/dJMb8Yp3LZb/ZKEpbaswdrCszr1LfiKXDk/img.png?width=1167&amp;amp;height=827&amp;amp;face=0_0_1167_827');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;게임 루프 설계를 통한 게임 흐름 제어하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;게임 루프 설계를 통한 게임 흐름 제어하기 GameState를 이용한 게임 루프 구현하기 게임루프: 보통 게임의 핵심적인 흐름을 얘기합니다. 즉 게임이 시작할 때부터 종료까지 수행하는 단계들게임&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/pages/Unreal-Engine-%EC%96%B8%EB%A6%AC%EC%96%BC-%EC%97%94%EC%A7%84&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;[페이지] Unreal Engine | 언리얼 엔진&lt;/b&gt;&lt;/a&gt;&lt;/h4&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;</description>
      <category>Unreal Engine/UE 기초</category>
      <category>C++</category>
      <category>Devlog</category>
      <category>Programming</category>
      <category>UE</category>
      <category>UE5</category>
      <category>Unreal engine</category>
      <category>게임 개발</category>
      <category>기초</category>
      <category>언리얼 엔진</category>
      <category>프로그래밍</category>
      <author>DevCol</author>
      <guid isPermaLink="true">https://devcol.tistory.com/114</guid>
      <comments>https://devcol.tistory.com/114#entry114comment</comments>
      <pubDate>Fri, 12 Jun 2026 04:17:42 +0900</pubDate>
    </item>
    <item>
      <title>[TA] TA - Technical Artist (테크니컬 아티스트)란? | [언리얼 엔진 C++ (Unreal Engine C++)]</title>
      <link>https://devcol.tistory.com/113</link>
      <description>&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;언리얼엔진&amp;nbsp;공식문서&amp;nbsp;-&amp;nbsp;직무&amp;nbsp;가이드&amp;nbsp;살펴보기:&amp;nbsp;&lt;a href=&quot;https://www.unrealengine.com/tech-blog/jobs-in-unreal-engine---technical-artist?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.unrealengine.com/tech-blog/jobs-in-unreal-engine---technical-artist?lang=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781191525995&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;언리얼 엔진 직무 살펴보기 - 테크니컬 아티스트&quot; data-og-description=&quot;실시간 기술 관련 커리어를 찾고 계신다면, 급성장 중인 테크니컬 아티스트를 고려해보시는 것은 어떨까요? 지난 12개월 사이에 수요가 48%나 증가한 이 직무는 아트와 코드를 잇는 중요한 역할&quot; data-og-host=&quot;www.unrealengine.com&quot; data-og-source-url=&quot;https://www.unrealengine.com/tech-blog/jobs-in-unreal-engine---technical-artist?lang=ko&quot; data-og-url=&quot;https://www.unrealengine.com/tech-blog/jobs-in-unreal-engine---technical-artist&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b5DQzD/dJMb83SrlTt/ZCGURKDbIi5yxB1vQcFFOk/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bN2XUa/dJMb82MLvtE/gQLUxDxiIWDVkIbC27kiBK/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/cklPJ6/dJMb81G5Ojt/OchbD5ohxwFcdvSzDykJuK/img.jpg?width=1640&amp;amp;height=1000&amp;amp;face=0_0_1640_1000&quot;&gt;&lt;a href=&quot;https://www.unrealengine.com/tech-blog/jobs-in-unreal-engine---technical-artist?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.unrealengine.com/tech-blog/jobs-in-unreal-engine---technical-artist?lang=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b5DQzD/dJMb83SrlTt/ZCGURKDbIi5yxB1vQcFFOk/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bN2XUa/dJMb82MLvtE/gQLUxDxiIWDVkIbC27kiBK/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/cklPJ6/dJMb81G5Ojt/OchbD5ohxwFcdvSzDykJuK/img.jpg?width=1640&amp;amp;height=1000&amp;amp;face=0_0_1640_1000');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;언리얼 엔진 직무 살펴보기 - 테크니컬 아티스트&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;실시간 기술 관련 커리어를 찾고 계신다면, 급성장 중인 테크니컬 아티스트를 고려해보시는 것은 어떨까요? 지난 12개월 사이에 수요가 48%나 증가한 이 직무는 아트와 코드를 잇는 중요한 역할&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.unrealengine.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;TA - &lt;span data-token-index=&quot;0&quot;&gt;Technical Artist&lt;/span&gt; 란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Unreal+Engine_blog_jobs-in-unreal-engine---technical-artist_huskdeath-spike2FX-617155a56aceee89897b17f6b6430fbd92a4dc29.gif&quot; data-origin-width=&quot;610&quot; data-origin-height=&quot;508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwDaSL/dJMcaaMmCwu/Bmk0DBn4HaJ3oZdEkOzWg1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwDaSL/dJMcaaMmCwu/Bmk0DBn4HaJ3oZdEkOzWg1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwDaSL/dJMcaaMmCwu/Bmk0DBn4HaJ3oZdEkOzWg1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bwDaSL/dJMcaaMmCwu/Bmk0DBn4HaJ3oZdEkOzWg1/img.gif&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;610&quot; height=&quot;508&quot; data-filename=&quot;Unreal+Engine_blog_jobs-in-unreal-engine---technical-artist_huskdeath-spike2FX-617155a56aceee89897b17f6b6430fbd92a4dc29.gif&quot; data-origin-width=&quot;610&quot; data-origin-height=&quot;508&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size14&quot;&gt;출처: &lt;a href=&quot;https://www.unrealengine.com/tech-blog/jobs-in-unreal-engine---technical-artist?lang=ko&quot;&gt;https://www.unrealengine.com/tech-blog/jobs-in-unreal-engine---technical-artist?lang=ko&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a1&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot; data-token-index=&quot;0&quot;&gt;&lt;b&gt;TA-&lt;span data-token-index=&quot;0&quot;&gt;Technical Artist | 테크니컬 아티스트&lt;/span&gt;&lt;/b&gt; &lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACAQQAA&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-subtree=&quot;aimfl,mfl&quot;&gt;'Technical Artist'는 한국 게임 및 IT 업계에서 줄여서 &lt;/span&gt;&lt;b&gt;'TA(티에이)'&lt;/b&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt; 또는 &lt;/span&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 500; margin: 0px; text-decoration: none; border-bottom: 0px rgb(238, 240, 255);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;'테크니컬 아티스트'&lt;/b&gt;&lt;/span&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;라고 부릅니다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACAYQAA&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;아트(디자인)와 프로그래밍(기술)의 교집합에 있는 직무로, 미술적 감각과 기술적 이해도를 모두 갖추고 작업 환경을 개선하는 역할을 합니다.&lt;span&gt; &lt;/span&gt;즉 아티스트가 만든 리소스가 엔진 안에서 제대로 사용되도록 돕고, 개발자가 만든 기능이 시각적으로 잘 표현되도록 연결합니다.&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwj05e-K9v2UAxX1iq8BHSuUBc8Qi4wTegoIAggACAAICxAA&quot; data-bfc=&quot;&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACAsQAQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;주요 업무 내용은 다음과 같습니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwj05e-K9v2UAxX1iq8BHSuUBc8Qi4wTegoIAggACAAIDRAA&quot; data-bfc=&quot;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACA0QAQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;최적화 및 엔진 구현:&lt;/b&gt; 아티스트가 만든 3D 모델이나 배경이 게임 엔진에서 원활하게 돌아가도록 리소스를 가다듬고 프레임 저하를 방지합니다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACA0QBw&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;툴(Tool) 개발 및 자동화:&lt;/b&gt; 아트 팀이 더 빠르고 편하게 작업할 수 있도록 돕는 전용 스크립트나 플러그인을 만듭니다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACA0QDQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;리깅(Rigging) 및 애니메이션:&lt;/b&gt; 캐릭터가 자연스럽게 움직일 수 있도록 뼈(Bone)를 심고 관절의 무게값을 설정합니다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACA0QEw&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;이펙트 및 셰이더 제작:&lt;/b&gt; 불, 물, 폭발 등 시각적 효과를 담당하거나, 독특한 질감과 빛의 반사를 표현하는 셰이더를 프로그래밍합니다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACA0QEw&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span&gt;&lt;b&gt; 리소스 파이프라인 정리&lt;/b&gt;: 파일 이름 규칙, 폴더 구조, Import 설정 관리 &lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACA0QEw&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span&gt;&lt;b&gt; 머티리얼 구조 설계: &lt;/b&gt;Parent Material, Material Instance 구조 정리 &lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACA0QEw&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span&gt;&lt;b&gt; 반복 작업 자동화&lt;/b&gt;: 에셋 이름 정리, 폴더 자동 분류, 검사 도구 제작 &lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACA0QEw&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span&gt;&lt;b&gt; VFX 연결&lt;/b&gt;: Niagara 이펙트 호출 위치와 타이밍 관리 &lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACA0QEw&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span&gt;&lt;b&gt; 최적화 기준 수립&lt;/b&gt;: Texture 크기, Material 복잡도, 파티클 수, Draw Call 관리 &lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACA0QGQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;부서 간 소통:&lt;/b&gt; 아트 팀과 프로그래밍 팀 사이의 의견을 조율하고 기술적인 해결책을 제시하는 다리 역할을 합니다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언리얼엔진&amp;nbsp;공식문서&amp;nbsp;-&amp;nbsp;직무&amp;nbsp;가이드&amp;nbsp;살펴보기:&amp;nbsp;&lt;a href=&quot;https://www.unrealengine.com/tech-blog/jobs-in-unreal-engine---technical-artist?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.unrealengine.com/tech-blog/jobs-in-unreal-engine---technical-artist?lang=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781137692191&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;언리얼 엔진 직무 살펴보기 - 테크니컬 아티스트&quot; data-og-description=&quot;실시간 기술 관련 커리어를 찾고 계신다면, 급성장 중인 테크니컬 아티스트를 고려해보시는 것은 어떨까요? 지난 12개월 사이에 수요가 48%나 증가한 이 직무는 아트와 코드를 잇는 중요한 역할&quot; data-og-host=&quot;www.unrealengine.com&quot; data-og-source-url=&quot;https://www.unrealengine.com/tech-blog/jobs-in-unreal-engine---technical-artist?lang=ko&quot; data-og-url=&quot;https://www.unrealengine.com/tech-blog/jobs-in-unreal-engine---technical-artist&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ef3wfH/dJMb88e8XPH/lyKAH9Q7QTjAAMqlLjnrOK/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/f76Mh/dJMb86O90Dt/IprUl6dOvG0hK1qVHJFlm1/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/720Ke/dJMb8Z3zHfC/WdBGBmqz46k4RtQ80vtOiK/img.jpg?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080&quot;&gt;&lt;a href=&quot;https://www.unrealengine.com/tech-blog/jobs-in-unreal-engine---technical-artist?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.unrealengine.com/tech-blog/jobs-in-unreal-engine---technical-artist?lang=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ef3wfH/dJMb88e8XPH/lyKAH9Q7QTjAAMqlLjnrOK/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/f76Mh/dJMb86O90Dt/IprUl6dOvG0hK1qVHJFlm1/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/720Ke/dJMb8Z3zHfC/WdBGBmqz46k4RtQ80vtOiK/img.jpg?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;언리얼 엔진 직무 살펴보기 - 테크니컬 아티스트&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;실시간 기술 관련 커리어를 찾고 계신다면, 급성장 중인 테크니컬 아티스트를 고려해보시는 것은 어떨까요? 지난 12개월 사이에 수요가 48%나 증가한 이 직무는 아트와 코드를 잇는 중요한 역할&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.unrealengine.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a2&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;&lt;/span&gt;클라이언트 개발자에게 TA 기초가 필요한 이유&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;클라이언트 개발자는 보통 기능을 구현한다. 하지만 화면에 그것이 출력되어야 하고 어떻게 보여줄지에 대해서 잘 알아야 합니다. 공격 모션, 무기 궤적 이펙트, 피격 이펙트, 사운드, 카메라 흔들림, 머티리얼 변화가 함께 연결되어야 플레이어가 &amp;ldquo;공격이 제대로 들어갔다&amp;rdquo;라고 느낍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; color #000000; border-left: 10px solid #5b63fb; font-weight: bold;&quot; data-ke-size=&quot;size20&quot;&gt;소통에 원활한 도움을 줍니다&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이펙트가 구려요 -&amp;gt; 공격 Notify 타이밍은 맞는데 Niagara System이 무기 Socket 위치와 어긋난 것 같습니다&lt;/li&gt;
&lt;li&gt;머티리얼 색이 이상하고&amp;nbsp; 잘 안보여요 -&amp;gt; 색상 문제라기보다 Lighting 환경과 Roughness 값 때문에 반사가 강하게 보이는 것 같습니다&lt;/li&gt;
&lt;li&gt;애니메이션 동작이 이상해요 -&amp;gt; Animation 자체 문제라기보다 Root Motion과 캐릭터 이동 로직이 충돌하는 것 같습니다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정확하고 구체적인 표현으로 소통할수있게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a4&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;게임 화면을 구성하는 기본 요소들&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; color #000000; border-left: 10px solid #5b63fb; font-weight: bold;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;Mesh&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;Mesh: 게임 오브젝트의 형태를 만드는 3D구조.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;그 중 크게 두개로 나눌 수 있는데 Static Mesh 와 Skeletal Mesh 가 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Static Mesh: 뼈대 구조가 없는 정적인 오브젝트들 (바위, 벽, 건물, 무기, 물건들)&lt;/li&gt;
&lt;li&gt;Skeletal Mesh: Bone과 Skeleton 구조를 가진 오브젝트( 캐릭터, 몬스터 등등 애니메이션이 필요한 오브젝트)&lt;/li&gt;
&lt;/ul&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;Skeletal Mesh to Static Mesh Conversion: &lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/skeletal-mesh-to-static-mesh-conversion-in-unreal-engine&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dev.epicgames.com/documentation/unreal-engine/skeletal-mesh-to-static-mesh-conversion-in-unreal-engine&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781139447173&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Skeletal Mesh to Static Mesh Conversion in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&quot; data-og-description=&quot;Learn how to convert posed Skeletal Mesh assets to Static Mesh assets in Unreal Engine.&quot; data-og-host=&quot;dev.epicgames.com&quot; data-og-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/skeletal-mesh-to-static-mesh-conversion-in-unreal-engine&quot; data-og-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/skeletal-mesh-to-static-mesh-conversion-in-unreal-engine&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/UWKYH/dJMb9jOu6XX/uNqstTPkwRWKSRRAiDiAak/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/bgvCJ2/dJMb9g5jeBG/e5h1bPs1cHsdptrG7Xtgi1/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/IdJil/dJMb9eTXKqW/lAeSTLZojkZa1zVsXkwvwk/img.png?width=1286&amp;amp;height=726&amp;amp;face=0_0_1286_726&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/skeletal-mesh-to-static-mesh-conversion-in-unreal-engine&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/skeletal-mesh-to-static-mesh-conversion-in-unreal-engine&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/UWKYH/dJMb9jOu6XX/uNqstTPkwRWKSRRAiDiAak/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/bgvCJ2/dJMb9g5jeBG/e5h1bPs1cHsdptrG7Xtgi1/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/IdJil/dJMb9eTXKqW/lAeSTLZojkZa1zVsXkwvwk/img.png?width=1286&amp;amp;height=726&amp;amp;face=0_0_1286_726');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Skeletal Mesh to Static Mesh Conversion in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Learn how to convert posed Skeletal Mesh assets to Static Mesh assets in Unreal Engine.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.epicgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;메시를&amp;nbsp;스켈레탈&amp;nbsp;메시로&amp;nbsp;변환하기: &lt;a href=&quot;https://dev.epicgames.com/documentation/fortnite/convert-a-static-mesh-into-a-skeletal-mesh-in-unreal-editor-for-fortnite?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dev.epicgames.com/documentation/fortnite/convert-a-static-mesh-into-a-skeletal-mesh-in-unreal-editor-for-fortnite?lang=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781139450056&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Convert a Static Mesh into a Skeletal Mesh in Unreal Editor for Fortnite | Fortnite Documentation | Epic Developer Community&quot; data-og-description=&quot;Create a fully working Skeletal Mesh from a Static Mesh using the suite of Mesh editors in Unreal Editor for Fortnite.&quot; data-og-host=&quot;dev.epicgames.com&quot; data-og-source-url=&quot;https://dev.epicgames.com/documentation/fortnite/convert-a-static-mesh-into-a-skeletal-mesh-in-unreal-editor-for-fortnite?lang=ko&quot; data-og-url=&quot;https://dev.epicgames.com/documentation/fortnite/convert-a-static-mesh-into-a-skeletal-mesh-in-unreal-editor-for-fortnite&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/o4Qut/dJMb9dHwoPd/kRiZnGLPLEqZvKJrMatkN1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bg3oP3/dJMb84X6ZER/6qdDLylZxvrRUrJ0Im8ZE1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/jRiZ4/dJMb9gxtD17/WLQtDLQTAiKHm8MZ5qY5S1/img.png?width=1900&amp;amp;height=335&amp;amp;face=0_0_1900_335&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/fortnite/convert-a-static-mesh-into-a-skeletal-mesh-in-unreal-editor-for-fortnite?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.epicgames.com/documentation/fortnite/convert-a-static-mesh-into-a-skeletal-mesh-in-unreal-editor-for-fortnite?lang=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/o4Qut/dJMb9dHwoPd/kRiZnGLPLEqZvKJrMatkN1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bg3oP3/dJMb84X6ZER/6qdDLylZxvrRUrJ0Im8ZE1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/jRiZ4/dJMb9gxtD17/WLQtDLQTAiKHm8MZ5qY5S1/img.png?width=1900&amp;amp;height=335&amp;amp;face=0_0_1900_335');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Convert a Static Mesh into a Skeletal Mesh in Unreal Editor for Fortnite | Fortnite Documentation | Epic Developer Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Create a fully working Skeletal Mesh from a Static Mesh using the suite of Mesh editors in Unreal Editor for Fortnite.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.epicgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h4 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; color #000000; border-left: 10px solid #5b63fb; font-weight: bold;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;Texture &lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3차원 물체(모델링)의 표면에 입혀지는 '무늬'나 '재질 이미지'를 뜻합니다. (예: 나무 상자 3D 도형 위에 실제 나무껍질 이미지를 입히는 것)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Texture는 Mesh 표면에 적용되는 이미지 데이터이고, 단순히 색을 입히는 이미지가 아니라, 표면의 여러 정보를 담습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;베이스 컬러 (Base Color):&amp;nbsp;&lt;/b&gt;기본 색상&lt;/li&gt;
&lt;li&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;노멀 맵 (Normal Map)&lt;/b&gt;: RGB 채널을 통해 표면의 &lt;b&gt;굴곡과 방향성&lt;/b&gt;을 기록하여, 폴리곤이 많지 않아도 빛을 받았을 때 마치 입체적인 요철이 있는 것처럼 착시를 일으키는 텍스처입니다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACAsQCw&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;메탈릭 맵 (Metallic Map)&lt;/b&gt;: 표면이 &lt;b&gt;금속인지 비금속인지&lt;/b&gt;를 구분하는 텍스처입니다. 보통 흰색(1.0)에 가까울수록 금속 특유의 반사를 띄고, 검은색(0.0)은 비금속을 의미합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACAsQDg&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;러프니스 맵 (Roughness Map)&lt;/b&gt;: 표면의 &lt;b&gt;거칠기&lt;/b&gt;를 표현합니다. 매끄러울수록 빛을 선명하게 반사하고, 거칠수록 빛이 여러 방향으로 퍼져 뿌옇게 반사되도록 합니다. (프로그램에 따라 반짝임을 뜻하는 '스무스니스(Smoothness) 맵'을 사용하기도 합니다.)&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACAsQEQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;앰비언트 오클루전 맵 (Ambient Occlusion Map)&lt;/b&gt;: 틈새나 주름 등 &lt;b&gt;빛이 닿기 힘든 구석진 곳에 생기는 미세한 그림자&lt;/b&gt;를 미리 구워낸 텍스처로, 사물 간의 입체감과 깊이를 더해줍니다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;h4 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; color #000000; border-left: 10px solid #5b63fb; font-weight: bold;&quot; data-ke-size=&quot;size20&quot;&gt;Material&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-subtree=&quot;aimfl,mfl&quot;&gt;3D 게임에서 &lt;/span&gt;&lt;b&gt;머티리얼(Material)&lt;/b&gt;은 3D 오브젝트 표면의 질감, 색상, 빛 반사 방식 등을 결정하는 렌더링 속성의 조합입니다&lt;/span&gt;. 현대 게임 엔진(유니티, 언리얼 등)에서는 주로 사실적인 물리 기반 렌더링(PBR) 방식을 사용하며, 머티리얼을 구성하는 주요 텍스처(맵) 종류는 다음과 같습니다&lt;/p&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 20px; font-weight: 600; margin: 24px 0px 12px; text-decoration: none; border-bottom: 0px rgb(238, 240, 255);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot; data-animation-nesting=&quot;&quot;&gt;&lt;b&gt;1. PBR 머티리얼을 구성하는 핵심 텍스처&lt;/b&gt;&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwjO1evW_v2UAxVwoK8BHVCDFcwQi4wTegoIAggACAEIChAA&quot; data-bfc=&quot;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCAoQAQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;베이스 컬러 / 알베도 (Base Color / Albedo):&lt;/b&gt; 물체 본연의 기본 색상과 패턴을 나타냅니다. (빛 정보는 포함하지 않음)&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCAoQBg&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;노멀 맵 (Normal Map):&lt;/b&gt; 텍스처의 밝고 어두운 명암을 이용해, 평평한 폴리곤 표면을 울퉁불퉁하거나 입체적인 질감으로 보이게 하는 속성입니다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCAoQCw&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;러프니스 / 스무스니스 (Roughness / Glossiness):&lt;/b&gt; 표면의 거친 정도를 나타내며, 빛이 표면에 닿았을 때 반사광이 얼마나 퍼지거나 선명하게 맺힐지 결정합니다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCAoQEA&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;메탈릭 (Metallic):&lt;/b&gt; 해당 표면이 금속(1.0)인지 비금속(0.0)인지 정의하며, 금속 특유의 반사율과 색상을 제어합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCAoQEw&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;앰비언트 오클루전 (Ambient Occlusion):&lt;/b&gt; 그림자가 생기는 구석이나 틈새 부분에 가짜 그림자를 드리워 입체감과 깊이를 더해줍니다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwjO1evW_v2UAxVwoK8BHVCDFcwQi4wTegoIAggACAEIDhAA&quot; data-bfc=&quot;&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 20px; font-weight: 600; margin: 24px 0px 12px; text-decoration: none; border-bottom: 0px rgb(238, 240, 255);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot; data-animation-nesting=&quot;&quot;&gt;&lt;b&gt;2. 표현 목적에 따른 렌더링 모드 및 특수 머티리얼&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwjO1evW_v2UAxVwoK8BHVCDFcwQi4wTegoIAggACAEIEBAA&quot; data-bfc=&quot;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCBAQAQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;불투명 (Opaque):&lt;/b&gt; 일반적인 벽, 돌, 금속 등 투명도가 없는 물체에 사용됩니다.&lt;/span&gt;&lt;span&gt; [&lt;a href=&quot;https://onecoke.tistory.com/entry/Unity-Material&quot;&gt;1&lt;/a&gt;]&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCBAQBg&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;투명 (Transparent):&lt;/b&gt; 유리, 물, 홀로그램, 식물의 잎처럼 빛이 투과되거나 반투명한 효과를 냅니다.&lt;/span&gt;&lt;span&gt; [&lt;a href=&quot;https://mvje.tistory.com/83&quot;&gt;1&lt;/a&gt;]&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCBAQCQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;언릿 (Unlit):&lt;/b&gt; 주변의 광원(빛)에 영향을 받지 않고 머티리얼 자체의 색상만 100% 발광하여 보여주는 방식입니다. (카툰 렌더링이나 UI에 주로 사용)&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCBAQDA&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;스킨 (Skin):&lt;/b&gt; 사람의 피부처럼 빛이 표면을 뚫고 들어가 살짝 산란되는 효과(Subsurface Scattering)를 적용한 머티리얼입니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;padding: 0.3em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #5b63fb; font-weight: bold; text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;Lighting &lt;/span&gt;&lt;/h4&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCAMQAA&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-subtree=&quot;aimfl,mfl&quot;&gt;3D 게임에서 라이팅은 게임의 분위기와 사실감을 결정하는 핵심 요소입니다&lt;/span&gt;. 크게 &lt;b&gt;빛의 형태와 역할&lt;/b&gt;에 따른 분류와 &lt;b&gt;연산 방식&lt;/b&gt;에 따른 분류로 나뉩니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCAMQAA&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 20px; font-weight: 600; margin: 24px 0px 12px; text-decoration: none; border-bottom: 0px rgb(238, 240, 255);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot; data-animation-nesting=&quot;&quot;&gt;&lt;b&gt;1. 광원의 형태와 역할에 따른 종류&lt;/b&gt;&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwiVg9_6_v2UAxWds1YBHWN6GaQQi4wTegoIAggACAEIChAA&quot; data-bfc=&quot;&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCAoQAQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;게임 월드 내에서 빛을 뿜어내는 방식에 따른 구분입니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwiVg9_6_v2UAxWds1YBHWN6GaQQi4wTegoIAggACAEICxAA&quot; data-bfc=&quot;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCAsQAQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;디렉셔널 라이트 (Directional Light)&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCAsQAg&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;태양이나 달처럼 무한히 먼 곳에서 평행하게 전체 공간을 비추는 빛입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCAsQAw&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;주로 씬(Scene)의 메인 광원으로 사용되며, 그림자 생성에 매우 효율적입니다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCAsQCA&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;포인트 라이트 (Point Light)&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCAsQCQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;전구나 횃불처럼 한 점(Point)에서 사방으로 퍼져나가는 빛입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCAsQCg&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;특정 범위 내의 물체와 환경을 비출 때 사용됩니다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCAsQDw&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;스포트라이트 (Spot Light)&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCAsQEA&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;손전등이나 무대 조명처럼 특정 원뿔(Cone) 형태나 각도로 퍼져나가는 빛입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCAsQEQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;빛의 도달 거리와 각도를 조절할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCAsQFg&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;에어리어 라이트 (Area Light)&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCAsQFw&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;사각형이나 원통 같은 특정 &lt;b&gt;면(Area)&lt;/b&gt; 에서 빛을 발산합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCAsQGA&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;가장 부드럽고 사실적인 그림자를 만들 수 있지만, 연산 비용이 높아 주로 오프라인 렌더링에 쓰이거나 베이크드 라이트로 활용됩니다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCAsQHg&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;앰비언트 라이트 (Ambient Light)&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCAsQHw&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;어두운 곳에서도 사물의 형태를 알아볼 수 있도록 씬 전체에 기본적으로 깔아주는 환경광입니다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCAsQJA&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;이미시브 라이트 (Emissive Light)&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCAsQJQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;광원 오브젝트 자체가 발광하여 주변을 비추는 효과입니다. (예: 네온사인, 모니터 화면)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwiVg9_6_v2UAxWds1YBHWN6GaQQi4wTegoIAggACAEIEhAA&quot; data-bfc=&quot;&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 20px; font-weight: 600; margin: 24px 0px 12px; text-decoration: none; border-bottom: 0px rgb(238, 240, 255);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot; data-animation-nesting=&quot;&quot;&gt;2. 연산 방식에 따른 종류&lt;/div&gt;
&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwiVg9_6_v2UAxWds1YBHWN6GaQQi4wTegoIAggACAEIFBAA&quot; data-bfc=&quot;&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCBQQAQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;게임 엔진에서 빛과 그림자를 계산하는 방식입니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwiVg9_6_v2UAxWds1YBHWN6GaQQi4wTegoIAggACAEIFxAA&quot; data-bfc=&quot;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCBcQAQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;실시간 라이팅 (Realtime Lighting)&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCBcQAg&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;게임이 실행되는 동안 매 프레임마다 빛과 그림자의 위치를 계산합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCBcQAw&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;캐릭터가 움직이거나 시간이 지남에 따라 변하는 환경에 적합하지만, 높은 사양(GPU)이 요구됩니다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCBcQCA&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;베이크드 라이팅 (Baked Lighting / Precomputed)&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCBcQCQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;게임을 실행하기 전에 미리 빛과 그림자를 계산하여 텍스처(라이트맵) 형태로 굳혀버리는 방식입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCBcQCg&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;그림자 연산이 없어 최적화에 탁월하지만, 움직이는 물체에는 적용할 수 없다는 단점이 있습니다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCBcQDw&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;혼합 라이팅 (Mixed Lighting)&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCBcQEA&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;실시간과 베이크드 방식을 결합한 형태입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCBcQEQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;예를 들어 배경은 미리 구워두고(Bake), 움직이는 플레이어 캐릭터에게만 실시간 그림자가 적용되도록 설정하여 퀄리티와 최적화를 모두 챙길 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwiVg9_6_v2UAxWds1YBHWN6GaQQi4wTegoIAggACAEIGRAA&quot; data-bfc=&quot;&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 20px; font-weight: 600; margin: 24px 0px 12px; text-decoration: none; border-bottom: 0px rgb(238, 240, 255);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot; data-animation-nesting=&quot;&quot;&gt;고급 라이팅 기법&lt;/div&gt;
&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwiVg9_6_v2UAxWds1YBHWN6GaQQi4wTegoIAggACAEIGhAA&quot; data-bfc=&quot;&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCBoQAQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;사실적인 그래픽을 위해 사용되는 현대적인 기술들입니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwiVg9_6_v2UAxWds1YBHWN6GaQQi4wTegoIAggACAEIHBAA&quot; data-bfc=&quot;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCBwQAQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;글로벌 일루미네이션 (Global Illumination, GI)&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCBwQAg&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;광원뿐만 아니라 물체에 부딪혀 튕겨 나오는 빛(반사광)까지 계산하여 극도로 사실적인 명암을 표현하는 기법입니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCBwQBQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;볼류메트릭 라이팅 (Volumetric Lighting)&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgBCBwQBg&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;빛 줄기 효과로, 안개나 먼지가 낀 공간에서 빛의 통로가 눈에 보이도록 렌더링하는 기법입니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwi754Th__2UAxXTh1YBHY3WLwkQi4wTegoIAggACAAIGBAA&quot; data-bfc=&quot;&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 20px; font-weight: 600; margin: 24px 0px 12px; text-decoration: none; border-bottom: 0px rgb(238, 240, 255);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot; data-animation-nesting=&quot;&quot;&gt;루멘 (Lumen) 글로벌 일루미네이션 및 리플렉션&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 20px; font-weight: 600; margin: 24px 0px 12px; text-decoration: none; border-bottom: 0px rgb(238, 240, 255);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot; data-animation-nesting=&quot;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwi754Th__2UAxXTh1YBHY3WLwkQi4wTegoIAggACAAIGhAA&quot; data-bfc=&quot;&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACBoQAQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;언리얼 엔진 5의 핵심 라이팅 시스템인 &lt;b&gt;루멘(Lumen)&lt;/b&gt; 은 빛이 표면에 부딪혀 반사되는 간접광(Global Illumination)과 반사(Reflection)를 실시간으로 처리합니다. 프로젝트 세팅에서 활성화하여 사용할 수 있습니다.
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;장점:&lt;/b&gt; 정적인 라이트 맵을 구울 필요 없이 빛을 수정할 때마다 결과가 뷰포트에 바로 반영되어 작업 속도가 매우 빠릅니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwi754Th__2UAxXTh1YBHY3WLwkQi4wTegoIAggACAAIExAA&quot; data-bfc=&quot;&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 20px; font-weight: 600; margin: 24px 0px 12px; text-decoration: none; border-bottom: 0px rgb(238, 240, 255);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot; data-animation-nesting=&quot;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 20px; font-weight: 600; margin: 24px 0px 12px; text-decoration: none; border-bottom: 0px rgb(238, 240, 255);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot; data-animation-nesting=&quot;&quot;&gt;&lt;b&gt;라이트 모빌리티 (Mobility)&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwi754Th__2UAxXTh1YBHY3WLwkQi4wTegoIAggACAAIFBAA&quot; data-bfc=&quot;&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACBQQAQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;라이트를 생성하면 &lt;b&gt;디테일(Details)&lt;/b&gt; 패널에서 모빌리티 설정을 지정해야 합니다. 이는 빛이 어떻게 연산되고 그림자가 표현되는지를 결정합니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwi754Th__2UAxXTh1YBHY3WLwkQi4wTegoIAggACAAIFRAA&quot; data-bfc=&quot;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACBUQAQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;스태틱 (Static):&lt;/b&gt; 완전히 고정된 라이트로, 런타임에 연산되지 않고 오프라인 상태에서 미리 구워(Bake) 둡니다. 성능 비용이 가장 낮지만 움직이는 물체에는 그림자가 제대로 적용되지 않습니다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACBUQBA&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;무버블 (Movable):&lt;/b&gt; 실시간으로 이동하고 작동하는 동적 라이트입니다. 퀄리티가 높고 움직이는 오브젝트에 완벽하게 반응하지만, 성능 소모가 가장 큽니다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACBUQBw&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;스테이셔너리 (Stationary):&lt;/b&gt; 라이트의 위치와 모양은 고정되어 있지만, 밝기와 색상 등은 실시간으로 변경할 수 있습니다. 스태틱과 무버블의 장점을 혼합한 방식으로, 고정된 환경에서 동적 그림자가 필요한 경우 주로 사용합니다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&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 style=&quot;font-family: Nanum Gothic;&quot;&gt;게임에서 빛의 역할들&lt;/span&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;공간감 형성: 그림자를 통해 깊이감 제공&lt;/li&gt;
&lt;li&gt;플레이 경험 보조: 위험 지역, 안전 지역, 목표 지점 강조&lt;/li&gt;
&lt;/ul&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 style=&quot;font-family: Nanum Gothic;&quot;&gt;[언리얼&amp;nbsp;페스트&amp;nbsp;서울&amp;nbsp;2025]&amp;nbsp;Day2&amp;nbsp;라이팅&amp;nbsp;팁:&amp;nbsp;라이트를&amp;nbsp;이해하는&amp;nbsp;법(feat.&amp;nbsp;CG&amp;nbsp;아티스트들이&amp;nbsp;라이트에&amp;nbsp;관심&amp;nbsp;없는&amp;nbsp;이유)&amp;nbsp;: &lt;a href=&quot;https://youtu.be/Mr_1CBuoThI&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://youtu.be/Mr_1CBuoThI&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=Mr_1CBuoThI&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/KjM1e/dJMb9efmddt/BWxK471bOXG2UTlB7mEss1/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720,https://scrap.kakaocdn.net/dn/0PTx3/dJMb9lMjFpB/nWmI4qKbXAIL8N0QqZGF51/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720,https://scrap.kakaocdn.net/dn/L5Tw7/dJMb9bwasxi/LoZDKInr1LC7ofNAHAt6O1/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;[언리얼 페스트 서울 2025] Day2 라이팅 팁: 라이트를 이해하는 법(feat. CG 아티스트들이 라이트에 관&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/Mr_1CBuoThI&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h4 style=&quot;padding: 0.3em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #5b63fb; font-weight: bold; text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;Animation &lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐릭터나 오브젝트의 움직임을 표현합니다.게임에서 Animation은 단순 재생 영상이 아니라 입력, 상태, 판정, 피드백과 연결된다.&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;&lt;b&gt; 공격 시작 타이밍:&amp;nbsp;&lt;/b&gt; 입력 후 언제 공격이 시작되는가&lt;/li&gt;
&lt;li&gt;&lt;b&gt; 무기 이동 타이밍&lt;/b&gt;: 무기가 실제로 휘둘리는 시점&lt;/li&gt;
&lt;li&gt;&lt;b&gt; 판정 타이밍&lt;/b&gt;: 데미지가 적용되는 시점&lt;/li&gt;
&lt;li&gt;&lt;b&gt; 이펙트 타이밍&lt;/b&gt;: Slash VFX, Hit VFX가 나오는 시점&lt;/li&gt;
&lt;li&gt;&lt;b&gt; 후속 행동 타이밍&lt;/b&gt;: 다음 행동으로 넘어갈 수 있는 시점&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;padding: 0.3em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #5b63fb; font-weight: bold; text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;VFX (Visual Effects, 시각 특수 효과)&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 700; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-subtree=&quot;aimfl,mfl&quot;&gt;3D 게임에서 VFX(Visual Effects, 시각 특수 효과)&lt;/span&gt;&lt;/b&gt;는 &lt;/span&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 500; margin: 0px; text-decoration: none; border-bottom: 0px rgb(238, 240, 255);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;게임 화면에 등장하는 마법, 폭발, 불, 물, 날씨 등 현실에서 직접 촬영하기 어렵거나 상상 속에만 존재하는 시각적 요소들을 컴퓨터 그래픽으로 구현하는 작업&lt;/span&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;입니다&lt;/span&gt;&lt;/p&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwjKhavOgf6UAxWXklYBHWzbAVkQi4wTegoIAggACAAIBxAA&quot; data-bfc=&quot;&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 20px; font-weight: 600; margin: 24px 0px 12px; text-decoration: none; border-bottom: 0px rgb(238, 240, 255);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot; data-animation-nesting=&quot;&quot;&gt;&lt;b&gt;1. 3D 게임 VFX의 핵심 역할&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwjKhavOgf6UAxWXklYBHWzbAVkQi4wTegoIAggACAAICBAA&quot; data-bfc=&quot;&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACAgQAQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;게임에서 VFX는 단순한 배경 장식을 넘어 게임플레이의 핵심적인 요소로 작동합니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwjKhavOgf6UAxWXklYBHWzbAVkQi4wTegoIAggACAAICxAA&quot; data-bfc=&quot;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACAsQAQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;타격감 및 피드백:&lt;/b&gt; 캐릭터가 스킬을 사용하거나 적을 공격할 때 번쩍이는 효과, 화면 흔들림, 파편 튀김 등을 통해 타격감과 조작의 재미를 극대화합니다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACAsQBg&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;몰입감 조성:&lt;/b&gt; 비, 눈, 안개, 모래바람 등 환경 효과를 만들어내어 게임의 분위기를 살립니다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACAsQCw&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;정보 전달:&lt;/b&gt; 캐릭터의 상태(예: 독에 걸림, 보호막 생성 등)를 시각적으로 명확하게 전달하여 유저가 상황을 인지하도록 돕습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwjKhavOgf6UAxWXklYBHWzbAVkQi4wTegoIAggACAAIDRAA&quot; data-bfc=&quot;&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 20px; font-weight: 600; margin: 24px 0px 12px; text-decoration: none; border-bottom: 0px rgb(238, 240, 255);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot; data-animation-nesting=&quot;&quot;&gt;&lt;b&gt;2. 주요 제작 분야&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwjKhavOgf6UAxWXklYBHWzbAVkQi4wTegoIAggACAAIDxAA&quot; data-bfc=&quot;&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACA8QAQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;게임 VFX는 크게 다음과 같은 효과들을 다룹니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwjKhavOgf6UAxWXklYBHWzbAVkQi4wTegoIAggACAAIERAA&quot; data-bfc=&quot;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACBEQAQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;스킬 및 마법 이펙트:&lt;/b&gt; 캐릭터의 액션에 동반되는 화려한 오라, 광선, 마법진.&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACBEQAg&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;물리/환경 효과:&lt;/b&gt; 폭발, 연기, 불꽃, 물의 흐름, 파도.&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACBEQAw&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;UI 및 연출 효과:&lt;/b&gt; 화면 가장자리가 붉어지는 피해 효과, 레벨 업 시 발생하는 빛 기둥 등.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwjKhavOgf6UAxWXklYBHWzbAVkQi4wTegoIAggACAAIFhAA&quot; data-bfc=&quot;&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 20px; font-weight: 600; margin: 24px 0px 12px; text-decoration: none; border-bottom: 0px rgb(238, 240, 255);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot; data-animation-nesting=&quot;&quot;&gt;&lt;b&gt;3. 게임 VFX 제작에 쓰이는 기술과 도구&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwjKhavOgf6UAxWXklYBHWzbAVkQi4wTegoIAggACAAIGxAA&quot; data-bfc=&quot;&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACBsQAQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;영화 VFX가 완성된 영상에 효과를 합성하는 것과 달리, 3D 게임 VFX는 실시간으로 화면을 렌더링해야 하므로 다음과 같은 기술과 툴이 주로 사용됩니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-ved=&quot;2ahUKEwjKhavOgf6UAxWXklYBHWzbAVkQi4wTegoIAggACAAIHRAA&quot; data-bfc=&quot;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACB0QAQ&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;파티클 시스템 (Particle System):&lt;/b&gt; 불꽃, 빗방울, 먼지처럼 수많은 작은 점이나 이미지를 흩날려 형태를 만드는 기술입니다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACB0QBw&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;셰이더 (Shader):&lt;/b&gt; 빛의 반사, 굴절, 물의 일렁임 등을 수학적으로 계산하여 화면에 그려내는 프로그래밍 및 노드 기반 기술입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAIIAAgACB0QCg&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;주요 엔진 툴: &lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;언리얼 엔진(Unreal Engine)&lt;/span&gt;의 나이아가라(Niagara)&lt;/b&gt;나 &lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;유니티(Unity)&lt;/span&gt;의 비주얼 이펙트 그래프(VFX Graph)를 주로 사용합니다&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게임에서 많이 쓰이는 VFX 예시&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;폭발: 강한 충격 표현&lt;/li&gt;
&lt;li&gt;먼지 / 불꽃: 상황의 질감 표현&lt;/li&gt;
&lt;li&gt;마법 효과: 스킬의 성격 표현&lt;/li&gt;
&lt;li&gt;위험 범위 표시: 플레이어에게 회피 정보 전달&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style2&quot; data-ke-type=&quot;horizontalRule&quot; /&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;h3 id=&quot;a2&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;과제 (게임 분석): 게임 액션 하나를 선택하고 리소스 연결 구조 분석하기 &lt;/span&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&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;선택한 게임과 액션:&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&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;총 발사&lt;/li&gt;
&lt;li&gt;피격&lt;/li&gt;
&lt;li&gt;점프 착지&lt;/li&gt;
&lt;li&gt;아이템 사용&lt;/li&gt;
&lt;li&gt;문 열기&lt;/li&gt;
&lt;li&gt;대시 이동&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&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;Mesh:&lt;/li&gt;
&lt;li&gt;Animation:&lt;/li&gt;
&lt;li&gt;VFX:&lt;/li&gt;
&lt;li&gt;Material:&lt;/li&gt;
&lt;li&gt;Sound:&lt;/li&gt;
&lt;li&gt;Camera:&lt;/li&gt;
&lt;li&gt;UI:&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;연결 흐름&lt;/b&gt;:&lt;/p&gt;
&lt;p 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-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개발자 담당:&lt;/li&gt;
&lt;li&gt;아티스트 담당:&lt;/li&gt;
&lt;li&gt;TA 관점에서 확인할 부분:&lt;/li&gt;
&lt;/ul&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;h3 style=&quot;padding: 0.3em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #5b63fb; font-weight: bold; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;추천&lt;/span&gt;&lt;/h3&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;a href=&quot;https://www.unrealengine.com/tech-blog/jobs-in-unreal-engine---technical-artist?lang=ko&quot;&gt;https://www.unrealengine.com/tech-blog/jobs-in-unreal-engine---technical-artist?lang=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781137708668&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;언리얼 엔진 직무 살펴보기 - 테크니컬 아티스트&quot; data-og-description=&quot;실시간 기술 관련 커리어를 찾고 계신다면, 급성장 중인 테크니컬 아티스트를 고려해보시는 것은 어떨까요? 지난 12개월 사이에 수요가 48%나 증가한 이 직무는 아트와 코드를 잇는 중요한 역할&quot; data-og-host=&quot;www.unrealengine.com&quot; data-og-source-url=&quot;https://www.unrealengine.com/tech-blog/jobs-in-unreal-engine---technical-artist?lang=ko&quot; data-og-url=&quot;https://www.unrealengine.com/tech-blog/jobs-in-unreal-engine---technical-artist&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ef3wfH/dJMb88e8XPH/lyKAH9Q7QTjAAMqlLjnrOK/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/f76Mh/dJMb86O90Dt/IprUl6dOvG0hK1qVHJFlm1/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/720Ke/dJMb8Z3zHfC/WdBGBmqz46k4RtQ80vtOiK/img.jpg?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080&quot;&gt;&lt;a href=&quot;https://www.unrealengine.com/tech-blog/jobs-in-unreal-engine---technical-artist?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.unrealengine.com/tech-blog/jobs-in-unreal-engine---technical-artist?lang=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ef3wfH/dJMb88e8XPH/lyKAH9Q7QTjAAMqlLjnrOK/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/f76Mh/dJMb86O90Dt/IprUl6dOvG0hK1qVHJFlm1/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/720Ke/dJMb8Z3zHfC/WdBGBmqz46k4RtQ80vtOiK/img.jpg?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;언리얼 엔진 직무 살펴보기 - 테크니컬 아티스트&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;실시간 기술 관련 커리어를 찾고 계신다면, 급성장 중인 테크니컬 아티스트를 고려해보시는 것은 어떨까요? 지난 12개월 사이에 수요가 48%나 증가한 이 직무는 아트와 코드를 잇는 중요한 역할&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.unrealengine.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Skeletal Mesh to Static Mesh Conversion: &lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/skeletal-mesh-to-static-mesh-conversion-in-unreal-engine&quot;&gt;https://dev.epicgames.com/documentation/unreal-engine/skeletal-mesh-to-static-mesh-conversion-in-unreal-engine&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781140346848&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Skeletal Mesh to Static Mesh Conversion in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&quot; data-og-description=&quot;Learn how to convert posed Skeletal Mesh assets to Static Mesh assets in Unreal Engine.&quot; data-og-host=&quot;dev.epicgames.com&quot; data-og-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/skeletal-mesh-to-static-mesh-conversion-in-unreal-engine&quot; data-og-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/skeletal-mesh-to-static-mesh-conversion-in-unreal-engine&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/UWKYH/dJMb9jOu6XX/uNqstTPkwRWKSRRAiDiAak/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/bgvCJ2/dJMb9g5jeBG/e5h1bPs1cHsdptrG7Xtgi1/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/IdJil/dJMb9eTXKqW/lAeSTLZojkZa1zVsXkwvwk/img.png?width=1286&amp;amp;height=726&amp;amp;face=0_0_1286_726&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/skeletal-mesh-to-static-mesh-conversion-in-unreal-engine&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/skeletal-mesh-to-static-mesh-conversion-in-unreal-engine&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/UWKYH/dJMb9jOu6XX/uNqstTPkwRWKSRRAiDiAak/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/bgvCJ2/dJMb9g5jeBG/e5h1bPs1cHsdptrG7Xtgi1/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/IdJil/dJMb9eTXKqW/lAeSTLZojkZa1zVsXkwvwk/img.png?width=1286&amp;amp;height=726&amp;amp;face=0_0_1286_726');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Skeletal Mesh to Static Mesh Conversion in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Learn how to convert posed Skeletal Mesh assets to Static Mesh assets in Unreal Engine.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.epicgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;메시를&amp;nbsp;스켈레탈&amp;nbsp;메시로&amp;nbsp;변환하기: &lt;a href=&quot;https://dev.epicgames.com/documentation/fortnite/convert-a-static-mesh-into-a-skeletal-mesh-in-unreal-editor-for-fortnite?lang=ko&quot;&gt;https://dev.epicgames.com/documentation/fortnite/convert-a-static-mesh-into-a-skeletal-mesh-in-unreal-editor-for-fortnite?lang=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781140349747&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Convert a Static Mesh into a Skeletal Mesh in Unreal Editor for Fortnite | Fortnite Documentation | Epic Developer Community&quot; data-og-description=&quot;Create a fully working Skeletal Mesh from a Static Mesh using the suite of Mesh editors in Unreal Editor for Fortnite.&quot; data-og-host=&quot;dev.epicgames.com&quot; data-og-source-url=&quot;https://dev.epicgames.com/documentation/fortnite/convert-a-static-mesh-into-a-skeletal-mesh-in-unreal-editor-for-fortnite?lang=ko&quot; data-og-url=&quot;https://dev.epicgames.com/documentation/fortnite/convert-a-static-mesh-into-a-skeletal-mesh-in-unreal-editor-for-fortnite&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/o4Qut/dJMb9dHwoPd/kRiZnGLPLEqZvKJrMatkN1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bg3oP3/dJMb84X6ZER/6qdDLylZxvrRUrJ0Im8ZE1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/jRiZ4/dJMb9gxtD17/WLQtDLQTAiKHm8MZ5qY5S1/img.png?width=1900&amp;amp;height=335&amp;amp;face=0_0_1900_335&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/fortnite/convert-a-static-mesh-into-a-skeletal-mesh-in-unreal-editor-for-fortnite?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.epicgames.com/documentation/fortnite/convert-a-static-mesh-into-a-skeletal-mesh-in-unreal-editor-for-fortnite?lang=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/o4Qut/dJMb9dHwoPd/kRiZnGLPLEqZvKJrMatkN1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bg3oP3/dJMb84X6ZER/6qdDLylZxvrRUrJ0Im8ZE1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/jRiZ4/dJMb9gxtD17/WLQtDLQTAiKHm8MZ5qY5S1/img.png?width=1900&amp;amp;height=335&amp;amp;face=0_0_1900_335');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Convert a Static Mesh into a Skeletal Mesh in Unreal Editor for Fortnite | Fortnite Documentation | Epic Developer Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Create a fully working Skeletal Mesh from a Static Mesh using the suite of Mesh editors in Unreal Editor for Fortnite.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.epicgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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 style=&quot;font-family: Nanum Gothic;&quot;&gt;[언리얼&amp;nbsp;페스트&amp;nbsp;서울&amp;nbsp;2025]&amp;nbsp;Day2&amp;nbsp;라이팅&amp;nbsp;팁:&amp;nbsp;라이트를&amp;nbsp;이해하는&amp;nbsp;법(feat.&amp;nbsp;CG&amp;nbsp;아티스트들이&amp;nbsp;라이트에&amp;nbsp;관심&amp;nbsp;없는&amp;nbsp;이유)&amp;nbsp;: &lt;a href=&quot;https://youtu.be/Mr_1CBuoThI&quot;&gt;https://youtu.be/Mr_1CBuoThI&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=Mr_1CBuoThI&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/KjM1e/dJMb9efmddt/BWxK471bOXG2UTlB7mEss1/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720,https://scrap.kakaocdn.net/dn/0PTx3/dJMb9lMjFpB/nWmI4qKbXAIL8N0QqZGF51/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720,https://scrap.kakaocdn.net/dn/L5Tw7/dJMb9bwasxi/LoZDKInr1LC7ofNAHAt6O1/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;[언리얼 페스트 서울 2025] Day2 라이팅 팁: 라이트를 이해하는 법(feat. CG 아티스트들이 라이트에 관&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/Mr_1CBuoThI&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/pages/Unreal-Engine-%EC%96%B8%EB%A6%AC%EC%96%BC-%EC%97%94%EC%A7%84&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;[페이지] Unreal Engine | 언리얼 엔진&lt;/b&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Unreal Engine/TA</category>
      <category>C++</category>
      <category>Programming</category>
      <category>ta</category>
      <category>Technical Artist</category>
      <category>UE</category>
      <category>UE5</category>
      <category>Unreal engine</category>
      <category>게임 개발</category>
      <category>언리얼 엔진</category>
      <category>프로그래밍</category>
      <author>DevCol</author>
      <guid isPermaLink="true">https://devcol.tistory.com/113</guid>
      <comments>https://devcol.tistory.com/113#entry113comment</comments>
      <pubDate>Fri, 12 Jun 2026 00:32:51 +0900</pubDate>
    </item>
    <item>
      <title>TA | 아이템 시스템과 게임 흐름 로직 구현하기 | 코드 카타 (Code Kata): 둘만의 암호 | TIL 35th | 캠프 34일 차 | 06/11/2026 (Thur)</title>
      <link>https://devcol.tistory.com/112</link>
      <description>&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;TA&amp;nbsp;|&amp;nbsp;아이템&amp;nbsp;시스템과&amp;nbsp;게임&amp;nbsp;흐름&amp;nbsp;로직&amp;nbsp;구현하기&amp;nbsp;|&amp;nbsp;코드&amp;nbsp;카타&amp;nbsp;(Code&amp;nbsp;Kata):&amp;nbsp;둘만의&amp;nbsp;암호&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a1&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot; data-token-index=&quot;0&quot;&gt;TA&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/113&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Unreal Engine/TA] - [TA] TA - Technical Artist (테크니컬 아티스트)란? | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781192072867&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[TA] TA - Technical Artist (테크니컬 아티스트)란? | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;언리얼엔진 공식문서 - 직무 가이드 살펴보기: https://www.unrealengine.com/tech-blog/jobs-in-unreal-engine---technical-artist?lang=ko 언리얼 엔진 직무 살펴보기 - 테크니컬 아티스트실시간 기술 관련 커리어를 찾&quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/113&quot; data-og-url=&quot;https://devcol.tistory.com/113&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/EStWD/dJMb81f0ZOb/MwvK7y3keWccy0LJq6RQo1/img.gif?width=610&amp;amp;height=508&amp;amp;face=0_0_610_508,https://scrap.kakaocdn.net/dn/oaNOp/dJMb82eVmKg/Vkb6ZNpktKNXijkSwb3U4K/img.gif?width=610&amp;amp;height=508&amp;amp;face=0_0_610_508&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/113&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/113&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/EStWD/dJMb81f0ZOb/MwvK7y3keWccy0LJq6RQo1/img.gif?width=610&amp;amp;height=508&amp;amp;face=0_0_610_508,https://scrap.kakaocdn.net/dn/oaNOp/dJMb82eVmKg/Vkb6ZNpktKNXijkSwb3U4K/img.gif?width=610&amp;amp;height=508&amp;amp;face=0_0_610_508');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[TA] TA - Technical Artist (테크니컬 아티스트)란? | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;언리얼엔진 공식문서 - 직무 가이드 살펴보기: https://www.unrealengine.com/tech-blog/jobs-in-unreal-engine---technical-artist?lang=ko 언리얼 엔진 직무 살펴보기 - 테크니컬 아티스트실시간 기술 관련 커리어를 찾&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a2&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;&amp;nbsp;&lt;/span&gt;아이템&amp;nbsp;시스템과&amp;nbsp;게임&amp;nbsp;흐름&amp;nbsp;로직&amp;nbsp;구현하기&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/107&quot;&gt;[Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781192108925&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;인터페이스 기반 아이템 클래스 설계하기 인터페이스 이해하기1️⃣ 인터페이스란?인터페이스 (Interface)란 클래스 (또는 오브젝트)가 반드시 구현해야 할 함수 목록만을 미리 정의해 두고, 실제 &quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/107&quot; data-og-url=&quot;https://devcol.tistory.com/107&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/sA9RM/dJMb9frNEV7/mqumL986okRdsyJE9ASHo1/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/biAScA/dJMb9gxtHkU/Yh7zNXgwmwbeJInju0dqf1/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/ApySg/dJMb87geO5s/dnf4JtgjnftSvuuZiKWhhK/img.png?width=997&amp;amp;height=544&amp;amp;face=0_0_997_544&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/107&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/107&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/sA9RM/dJMb9frNEV7/mqumL986okRdsyJE9ASHo1/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/biAScA/dJMb9gxtHkU/Yh7zNXgwmwbeJInju0dqf1/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/ApySg/dJMb87geO5s/dnf4JtgjnftSvuuZiKWhhK/img.png?width=997&amp;amp;height=544&amp;amp;face=0_0_997_544');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스 기반 아이템 클래스 설계하기 인터페이스 이해하기1️⃣ 인터페이스란?인터페이스 (Interface)란 클래스 (또는 오브젝트)가 반드시 구현해야 할 함수 목록만을 미리 정의해 두고, 실제&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://devcol.tistory.com/108&quot;&gt;[Unreal Engine/UE 기초] - 충돌 이벤트로 획득되는 아이템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781192110315&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;충돌 이벤트로 획득되는 아이템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;충돌 이벤트로 획득되는 아이템 구현하기 이전 포스팅에서는 클래스 구조만 짜고 로직은 비여있던 상태.이전 포스팅: [Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼 &quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/108&quot; data-og-url=&quot;https://devcol.tistory.com/108&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/jmWjD/dJMb82MLsPp/7QMxGqRnfqAFCn6p5k8tkk/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/JFK5Z/dJMb81G5Lvh/TXhxaBoI1kuEALcXwK5ByK/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/bHB478/dJMb9g5jhTi/zCDS1GY8Z9i42g4dal6kB0/img.png?width=1596&amp;amp;height=489&amp;amp;face=0_0_1596_489&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/108&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/108&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/jmWjD/dJMb82MLsPp/7QMxGqRnfqAFCn6p5k8tkk/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/JFK5Z/dJMb81G5Lvh/TXhxaBoI1kuEALcXwK5ByK/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/bHB478/dJMb9g5jhTi/zCDS1GY8Z9i42g4dal6kB0/img.png?width=1596&amp;amp;height=489&amp;amp;face=0_0_1596_489');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;충돌 이벤트로 획득되는 아이템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;충돌 이벤트로 획득되는 아이템 구현하기 이전 포스팅에서는 클래스 구조만 짜고 로직은 비여있던 상태.이전 포스팅: [Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://devcol.tistory.com/109&quot;&gt;[Unreal Engine/UE 기초] - 아이템 스폰 및 레벨 데이터 관리하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781192111489&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;아이템 스폰 및 레벨 데이터 관리하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;아이템 스폰 및 레벨 데이터 관리하기 랜덤 위치에 아이템 스폰하기 1️⃣ 레벨 셋팅하기Resources 폴더에 Maps 폴더에는 3개의 레벨이 이미 존재합니다. 각각 난이도에 따라서 크기가 다른 맵이고, &quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/109&quot; data-og-url=&quot;https://devcol.tistory.com/109&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cLGxfm/dJMb8Yp3Jgs/XodaPA7Bq8Q2bwJcaYrOk1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/b3TL4M/dJMb81f0W7R/XxH3bkz7XP3Dxcl22AJkU1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/c4oxJD/dJMb89ylWzD/GSEuPUkAww5SFszPpPhOs1/img.png?width=940&amp;amp;height=571&amp;amp;face=0_0_940_571&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/109&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/109&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cLGxfm/dJMb8Yp3Jgs/XodaPA7Bq8Q2bwJcaYrOk1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/b3TL4M/dJMb81f0W7R/XxH3bkz7XP3Dxcl22AJkU1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/c4oxJD/dJMb89ylWzD/GSEuPUkAww5SFszPpPhOs1/img.png?width=940&amp;amp;height=571&amp;amp;face=0_0_940_571');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;아이템 스폰 및 레벨 데이터 관리하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;아이템 스폰 및 레벨 데이터 관리하기 랜덤 위치에 아이템 스폰하기 1️⃣ 레벨 셋팅하기Resources 폴더에 Maps 폴더에는 3개의 레벨이 이미 존재합니다. 각각 난이도에 따라서 크기가 다른 맵이고,&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://devcol.tistory.com/110&quot;&gt;[Unreal Engine/UE 기초] - 캐릭터 체력 및 점수 관리 시스템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781192112544&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;캐릭터 체력 및 점수 관리 시스템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;캐릭터 체력 및 점수 관리 시스템 구현하기 캐릭터 체력 시스템 구현하기 1️⃣ 캐릭터 클래스에 체력 변수 및 함수 선언PlayerState를 쓰지 않는 이유PlayerState: 각 플레이어마다의 어떤 정보를 관&quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/110&quot; data-og-url=&quot;https://devcol.tistory.com/110&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bYqXoH/dJMb8WMxYMp/5mzpC6c0dk8y31rndJrJuK/img.png?width=773&amp;amp;height=359&amp;amp;face=0_0_773_359,https://scrap.kakaocdn.net/dn/ectDw4/dJMb9gxtHk0/ZVLADkGrrgLpKlXy7MKsi0/img.png?width=773&amp;amp;height=359&amp;amp;face=0_0_773_359,https://scrap.kakaocdn.net/dn/bEAEtk/dJMb8SpQkZA/PbM36SDF25VGpi0p9ZsKz1/img.png?width=915&amp;amp;height=558&amp;amp;face=0_0_915_558&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/110&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/110&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bYqXoH/dJMb8WMxYMp/5mzpC6c0dk8y31rndJrJuK/img.png?width=773&amp;amp;height=359&amp;amp;face=0_0_773_359,https://scrap.kakaocdn.net/dn/ectDw4/dJMb9gxtHk0/ZVLADkGrrgLpKlXy7MKsi0/img.png?width=773&amp;amp;height=359&amp;amp;face=0_0_773_359,https://scrap.kakaocdn.net/dn/bEAEtk/dJMb8SpQkZA/PbM36SDF25VGpi0p9ZsKz1/img.png?width=915&amp;amp;height=558&amp;amp;face=0_0_915_558');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;캐릭터 체력 및 점수 관리 시스템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;캐릭터 체력 및 점수 관리 시스템 구현하기 캐릭터 체력 시스템 구현하기 1️⃣ 캐릭터 클래스에 체력 변수 및 함수 선언PlayerState를 쓰지 않는 이유PlayerState: 각 플레이어마다의 어떤 정보를 관&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://devcol.tistory.com/111&quot;&gt;[Unreal Engine/UE 기초] - 게임 루프 설계를 통한 게임 흐름 제어하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781192115205&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;게임 루프 설계를 통한 게임 흐름 제어하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;게임 루프 설계를 통한 게임 흐름 제어하기 GameState를 이용한 게임 루프 구현하기 게임루프: 보통 게임의 핵심적인 흐름을 얘기합니다. 즉 게임이 시작할 때부터 종료까지 수행하는 단계들게임&quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/111&quot; data-og-url=&quot;https://devcol.tistory.com/111&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/m3HSO/dJMb8Yp3LZc/oDKcOSmHa6KQokX0K8otyK/img.png?width=800&amp;amp;height=566&amp;amp;face=0_0_800_566,https://scrap.kakaocdn.net/dn/bezEhJ/dJMb8TCh97F/a38cyWkwwklT9XZIOkmAI0/img.png?width=800&amp;amp;height=566&amp;amp;face=0_0_800_566,https://scrap.kakaocdn.net/dn/dBmfWn/dJMb8Yp3LZb/ZKEpbaswdrCszr1LfiKXDk/img.png?width=1167&amp;amp;height=827&amp;amp;face=0_0_1167_827&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/111&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/111&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/m3HSO/dJMb8Yp3LZc/oDKcOSmHa6KQokX0K8otyK/img.png?width=800&amp;amp;height=566&amp;amp;face=0_0_800_566,https://scrap.kakaocdn.net/dn/bezEhJ/dJMb8TCh97F/a38cyWkwwklT9XZIOkmAI0/img.png?width=800&amp;amp;height=566&amp;amp;face=0_0_800_566,https://scrap.kakaocdn.net/dn/dBmfWn/dJMb8Yp3LZb/ZKEpbaswdrCszr1LfiKXDk/img.png?width=1167&amp;amp;height=827&amp;amp;face=0_0_1167_827');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;게임 루프 설계를 통한 게임 흐름 제어하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;게임 루프 설계를 통한 게임 흐름 제어하기 GameState를 이용한 게임 루프 구현하기 게임루프: 보통 게임의 핵심적인 흐름을 얘기합니다. 즉 게임이 시작할 때부터 종료까지 수행하는 단계들게임&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a4&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;코드 카타 (Code Kata) : 둘만의 암호&lt;/h3&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;a href=&quot;https://github.com/devcol-main/CodeKata/blob/455afb31f97c399b772ad546584bc1013af901d9/Programmers/067.%20%EB%91%98%EB%A7%8C%EC%9D%98%20%EC%95%94%ED%98%B8.md&quot; data-tooltip-position=&quot;top&quot;&gt;067. 둘만의 암호&lt;/a&gt; | Solved Date: 2026-06-11-Thur | &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/155652?language=cpp&quot; data-tooltip-position=&quot;top&quot;&gt;Problem Link&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781191460572&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;CodeKata/Programmers/067. 둘만의 암호.md at 455afb31f97c399b772ad546584bc1013af901d9 &amp;middot; devcol-main/CodeKata&quot; data-og-description=&quot;CodeKata. Contribute to devcol-main/CodeKata development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/devcol-main/CodeKata/blob/455afb31f97c399b772ad546584bc1013af901d9/Programmers/067.%20%EB%91%98%EB%A7%8C%EC%9D%98%20%EC%95%94%ED%98%B8.md&quot; data-og-url=&quot;https://github.com/devcol-main/CodeKata/blob/455afb31f97c399b772ad546584bc1013af901d9/Programmers/067.%20%EB%91%98%EB%A7%8C%EC%9D%98%20%EC%95%94%ED%98%B8.md&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/V5cFz/dJMb8YXT3kz/W8uelUndJCPfkLKZWYNi71/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/wTOZk/dJMb8QMkuKq/doL4u4HR8QKvhy9wjlbfiK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/devcol-main/CodeKata/blob/455afb31f97c399b772ad546584bc1013af901d9/Programmers/067.%20%EB%91%98%EB%A7%8C%EC%9D%98%20%EC%95%94%ED%98%B8.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/devcol-main/CodeKata/blob/455afb31f97c399b772ad546584bc1013af901d9/Programmers/067.%20%EB%91%98%EB%A7%8C%EC%9D%98%20%EC%95%94%ED%98%B8.md&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/V5cFz/dJMb8YXT3kz/W8uelUndJCPfkLKZWYNi71/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/wTOZk/dJMb8QMkuKq/doL4u4HR8QKvhy9wjlbfiK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;CodeKata/Programmers/067. 둘만의 암호.md at 455afb31f97c399b772ad546584bc1013af901d9 &amp;middot; devcol-main/CodeKata&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;CodeKata. Contribute to devcol-main/CodeKata development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL/Boot Camp</category>
      <category>C++</category>
      <category>Code Kata</category>
      <category>Devlog</category>
      <category>Programming</category>
      <category>til</category>
      <category>Unreal engine</category>
      <category>게임 개발</category>
      <category>언리얼 엔진</category>
      <category>코드카타</category>
      <category>프로그래밍</category>
      <author>DevCol</author>
      <guid isPermaLink="true">https://devcol.tistory.com/112</guid>
      <comments>https://devcol.tistory.com/112#entry112comment</comments>
      <pubDate>Thu, 11 Jun 2026 23:55:57 +0900</pubDate>
    </item>
    <item>
      <title>게임 루프 설계를 통한 게임 흐름 제어하기 | [언리얼 엔진 C++ (Unreal Engine C++)]</title>
      <link>https://devcol.tistory.com/111</link>
      <description>&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt; 게임 루프 설계를 통한 게임 흐름 제어하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a1&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;GameState를 이용한 게임 루프 구현하기&lt;/h3&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;게임루프&lt;/b&gt;: 보통 게임의 핵심적인 흐름을 얘기합니다. 즉 게임이 시작할 때부터 종료까지 수행하는 단계들&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;게임플로우&lt;/b&gt;: 게임을 시작해서 진행하고 끝내는 과정에서 발생하는 모든 상호작용들&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣ &lt;b&gt;GameState와 GameMode&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언리얼 엔진에서 &lt;b&gt;게임 루프나 전역 상태&lt;/b&gt;를 관리할 때 대표적으로 고려되는 클래스는 &lt;b&gt;GameState&lt;/b&gt;와 &lt;b&gt;GameMode&lt;/b&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;b&gt;GameMode를 쓰는 이유는?&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;서버 전용&lt;/b&gt; 로직을 담는 곳이며, 게임 규칙 (팀 배정, 승패 조건, 플레이어 스폰 등)을 서버에서 제어하는 데 사용됩니다.&lt;/li&gt;
&lt;li&gt;클라이언트는 GameMode에 직접 접근할 수 없습니다. 따라서 &lt;b&gt;클라이언트도 알아야 하는 정보&lt;/b&gt;(예: 남은 시간, 현재 점수 등)를 GameMode에만 두면 복잡해집니다.&lt;/li&gt;
&lt;li&gt;보통 멀티플레이를 고려한다면, &amp;ldquo;중요 규칙 로직&amp;rdquo;만 GameMode에 두고, &amp;ldquo;서버-클라이언트가 공통으로 알아야 하는 상태&amp;rdquo;는 GameState에 두는 방식을 많이 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GameState를 쓰는 이유는?&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;게임 전반에 걸쳐 &lt;b&gt;모든 플레이어가 공유&lt;/b&gt;해야 하는 상태를 담는 클래스입니다. 보통 전역 상태가 필요할 경우 GameState를 활용합니다.&lt;/li&gt;
&lt;li&gt;GameState 객체는 게임이 시작될 때 서버에서 생성되고, 클라이언트는 이를 복제받아서 똑같은 정보를 읽을 수 있습니다. 즉, &amp;ldquo;서버와 클라이언트 모두&amp;rdquo; 동일한 정보를 가지게 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이번 강의에서는 레벨마다 40개의 아이템을 스폰하고, 시간 제한 30초 내에 플레이어가 모든 코인을 주우면 즉시 레벨이 끝나고 다음 레벨로 넘어가는 구조를 만들 것입니다. 이처럼 멀티플레이를 고려했을 때도 클라이언트가 알아야 할 상태가 많아지므로, GameMode 대신 GameState를 선택하여 전역 상태를 관리하는 방식으로 구현합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2️⃣ &lt;b&gt;SpawnVolume 클래스 스폰 데이터 반환 수정&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기존에는 스폰 함수가 void를 반환했는데, 스폰된 아이템의 정보 (코인이 맞는지, 혹은 다른 아이템인지)를 추후 GameState에서 카운팅 하려면, 스폰 함수가 스폰된 AActor*를 반환해야 합니다.&lt;/li&gt;
&lt;li&gt;아래 코드에서는 SpawnRandomItem()이 스폰된 액터 포인터를 반환하도록 수정하고, 그 액터가 코인인지 확인할 수 있게 만듭니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1781164894576&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pragma once

#include &quot;CoreMinimal.h&quot;
#include &quot;GameFramework/Actor.h&quot;
#include &quot;ItemSpawnRow.h&quot;       // 우리가 정의한 구조체

#include &quot;SpawnVolume.generated.h&quot;

class UBoxComponent;

UCLASS()
class BC_CH3_ASSIGNMENT_5_API ASpawnVolume : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ASpawnVolume();
	
	UFUNCTION(BlueprintCallable, Category = &quot;Spawning&quot;)	
	AActor* SpawnRandomItem(); // 리턴 형식을 AActor* 로 변경
	
protected:
	
	//
	FItemSpawnRow* GetRandomItem() const;
	
	// === Components	
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=&quot;Spawning&quot;)
    USceneComponent* Scene;
    // 스폰 영역을 담당할 박스 컴포넌트
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=&quot;Spawning&quot;)
    UBoxComponent* SpawningBox;
	
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = &quot;Spawning&quot;)
	UDataTable* ItemDataTable;
	
	// === Functions
	
	// 특정 아이템 클래스를 스폰하는 함수
	UFUNCTION(BlueprintCallable, Category=&quot;Spawning&quot;)
	AActor* SpawnItem(TSubclassOf&amp;lt;AActor&amp;gt; ItemClass); // 리턴 형식을 AActor* 로 변경
	
	// 스폰 볼륨 내부에서 무작위 좌표를 얻어오는 함수
	UFUNCTION(BlueprintCallable, Category=&quot;Spawning&quot;)
	FVector GetRandomPointInVolume() const;	
	
	
};&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1781164906960&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;SpawnVolume.h&quot;
#include &quot;Components/BoxComponent.h&quot;
#include &quot;Engine/World.h&quot;
#include &quot;GameFramework/Actor.h&quot;

ASpawnVolume::ASpawnVolume()
{
	PrimaryActorTick.bCanEverTick = false;

	// 박스 컴포넌트를 생성하고, 이 액터의 루트로 설정
	Scene = CreateDefaultSubobject&amp;lt;USceneComponent&amp;gt;(TEXT(&quot;Scene&quot;));
	SetRootComponent(Scene);
    
	SpawningBox = CreateDefaultSubobject&amp;lt;UBoxComponent&amp;gt;(TEXT(&quot;SpawningBox&quot;));
	SpawningBox-&amp;gt;SetupAttachment(Scene);
}

AActor* ASpawnVolume::SpawnRandomItem()
{
	if (FItemSpawnRow* SelectedRow = GetRandomItem())
	{
		if (UClass* ActualClass = SelectedRow-&amp;gt;ItemClass.Get())
		{
			return SpawnItem(ActualClass);
		}
	}
	return nullptr;
} 

FVector ASpawnVolume::GetRandomPointInVolume() const
{
	// 1) 박스 컴포넌트의 스케일된 Extent, 즉 x/y/z 방향으로 반지름(절반 길이)을 구함
	FVector BoxExtent = SpawningBox-&amp;gt;GetScaledBoxExtent();
	// 2) 박스 중심 위치
	FVector BoxOrigin = SpawningBox-&amp;gt;GetComponentLocation();

	// 3) 각 축별로 -Extent ~ +Extent 범위의 무작위 값 생성
	return BoxOrigin + FVector(
		FMath::FRandRange(-BoxExtent.X, BoxExtent.X),
		FMath::FRandRange(-BoxExtent.Y, BoxExtent.Y),
		FMath::FRandRange(-BoxExtent.Z, BoxExtent.Z)
	);
}


FItemSpawnRow* ASpawnVolume::GetRandomItem() const
{
	if (!ItemDataTable) 
		return nullptr;

	
	// 1) 모든 Row(행) 가져오기
	TArray&amp;lt;FItemSpawnRow*&amp;gt; AllRows;
	static const FString ContextString(TEXT(&quot;ItemSpawnContext&quot;)); // 디버깅 용도
	ItemDataTable-&amp;gt;GetAllRows(ContextString, AllRows);

	if (AllRows.IsEmpty()) return nullptr; 

	// 2) 전체 확률 합 구하기
	float TotalChance = 0.0f; // 초기화
	for (const FItemSpawnRow* Row : AllRows) // AllRows 배열의 각 Row를 순회
	{
		if (Row) // Row가 유효한지 확인
		{
			TotalChance += Row-&amp;gt;SpawnChance; // SpawnChance 값을 TotalChance에 더하기
		}
	}

	// 3) 0 ~ TotalChance 사이 랜덤 값
	const float RandValue = FMath::FRandRange(0.0f, TotalChance);
	float AccumulateChance = 0.0f; // 랜덤 값 보정
	//Algo::Accumulate( AllRows, AccumulateChance)
	
	// 4) 누적 확률로 아이템 선택
	for (FItemSpawnRow* Row : AllRows)
	{
		AccumulateChance += Row-&amp;gt;SpawnChance;
		if (RandValue &amp;lt;= AccumulateChance)
		{
			return Row;
		}
	}

	return nullptr;
}

AActor* ASpawnVolume::SpawnItem(TSubclassOf&amp;lt;AActor&amp;gt; ItemClass)
{
	if (!ItemClass) return nullptr;

	// SpawnActor가 성공하면 스폰된 액터의 포인터가 반환됨
	AActor* SpawnedActor = GetWorld()-&amp;gt;SpawnActor&amp;lt;AActor&amp;gt;(
		ItemClass,
		GetRandomPointInVolume(),
		FRotator::ZeroRotator
	);
	
	return SpawnedActor;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3️⃣ &lt;b&gt;GameState 기반의 게임 루프 구현&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;게임 흐름 (3레벨, 각 레벨당 30초, 코인 모두 획득 시 즉시 다음 레벨로 이동, 3 레벨이 끝나면 Game Over)의 로직을 관리하도록 변경합니다.&lt;/li&gt;
&lt;li&gt;레벨 시작 시 40개 아이템을 소환하며, 그중 &lt;b&gt;코인&lt;/b&gt; 아이템이 몇 개 생성되었는지 추적(SpawnedCoinCount)하고, 플레이어가 먹은 코인 개수를 추적(CollectedCoinCount)하여 &amp;ldquo;모두 먹었다면&amp;rdquo; 즉시 레벨 종료합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;맵 전환 (OpenLevel) 시 주의&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UGameplayStatics::OpenLevel을 호출하면 &lt;b&gt;지금 월드가 언로드 (제거)&lt;/b&gt; 되고, &lt;b&gt;새로운 맵이 로드&lt;/b&gt;되면서 BeginPlay()가 다시 실행됩니다. 이때 GameState도 &lt;b&gt;새로 생성&lt;/b&gt;되기 때문에, 이전 레벨에서 유지하던 변수가 모두 초기화될 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;로직 함수&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;BeginPlay&lt;/b&gt;(): 게임 시작 시 &lt;b&gt;StartLevel&lt;/b&gt;() 호출&lt;/li&gt;
&lt;li&gt;&lt;b&gt;StartLevel&lt;/b&gt;():
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;코인 개수들 초기화(SpawnedCoinCount=0, CollectedCoinCount=0)&lt;/li&gt;
&lt;li&gt;스폰 볼륨들을 찾아서 40개 아이템 스폰(반복).
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약 SpawnRandomItem()이 ACoinItem을 반환하면 SpawnedCoinCount++&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;30초 타이머 설정 (OnLevelTimeUp 호출)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;UGameplayStatics::GetAllActorsOfClass&lt;/b&gt;(GetWorld(), ASpawnVolume::StaticClass(), FoundVolumes);
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GetAllActorsOfClass(): 현재 월드에서 이 액터에 해당되는 것들을 모두 가져오는 함수&lt;/li&gt;
&lt;li&gt;#include &quot;Kismet/GameplayStatics.h&quot; 추가 해줘야합니다&lt;/li&gt;
&lt;li&gt;TArray&amp;lt;AActor*&amp;gt;&amp;nbsp;FoundVolumes;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;IsA()&lt;/b&gt; : 해당 포인터가 찾는 게 맞는지 확인. (하위 클래스도 같이 확인해 줍니다)&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;OnLevelTimeUp&lt;/b&gt;(): 30초가 만료되면 레벨 종료(EndLevel())&lt;/li&gt;
&lt;li&gt;&lt;b&gt;OnCoinCollected&lt;/b&gt;(): 코인 아이템을 먹을 때마다 호출.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CollectedCoinCount++&lt;/li&gt;
&lt;li&gt;CollectedCoinCount &amp;gt;= SpawnedCoinCount 이면, 즉시 EndLevel()&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GetWorldTimerManager().ClearTimer:&amp;nbsp;&lt;/b&gt;타이머 초기화&lt;/li&gt;
&lt;li&gt;&lt;b&gt;EndLevel&lt;/b&gt;()
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;현재 레벨 타이머 정리&lt;/li&gt;
&lt;li&gt;CurrentLevelIndex++&lt;/li&gt;
&lt;li&gt;만약 CurrentLevelIndex &amp;gt;= MaxLevels 이면 OnGameOver()
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아니면 다음 레벨 StartLevel()&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;OnGameOver&lt;/b&gt;()
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GameOver 로그 출력 (혹은 UI 호출 등)&lt;/li&gt;
&lt;li&gt;추후 RestartGame 등 처리(블루프린트나 GameMode에서 구현)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1781167124262&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pragma once

#include &quot;CoreMinimal.h&quot;
#include &quot;GameFramework/GameState.h&quot;
#include &quot;MainGameState.generated.h&quot;


UCLASS()
class BC_CH3_ASSIGNMENT_5_API AMainGameState : public AGameState
{
	GENERATED_BODY()
	
public:
	AMainGameState();	
	
	virtual void BeginPlay() override;
	
	// === Variables ===
	// 전역 점수를 저장하는 변수
	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category=&quot;Score&quot;)
	int32 Score;

	// 현재 레벨에서 스폰된 코인 개수
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = &quot;Coin&quot;)
	int32 SpawnedCoinCount;
	// 플레이어가 수집한 코인 개수
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = &quot;Coin&quot;)
	int32 CollectedCoinCount;
	// 각 레벨이 유지되는 시간 (초 단위)
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = &quot;Level&quot;)
	float LevelDuration;
	// 현재 진행 중인 레벨 인덱스
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = &quot;Level&quot;)
	int32 CurrentLevelIndex;
	// 전체 레벨의 개수
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = &quot;Level&quot;)
	int32 MaxLevels;
	// 실제 레벨 맵 이름 배열. 여기 있는 인덱스를 차례대로 연동
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = &quot;Level&quot;)
	TArray&amp;lt;FName&amp;gt; LevelMapNames;
	
	// 매 레벨이 끝나기 전까지 시간이 흐르도록 관리하는 타이머
	FTimerHandle LevelTimerHandle;
	
	
	// === Func ===
	// 현재 점수를 읽는 함수
	UFUNCTION(BlueprintPure, Category=&quot;Score&quot;)
	int32 GetScore() const;
	
	// 점수를 추가해주는 함수
	UFUNCTION(BlueprintCallable, Category=&quot;Score&quot;)
	void AddScore(int32 Amount);
	
	UFUNCTION(BlueprintCallable, Category = &quot;Level&quot;)
	void OnGameOver();
	
	// 레벨을 시작할 때, 아이템 스폰 및 타이머 설정
	void StartLevel();
	// 레벨 제한 시간이 만료되었을 때 호출
	void OnLevelTimeUp();
	// 코인을 주웠을 때 호출
	void OnCoinCollected();
	// 레벨을 강제 종료하고 다음 레벨로 이동
	void EndLevel();
	
};&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1781167137667&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;MainGameState.h&quot;
#include &quot;Kismet/GameplayStatics.h&quot;
#include &quot;SpawnVolume.h&quot;
#include &quot;CoinItem.h&quot;

AMainGameState::AMainGameState()
{
	Score = 0;
	SpawnedCoinCount = 0;
	CollectedCoinCount = 0;
	LevelDuration = 30.0f; // 한 레벨당 30초
	CurrentLevelIndex = 0;
	MaxLevels = 3;
}

void AMainGameState::BeginPlay()
{
	Super::BeginPlay();
	
	// 게임 시작 시 첫 레벨부터 진행
	StartLevel();
}

int32 AMainGameState::GetScore() const
{
	return Score;
}

void AMainGameState::AddScore(int32 Amount)
{
	Score += Amount;
}


void AMainGameState::StartLevel()
{
		// 레벨 시작 시, 코인 개수 초기화
		SpawnedCoinCount = 0;
		CollectedCoinCount = 0;
	
		// 현재 맵에 배치된 모든 SpawnVolume을 찾아 아이템 40개를 스폰
		TArray&amp;lt;AActor*&amp;gt; FoundVolumes;
		UGameplayStatics::GetAllActorsOfClass(GetWorld(), ASpawnVolume::StaticClass(), FoundVolumes);
	
		const int32 ItemToSpawn = 40;
		
		for (int32 i = 0; i &amp;lt; ItemToSpawn; i++)
		{
				if (FoundVolumes.Num() &amp;gt; 0)
						{
						ASpawnVolume* SpawnVolume = Cast&amp;lt;ASpawnVolume&amp;gt;(FoundVolumes[0]);
						if (SpawnVolume)
						{
								AActor* SpawnedActor = SpawnVolume-&amp;gt;SpawnRandomItem();
								// 만약 스폰된 액터가 코인 타입이라면 SpawnedCoinCount 증가
								if (SpawnedActor &amp;amp;&amp;amp; SpawnedActor-&amp;gt;IsA(ACoinItem::StaticClass()))
								{
										SpawnedCoinCount++;
								}
						}				
				}
		}
	
		// 30초 후에 OnLevelTimeUp()가 호출되도록 타이머 설정
		GetWorldTimerManager().SetTimer(
			LevelTimerHandle,
			this,
			&amp;amp;AMainGameState::OnLevelTimeUp,
			LevelDuration,
			false
		);
	
		UE_LOG(LogTemp, Warning, TEXT(&quot;Level %d Start!, Spawned %d coin&quot;),
			CurrentLevelIndex + 1,
			SpawnedCoinCount);
}

void AMainGameState::OnLevelTimeUp()
{
		// 시간이 다 되면 레벨을 종료
		EndLevel();
}

void AMainGameState::OnCoinCollected()
{
		CollectedCoinCount++;
	
		UE_LOG(LogTemp, Warning, TEXT(&quot;Coin Collected: %d / %d&quot;), 
			CollectedCoinCount,
			SpawnedCoinCount)
	
		// 현재 레벨에서 스폰된 코인을 전부 주웠다면 즉시 레벨 종료
		if (SpawnedCoinCount &amp;gt; 0 &amp;amp;&amp;amp; CollectedCoinCount &amp;gt;= SpawnedCoinCount)
		{
				EndLevel();
		}
}

void AMainGameState::EndLevel()
{
		// 타이머 해제
		GetWorldTimerManager().ClearTimer(LevelTimerHandle);
		// 다음 레벨 인덱스로
		CurrentLevelIndex++;

		// 모든 레벨을 다 돌았다면 게임 오버 처리
		if (CurrentLevelIndex &amp;gt;= MaxLevels)
		{
				OnGameOver();
				return;
		}
		
		// 레벨 맵 이름이 있다면 해당 맵 불러오기
		if (LevelMapNames.IsValidIndex(CurrentLevelIndex))
		{			    
				UGameplayStatics::OpenLevel(GetWorld(), LevelMapNames[CurrentLevelIndex]);
		}
		else
		{
				// 맵 이름이 없으면 게임오버
				OnGameOver();
		}
}

void AMainGameState::OnGameOver()
{
		UE_LOG(LogTemp, Warning, TEXT(&quot;Game Over!!&quot;));
		// 여기서 UI를 띄운다거나, 재시작 기능을 넣을 수도 있음
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4️⃣ &lt;b&gt;코인 아이템 점수 획득 로직 수정&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CoinItem은 플레이어가 닿았을 때 (ActivateItem) 점수를 획득하고 자기 자신을 제거하는 구조입니다. 여기서 &lt;b&gt;추가로&lt;/b&gt; &amp;ldquo;코인을 하나 더 먹었다&amp;rdquo;라고 GameState에게 알려야 합니다&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781167219011&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;CoinItem.h&quot;
#include &quot;Engine/World.h&quot;
#include &quot;MainGameState.h&quot;

ACoinItem::ACoinItem()
{
	// 부모클래스라 안해도 되지만 
	// 점수 기본값을 0으로 설정
	PointValue = 0;
	ItemType = &quot;DefaultCoin&quot;;
}

void ACoinItem::ActivateItem(AActor* Activator)
{
	// 플레이어 태그 확인
	if (Activator &amp;amp;&amp;amp; Activator-&amp;gt;ActorHasTag(&quot;Player&quot;))
	{
		// 점수 획득 디버그 메시지
		GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, 
			FString::Printf(TEXT(&quot;Player Gained %i Points!&quot;), PointValue));
        	
		
		if (UWorld* World = GetWorld())
		{
			if (AMainGameState* GameState = World-&amp;gt;GetGameState&amp;lt;AMainGameState&amp;gt;())
			{
				GameState-&amp;gt;AddScore(PointValue);
				GameState-&amp;gt;OnCoinCollected();
			}
		}
		
		// 부모 클래스 (BaseItem)에 정의된 아이템 파괴 함수 호출
		DestroyItem();
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a4&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;Game Instance를 활용한 데이터 유지하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BP_MainGameState의 Level Map Names Setting.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1225&quot; data-origin-height=&quot;492&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGkuLO/dJMcaglvI5K/ejIlU5vs9yfMxtKB3Oa48K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGkuLO/dJMcaglvI5K/ejIlU5vs9yfMxtKB3Oa48K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGkuLO/dJMcaglvI5K/ejIlU5vs9yfMxtKB3Oa48K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGkuLO%2FdJMcaglvI5K%2FejIlU5vs9yfMxtKB3Oa48K%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;1225&quot; height=&quot;492&quot; data-origin-width=&quot;1225&quot; data-origin-height=&quot;492&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&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;372&quot; data-origin-height=&quot;222&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cAuPq4/dJMcaiDEDBK/RPDHTNpQPzqunQSx5JhrDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cAuPq4/dJMcaiDEDBK/RPDHTNpQPzqunQSx5JhrDk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cAuPq4/dJMcaiDEDBK/RPDHTNpQPzqunQSx5JhrDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcAuPq4%2FdJMcaiDEDBK%2FRPDHTNpQPzqunQSx5JhrDk%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;372&quot; height=&quot;222&quot; data-origin-width=&quot;372&quot; data-origin-height=&quot;222&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Proejct -Maps &amp;amp; Modes 세팅에서 Game State Class를 BP_MainGameState 로 설정해 줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;716&quot; data-origin-height=&quot;387&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brPMq9/dJMcabEvBP9/IZrithKLTUUlB9wQG886Jk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brPMq9/dJMcabEvBP9/IZrithKLTUUlB9wQG886Jk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brPMq9/dJMcabEvBP9/IZrithKLTUUlB9wQG886Jk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrPMq9%2FdJMcabEvBP9%2FIZrithKLTUUlB9wQG886Jk%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;716&quot; height=&quot;387&quot; data-origin-width=&quot;716&quot; data-origin-height=&quot;387&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;현재 게임은 Level이 전환될 때마다 GameState 가 새로 만들어져서 Variable 들의 정보가 다 초기화됩니다 (Score, CurrentLevelIndex 등등) 그래서 유지해야 하는 데이터들을 저장하기 위한 작업을 해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣ &lt;b&gt;Game Instance란?&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;레벨 전환&lt;/b&gt; 시에는 &lt;b&gt;GameState&lt;/b&gt;, &lt;b&gt;GameMode&lt;/b&gt; 같은 기본 클래스를 비롯해, 맵 내에서 생성된 대부분의 객체가 &lt;b&gt;처음부터 다시 생성&lt;/b&gt;됩니다.&lt;/li&gt;
&lt;li&gt;하지만 어떤 경우에는 &amp;ldquo;이전 레벨에서 획득한 점수나 플레이어 상태&amp;rdquo; 등을 &lt;b&gt;모든 레벨에 걸쳐 유지&lt;/b&gt;하고 싶을 수 있습니다. 이를 위해서는 보통 두 가지 방법을 활용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Game Instance&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로젝트가 시작될 때 (에디터에서 게임 실행을 누른 시점)부터 애플리케이션이 완전히 종료될 때까지 &lt;b&gt;유일하게 계속 살아있는 객체&lt;/b&gt;입니다.&lt;/li&gt;
&lt;li&gt;마치 Singleton과 비슷하다.&lt;/li&gt;
&lt;li&gt;맵이 전환되어도 &lt;b&gt;파괴되지 않으므로&lt;/b&gt;, 여기서 전역 데이터를 유지할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Seamless Travel&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;멀티플레이 환경에서 주로 사용되는 레벨 전환 방식으로, GameState/PlayerController 등을 &lt;b&gt;파괴하지 않고&lt;/b&gt; 그대로 다음 맵으로 넘어가는 기능입니다.&lt;/li&gt;
&lt;li&gt;Seamless Travel을 사용하면 대부분의 객체를 유지할 수 있지만, 설정과 로직이 조금 더 복잡하므로, 싱글 플레이 전용 간단 프로젝트라면 GameInstance를 사용하기가 쉽습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; Game Instance Subsystem&lt;/b&gt; 이란 것 또한 많이 사용하는데 이것은 추후에 더 알아보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;781&quot; data-origin-height=&quot;560&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cF9MG3/dJMcacpVNIo/SwTEWR2hNJww2924pTjKVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cF9MG3/dJMcacpVNIo/SwTEWR2hNJww2924pTjKVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cF9MG3/dJMcacpVNIo/SwTEWR2hNJww2924pTjKVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcF9MG3%2FdJMcacpVNIo%2FSwTEWR2hNJww2924pTjKVk%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;781&quot; height=&quot;560&quot; data-origin-width=&quot;781&quot; data-origin-height=&quot;560&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;924&quot; data-origin-height=&quot;554&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0YtDF/dJMcaijlv7Z/JiYJy823YYQSIPsTdKtMOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0YtDF/dJMcaijlv7Z/JiYJy823YYQSIPsTdKtMOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0YtDF/dJMcaijlv7Z/JiYJy823YYQSIPsTdKtMOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0YtDF%2FdJMcaijlv7Z%2FJiYJy823YYQSIPsTdKtMOk%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;924&quot; height=&quot;554&quot; data-origin-width=&quot;924&quot; data-origin-height=&quot;554&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;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&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;h2 data-ke-size=&quot;size26&quot;&gt;2️⃣ &lt;b&gt;Game Instance 생성 및 변수 선언&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1781173392468&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pragma once

#include &quot;CoreMinimal.h&quot;
#include &quot;Engine/GameInstance.h&quot;
#include &quot;MainGameInstance.generated.h&quot;

UCLASS()
class BC_CH3_ASSIGNMENT_5_API UMainGameInstance : public UGameInstance
{
	GENERATED_BODY()
	
public:
	UMainGameInstance();
	
	// 게임 전체 누적 점수
	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = &quot;GameData&quot;)
	int32 TotalScore;
	// 현재 레벨 인덱스 (GameState에서도 관리할 수 있지만, 맵 전환 후에도 살리고 싶다면 GameInstance에 복제할 수 있음)
	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = &quot;GameData&quot;)
	int32 CurrentLevelIndex;
	
	UFUNCTION(BlueprintCallable, Category = &quot;GameData&quot;)
	void AddToScore(int32 Amount);
	
};&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1781173403805&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;MainGameInstance.h&quot;

UMainGameInstance::UMainGameInstance()
{
	TotalScore = 0;
	CurrentLevelIndex = 0;
}

void UMainGameInstance::AddToScore(int32 Amount)
{
	TotalScore += Amount;
	UE_LOG(LogTemp, Warning, TEXT(&quot;Total Score Updated: %d&quot;), TotalScore);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Update 된 MainGameState.cpp&lt;/p&gt;
&lt;pre id=&quot;code_1781174077468&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;MainGameState.h&quot;
#include &quot;MainGameInstance.h&quot;
#include &quot;Kismet/GameplayStatics.h&quot;
#include &quot;SpawnVolume.h&quot;
#include &quot;CoinItem.h&quot;

AMainGameState::AMainGameState()
{
	Score = 0;
	SpawnedCoinCount = 0;
	CollectedCoinCount = 0;
	LevelDuration = 30.0f; // 한 레벨당 30초
	CurrentLevelIndex = 0;
	MaxLevels = 3;
}

void AMainGameState::BeginPlay()
{
	Super::BeginPlay();

	// 게임 시작 시 첫 레벨부터 진행
	StartLevel();
}

int32 AMainGameState::GetScore() const
{
	return Score;
}

void AMainGameState::AddScore(int32 Amount)
{
	if (UGameInstance* GameInstance = GetGameInstance())
	{
		UMainGameInstance* MainGameInstance = Cast&amp;lt;UMainGameInstance&amp;gt;(GameInstance);
		if (MainGameInstance)
		{
			MainGameInstance-&amp;gt;AddToScore(Amount);
		}
	}
}


void AMainGameState::StartLevel()
{
	if (UGameInstance* GameInstance = GetGameInstance())
	{
		UMainGameInstance* MainGameInstance = Cast&amp;lt;UMainGameInstance&amp;gt;(GameInstance);
		if (MainGameInstance)
		{
			CurrentLevelIndex = MainGameInstance-&amp;gt;CurrentLevelIndex;
		}
	}

	// 레벨 시작 시, 코인 개수 초기화
	SpawnedCoinCount = 0;
	CollectedCoinCount = 0;
	// 현재 맵에 배치된 모든 SpawnVolume을 찾아 아이템 40개를 스폰
	TArray&amp;lt;AActor*&amp;gt; FoundVolumes;
	UGameplayStatics::GetAllActorsOfClass(GetWorld(), ASpawnVolume::StaticClass(), FoundVolumes);
	const int32 ItemToSpawn = 40;

	for (int32 i = 0; i &amp;lt; ItemToSpawn; i++)
	{
		if (FoundVolumes.Num() &amp;gt; 0)
		{
			ASpawnVolume* SpawnVolume = Cast&amp;lt;ASpawnVolume&amp;gt;(FoundVolumes[0]);
			if (SpawnVolume)
			{
				AActor* SpawnedActor = SpawnVolume-&amp;gt;SpawnRandomItem();
				// 만약 스폰된 액터가 코인 타입이라면 SpawnedCoinCount 증가
				if (SpawnedActor &amp;amp;&amp;amp; SpawnedActor-&amp;gt;IsA(ACoinItem::StaticClass()))
				{
					SpawnedCoinCount++;
				}
			}
		}
	}
	// 30초 후에 OnLevelTimeUp()가 호출되도록 타이머 설정
	GetWorldTimerManager().SetTimer(
		LevelTimerHandle,
		this,
		&amp;amp;AMainGameState::OnLevelTimeUp,
		LevelDuration,
		false
	);
	UE_LOG(LogTemp, Warning, TEXT(&quot;Level %d Start!, Spawned %d coin&quot;),
	       CurrentLevelIndex + 1,
	       SpawnedCoinCount);
}

void AMainGameState::OnLevelTimeUp()
{
	// 시간이 다 되면 레벨을 종료
	EndLevel();
}

void AMainGameState::OnCoinCollected()
{
	CollectedCoinCount++;

	UE_LOG(LogTemp, Warning, TEXT(&quot;Coin Collected: %d / %d&quot;),
	       CollectedCoinCount,
	       SpawnedCoinCount)

	// 현재 레벨에서 스폰된 코인을 전부 주웠다면 즉시 레벨 종료
	if (SpawnedCoinCount &amp;gt; 0 &amp;amp;&amp;amp; CollectedCoinCount &amp;gt;= SpawnedCoinCount)
	{
		EndLevel();
	}
}

void AMainGameState::EndLevel()
{	
	
	// 타이머 해제
	GetWorldTimerManager().ClearTimer(LevelTimerHandle);
	// 다음 레벨 인덱스로
	//CurrentLevelIndex++;
	
	if (UGameInstance* GameInstance = GetGameInstance())
	{
		UMainGameInstance* MainGameInstance = Cast&amp;lt;UMainGameInstance&amp;gt;(GameInstance);
		if (MainGameInstance)
		{
			AddScore(Score);
			CurrentLevelIndex++;
			MainGameInstance-&amp;gt;CurrentLevelIndex = CurrentLevelIndex;
		}
	}

	// 모든 레벨을 다 돌았다면 게임 오버 처리
	if (CurrentLevelIndex &amp;gt;= MaxLevels)
	{
		OnGameOver();
		return;
	}

	// 레벨 맵 이름이 있다면 해당 맵 불러오기
	if (LevelMapNames.IsValidIndex(CurrentLevelIndex))
	{
		UGameplayStatics::OpenLevel(GetWorld(), LevelMapNames[CurrentLevelIndex]);
	}
	else
	{
		// 맵 이름이 없으면 게임오버
		OnGameOver();
	}
}

void AMainGameState::OnGameOver()
{
	UE_LOG(LogTemp, Warning, TEXT(&quot;Game Over!!&quot;));
	// 여기서 UI를 띄운다거나, 재시작 기능을 넣을 수도 있음
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 세팅 안에 Game Instance 도 변경해줘야 합니다. 그전에 BP_MainGmaeInstace 도 만들고 설정하겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;401&quot; data-origin-height=&quot;499&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxTRX6/dJMcagZ5Ceo/6ePWOwX9rwDnrd0Lm4hTHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxTRX6/dJMcagZ5Ceo/6ePWOwX9rwDnrd0Lm4hTHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxTRX6/dJMcagZ5Ceo/6ePWOwX9rwDnrd0Lm4hTHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxTRX6%2FdJMcagZ5Ceo%2F6ePWOwX9rwDnrd0Lm4hTHk%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;401&quot; height=&quot;499&quot; data-origin-width=&quot;401&quot; data-origin-height=&quot;499&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;1167&quot; data-origin-height=&quot;827&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/46kfc/dJMcahEHyrc/GjKVewmk5BzriqgfcLBAG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/46kfc/dJMcahEHyrc/GjKVewmk5BzriqgfcLBAG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/46kfc/dJMcahEHyrc/GjKVewmk5BzriqgfcLBAG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F46kfc%2FdJMcahEHyrc%2FGjKVewmk5BzriqgfcLBAG1%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;1167&quot; height=&quot;827&quot; data-origin-width=&quot;1167&quot; data-origin-height=&quot;827&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3️⃣ &lt;b&gt;전체 게임 루프 요약&lt;/b&gt;&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;게임 실행&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GameInstance 생성, GameMode/GameState 생성, 첫 레벨 로드&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;BeginPlay()&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ASpartaGameState::BeginPlay() &amp;rarr; StartLevel()&lt;/li&gt;
&lt;li&gt;스폰 볼륨(SpawnVolume)에서 &lt;b&gt;40개 아이템&lt;/b&gt; 스폰&lt;/li&gt;
&lt;li&gt;코인 개수 추적(SpawnedCoinCount)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;30초 타이머&lt;/b&gt; 시작&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;플레이어가 코인 획득&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CoinItem::ActivateItem()에서 GameState-&amp;gt;AddScore(), OnCoinCollected()&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모든 코인&lt;/b&gt;을 모으면 즉시 EndLevel()&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;레벨 종료&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;EndLevel()에서 CurrentLevelIndex++&lt;/li&gt;
&lt;li&gt;남은 레벨이 있으면 UGameplayStatics::OpenLevel(...)로 &lt;b&gt;다음 맵 로드&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;더 이상 레벨이 없으면 OnGameOver()&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다음 맵 로드&lt;/b&gt; 시
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;새로운 GameState&lt;/b&gt;가 생성 &amp;rarr; 다시 BeginPlay() &amp;rarr; StartLevel()&lt;/li&gt;
&lt;li&gt;이전 레벨에서 유지하고 싶은 정보는 GameInstance나 &amp;ldquo;Seamless Travel&amp;rdquo; 등을 통해 별도로 관리해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Game Over&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로그 출력 (추후 UI 표시로 전환)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&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;h3 style=&quot;padding: 0.3em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #5b63fb; font-weight: bold; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;추천&lt;/span&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/107&quot;&gt;[Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781164243473&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;인터페이스 기반 아이템 클래스 설계하기 인터페이스 이해하기1️⃣ 인터페이스란?인터페이스 (Interface)란 클래스 (또는 오브젝트)가 반드시 구현해야 할 함수 목록만을 미리 정의해 두고, 실제 &quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/107&quot; data-og-url=&quot;https://devcol.tistory.com/107&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/sA9RM/dJMb9frNEV7/mqumL986okRdsyJE9ASHo1/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/biAScA/dJMb9gxtHkU/Yh7zNXgwmwbeJInju0dqf1/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/ApySg/dJMb87geO5s/dnf4JtgjnftSvuuZiKWhhK/img.png?width=997&amp;amp;height=544&amp;amp;face=0_0_997_544&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/107&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/107&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/sA9RM/dJMb9frNEV7/mqumL986okRdsyJE9ASHo1/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/biAScA/dJMb9gxtHkU/Yh7zNXgwmwbeJInju0dqf1/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/ApySg/dJMb87geO5s/dnf4JtgjnftSvuuZiKWhhK/img.png?width=997&amp;amp;height=544&amp;amp;face=0_0_997_544');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스 기반 아이템 클래스 설계하기 인터페이스 이해하기1️⃣ 인터페이스란?인터페이스 (Interface)란 클래스 (또는 오브젝트)가 반드시 구현해야 할 함수 목록만을 미리 정의해 두고, 실제&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/108&quot;&gt;[Unreal Engine/UE 기초] - 충돌 이벤트로 획득되는 아이템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781164252282&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;충돌 이벤트로 획득되는 아이템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;충돌 이벤트로 획득되는 아이템 구현하기 이전 포스팅에서는 클래스 구조만 짜고 로직은 비여있던 상태.이전 포스팅: [Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼 &quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/108&quot; data-og-url=&quot;https://devcol.tistory.com/108&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/jmWjD/dJMb82MLsPp/7QMxGqRnfqAFCn6p5k8tkk/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/JFK5Z/dJMb81G5Lvh/TXhxaBoI1kuEALcXwK5ByK/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/bHB478/dJMb9g5jhTi/zCDS1GY8Z9i42g4dal6kB0/img.png?width=1596&amp;amp;height=489&amp;amp;face=0_0_1596_489&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/108&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/108&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/jmWjD/dJMb82MLsPp/7QMxGqRnfqAFCn6p5k8tkk/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/JFK5Z/dJMb81G5Lvh/TXhxaBoI1kuEALcXwK5ByK/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/bHB478/dJMb9g5jhTi/zCDS1GY8Z9i42g4dal6kB0/img.png?width=1596&amp;amp;height=489&amp;amp;face=0_0_1596_489');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;충돌 이벤트로 획득되는 아이템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;충돌 이벤트로 획득되는 아이템 구현하기 이전 포스팅에서는 클래스 구조만 짜고 로직은 비여있던 상태.이전 포스팅: [Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/109&quot;&gt;[Unreal Engine/UE 기초] - 아이템 스폰 및 레벨 데이터 관리하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781164253622&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;아이템 스폰 및 레벨 데이터 관리하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;아이템 스폰 및 레벨 데이터 관리하기 랜덤 위치에 아이템 스폰하기 1️⃣ 레벨 셋팅하기Resources 폴더에 Maps 폴더에는 3개의 레벨이 이미 존재합니다. 각각 난이도에 따라서 크기가 다른 맵이고, &quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/109&quot; data-og-url=&quot;https://devcol.tistory.com/109&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cLGxfm/dJMb8Yp3Jgs/XodaPA7Bq8Q2bwJcaYrOk1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/b3TL4M/dJMb81f0W7R/XxH3bkz7XP3Dxcl22AJkU1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/c4oxJD/dJMb89ylWzD/GSEuPUkAww5SFszPpPhOs1/img.png?width=940&amp;amp;height=571&amp;amp;face=0_0_940_571&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/109&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/109&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cLGxfm/dJMb8Yp3Jgs/XodaPA7Bq8Q2bwJcaYrOk1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/b3TL4M/dJMb81f0W7R/XxH3bkz7XP3Dxcl22AJkU1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/c4oxJD/dJMb89ylWzD/GSEuPUkAww5SFszPpPhOs1/img.png?width=940&amp;amp;height=571&amp;amp;face=0_0_940_571');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;아이템 스폰 및 레벨 데이터 관리하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;아이템 스폰 및 레벨 데이터 관리하기 랜덤 위치에 아이템 스폰하기 1️⃣ 레벨 셋팅하기Resources 폴더에 Maps 폴더에는 3개의 레벨이 이미 존재합니다. 각각 난이도에 따라서 크기가 다른 맵이고,&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/110&quot;&gt;[Unreal Engine/UE 기초] - 캐릭터 체력 및 점수 관리 시스템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781164255422&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;캐릭터 체력 및 점수 관리 시스템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;캐릭터 체력 및 점수 관리 시스템 구현하기 캐릭터 체력 시스템 구현하기 1️⃣ 캐릭터 클래스에 체력 변수 및 함수 선언PlayerState를 쓰지 않는 이유PlayerState: 각 플레이어마다의 어떤 정보를 관&quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/110&quot; data-og-url=&quot;https://devcol.tistory.com/110&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bYqXoH/dJMb8WMxYMp/5mzpC6c0dk8y31rndJrJuK/img.png?width=773&amp;amp;height=359&amp;amp;face=0_0_773_359,https://scrap.kakaocdn.net/dn/ectDw4/dJMb9gxtHk0/ZVLADkGrrgLpKlXy7MKsi0/img.png?width=773&amp;amp;height=359&amp;amp;face=0_0_773_359,https://scrap.kakaocdn.net/dn/bEAEtk/dJMb8SpQkZA/PbM36SDF25VGpi0p9ZsKz1/img.png?width=915&amp;amp;height=558&amp;amp;face=0_0_915_558&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/110&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/110&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bYqXoH/dJMb8WMxYMp/5mzpC6c0dk8y31rndJrJuK/img.png?width=773&amp;amp;height=359&amp;amp;face=0_0_773_359,https://scrap.kakaocdn.net/dn/ectDw4/dJMb9gxtHk0/ZVLADkGrrgLpKlXy7MKsi0/img.png?width=773&amp;amp;height=359&amp;amp;face=0_0_773_359,https://scrap.kakaocdn.net/dn/bEAEtk/dJMb8SpQkZA/PbM36SDF25VGpi0p9ZsKz1/img.png?width=915&amp;amp;height=558&amp;amp;face=0_0_915_558');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;캐릭터 체력 및 점수 관리 시스템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;캐릭터 체력 및 점수 관리 시스템 구현하기 캐릭터 체력 시스템 구현하기 1️⃣ 캐릭터 클래스에 체력 변수 및 함수 선언PlayerState를 쓰지 않는 이유PlayerState: 각 플레이어마다의 어떤 정보를 관&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/pages/Unreal-Engine-%EC%96%B8%EB%A6%AC%EC%96%BC-%EC%97%94%EC%A7%84&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;[페이지] Unreal Engine | 언리얼 엔진&lt;/b&gt;&lt;/a&gt;&lt;/h4&gt;</description>
      <category>Unreal Engine/UE 기초</category>
      <category>C++</category>
      <category>Devlog</category>
      <category>Programming</category>
      <category>UE</category>
      <category>UE5</category>
      <category>Unreal engine</category>
      <category>게임 개발</category>
      <category>기초</category>
      <category>언리얼 엔진</category>
      <category>프로그래밍</category>
      <author>DevCol</author>
      <guid isPermaLink="true">https://devcol.tistory.com/111</guid>
      <comments>https://devcol.tistory.com/111#entry111comment</comments>
      <pubDate>Thu, 11 Jun 2026 19:54:04 +0900</pubDate>
    </item>
    <item>
      <title>캐릭터 체력 및 점수 관리 시스템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]</title>
      <link>https://devcol.tistory.com/110</link>
      <description>&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;캐릭터 체력 및 점수 관리 시스템 구현하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a1&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;캐릭터 체력 시스템 구현하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣ &lt;b&gt;캐릭터 클래스에 체력 변수 및 함수 선언&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;PlayerState를 쓰지 않는 이유&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PlayerState: 각 플레이어마다의 어떤 정보를 관리해주는 클래스&amp;nbsp;&lt;/li&gt;
&lt;li&gt;언리얼 엔진에서 &lt;b&gt;PlayerState&lt;/b&gt;는 주로 멀티플레이 환경에서 각 플레이어 간 &lt;b&gt;데이터 동기화&lt;/b&gt;를 위해 사용합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어, 점수나 킬/데스 카운트처럼 &lt;b&gt;서버와 클라이언트 모두가 공통으로 확인해야 하는 정보&lt;/b&gt;를 저장하죠.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;하지만 &lt;b&gt;싱글 플레이 게임&lt;/b&gt;에서는 이런 동기화가 필요 없으므로, 캐릭터 클래스자체에 체력이나 스코어 변수를 넣어 관리해도 충분합니다.&lt;/li&gt;
&lt;li&gt;그럼에도 추후 확장성 생각하면 &lt;b&gt;PlayerState&lt;/b&gt;&amp;nbsp;가 더 좋을 수 있지만 우선은 이렇게 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;캐릭터 클래스에 체력 관리 로직 추가&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;MaxHealth&lt;/b&gt;: 캐릭터의 &lt;b&gt;최대 체력&lt;/b&gt;을 나타냅니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Health&lt;/b&gt;: 캐릭터의 &lt;b&gt;현재 체력&lt;/b&gt;을 나타냅니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;TakeDamage()&lt;/b&gt;: 데미지를 받았을 때 호출되는 함수로, 내부에서 체력을 감소시키는 로직을 처리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;AddHealth()&lt;/b&gt;: 아이템 등을 통해 체력을 회복할 때 호출하는 함수로, 내부에서 체력을 회복시킵니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;OnDeath()&lt;/b&gt;: 체력이 0 이하가 되었을 때 호출되는 사망 처리 함수입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(BlueprintPure: Get함수 사용시 주로 사용됩니다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2️⃣ &lt;b&gt;데미지 및 회복 처리&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;언리얼 엔진에는 &lt;b&gt;데미지 시스템&lt;/b&gt;을 간편히 사용할 수 있는 &lt;b&gt;UGameplayStatics::ApplyDamage&lt;/b&gt;(데미지 발생)와 &lt;b&gt;AActor::TakeDamage&lt;/b&gt;(데미지 처리) 함수가 제공됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데미지 처리 흐름 (ApplyDamage &amp;rarr; TakeDamage)&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;UGameplayStatics::ApplyDamage&lt;/b&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;내부적으로 대상 액터의 TakeDamage() 함수를 호출하려 시도합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;AActor::TakeDamage&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Actor&lt;/b&gt;의 가상 함수입니다. 모든 액터가 기본적으로 이 함수를 가지고 있으며, 필요하다면 자식 클래스(캐릭터 등)에서 &lt;b&gt;오버라이드&lt;/b&gt;할 수 있습니다.&lt;/li&gt;
&lt;li&gt;실제로 체력 감소 또는 특수한 데미지 처리 로직을 이 안에서 구현하게 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;AddHealth(float Amount)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;체력을 일정 양만큼 &lt;b&gt;회복&lt;/b&gt;합니다.&lt;/li&gt;
&lt;li&gt;FMath::Clamp를 통해 &lt;b&gt;최대 체력&lt;/b&gt;을 초과하지 않도록 제한합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;TakeDamage(...)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;언리얼 엔진의 기본 데미지 시스템&lt;/b&gt;을 사용하는 대표적인 함수입니다.&lt;/li&gt;
&lt;li&gt;DamageAmount: 데미지 값&lt;/li&gt;
&lt;li&gt;EventInstigator: 데미지를 유발한 주체(Controller)&lt;/li&gt;
&lt;li&gt;DamageCauser: 데미지를 직접 발생시킨 오브젝트(총알, 폭발물 등)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;반환값&lt;/b&gt;: 실제 적용된 데미지(기본 로직에서는 DamageAmount와 동일한 경우가 많지만, 게임 상황에 따라 감소 또는 증폭 등을 처리할 수도 있습니다.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;OnDeath()&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;체력이 0 이하로 떨어졌을 때 &lt;b&gt;사망 로직&lt;/b&gt;을 처리하는 함수입니다.&lt;/li&gt;
&lt;li&gt;흔히 &lt;b&gt;입력 비활성화&lt;/b&gt;, &lt;b&gt;Ragdoll 적용&lt;/b&gt;, &lt;b&gt;사망 애니메이션 재생&lt;/b&gt; 등을 수행합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MainCharacter.h&lt;/p&gt;
&lt;pre id=&quot;code_1781161379889&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pragma once

#include &quot;CoreMinimal.h&quot;
#include &quot;GameFramework/Character.h&quot;
#include &quot;MainCharacter.generated.h&quot;

// 미리 선언
// 전방 선언(Forward Declaration) 
class USpringArmComponent; // 스프링 암 관련 클래스 헤더
class UCameraComponent; // 카메라 관련 클래스 전방 선언


// Enhanced Input에서 액션 값을 받을 때 사용하는 구조체
struct FInputActionValue;

UCLASS()
class BC_CH3_ASSIGNMENT_5_API AMainCharacter : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	AMainCharacter();
	
	
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = &quot;Camera&quot;)
	USpringArmComponent* SpringArmComp  = nullptr;
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = &quot;Camera&quot;)
	UCameraComponent* CameraComp = nullptr;
	
	// 현재 체력을 가져오는 함수
	UFUNCTION(BlueprintPure, Category = &quot;Health&quot;)
	float GetHealth() const;
		
	// 체력을 회복시키는 함수
	UFUNCTION(BlueprintCallable, Category = &quot;Health&quot;)
	void AddHealth(float Amount);
	
protected:
	
	// === Variables ===
	// 최대 체력
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Health&quot;)
	float  MaxHealth;
	// 현재 체력
	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = &quot;Health&quot;)
	float  Health;
	
	// = Movements
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Movement&quot;)
	float NormalSpeed; // 기본 걷기 속도
	
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Movement&quot;)
	float SprintSpeedMultiplier;  // &quot;기본 속도&quot; 대비 몇 배로 빠르게 달릴지
	
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = &quot;Movement&quot;)
	float SprintSpeed; 	// 실제 스프린트 속도 SprintSpeed= NormalSpeed * SprintSpeedMultiplier
	
	
	// =====	
	
	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;	
	
	UFUNCTION()
	void Move(const FInputActionValue&amp;amp; value);
	
	UFUNCTION()
	void Look(const FInputActionValue&amp;amp; value);
	
	// on off 의 형태의 것들은 그냥 나눠 주는 것이 좋다
	// 왜냐하면 이전에는 세세하게 처리하기가 상당이 까다로웠는데
	// EnhancedInputSystem은 그것들을 매우 편하게 변경해주었기 때문에 왠만하면 나눠 주는 것이 좋다
	UFUNCTION()
	void StartJump(const FInputActionValue&amp;amp; value);
	UFUNCTION()
	void StopJump(const FInputActionValue&amp;amp; value);
	
	UFUNCTION()
	void StartSprint(const FInputActionValue&amp;amp; value);
	UFUNCTION()
	void StopSprint(const FInputActionValue&amp;amp; value);
	
	
	// 사망 처리 함수 (체력이 0 이하가 되었을 때 호출)
	UFUNCTION(BlueprintCallable, Category = &quot;Health&quot;)
	virtual void OnDeath();

	// 데미지 처리 함수 - 외부로부터 데미지를 받을 때 호출됨
	// 또는 AActor의 TakeDamage()를 오버라이드
	virtual float TakeDamage(
		float DamageAmount,
		struct FDamageEvent const&amp;amp; DamageEvent, // Damage 관련 추가 정보 (예: Skill 속성에 따른 반응) 
		AController* EventInstigator, //데미지를 발생 시킨 주체
		AActor* DamageCauser // 데미지를 일으킨 오브젝트
		) override;
	
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MainCharacter.cpp&lt;/p&gt;
&lt;pre id=&quot;code_1781161569394&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;MainCharacter.h&quot;
#include &quot;EnhancedInputComponent.h&quot;
//#include &quot;InputActionValue.h&quot;
#include &quot;MainPlayerController.h&quot;

// 카메라, 스프링 암 실제 구현이 필요한 경우라서 include
// 전방 선언(Forward Declaration) 한것 여기서 (실질적으로 사용하는곳) 포함
#include &quot;Camera/CameraComponent.h&quot;
#include &quot;GameFramework/SpringArmComponent.h&quot; 

//
#include &quot;GameFramework/CharacterMovementComponent.h&quot; // GetCharacterMovement() 사용을 위해
#include &quot;GameFramework/Actor.h&quot;
#include &quot;Kismet/GameplayStatics.h&quot;

AMainCharacter::AMainCharacter()
{ 	
	PrimaryActorTick.bCanEverTick = false;	
	
	// (1) 스프링 암 생성
	SpringArmComp = CreateDefaultSubobject&amp;lt;USpringArmComponent&amp;gt;(TEXT(&quot;SpringArm&quot;));
	// 스프링 암을 루트 컴포넌트 (CapsuleComponent)에 부착
	SpringArmComp-&amp;gt;SetupAttachment(RootComponent);
	// 캐릭터와 카메라 사이의 거리 기본값 300으로 설정
	SpringArmComp-&amp;gt;TargetArmLength = 300.0f;  
	// 컨트롤러 회전에 따라 스프링 암도 회전하도록 설정
	SpringArmComp-&amp;gt;bUsePawnControlRotation = true;  
	
	
	//

	// (2) 카메라 컴포넌트 생성
	CameraComp = CreateDefaultSubobject&amp;lt;UCameraComponent&amp;gt;(TEXT(&quot;Camera&quot;));
	// 스프링 암의 소켓 위치에 카메라를 부착
	CameraComp-&amp;gt;SetupAttachment(SpringArmComp, USpringArmComponent::SocketName);
	// 카메라는 스프링 암의 회전을 따르므로 PawnControlRotation은 꺼둠
	CameraComp-&amp;gt;bUsePawnControlRotation = false;
	
	// Movements &amp;amp; Sprint Speed
	
	NormalSpeed = 600.0f;
	SprintSpeedMultiplier = 1.75f;
	SprintSpeed = NormalSpeed * SprintSpeedMultiplier;

	
	// #include &quot;GameFramework/CharacterMovementComponent.h&quot; 추가해야함
	// MaxWalkSpeed 변경시 캐릭터 이동속도가 즉시 변경
	GetCharacterMovement()-&amp;gt;MaxWalkSpeed = NormalSpeed;
	
	
	// 초기 체력 설정
	MaxHealth = 100.0f;
	Health = MaxHealth;
}


// Called to bind functionality to input
void AMainCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
	// Enhanced InputComponent로 캐스팅
    if (UEnhancedInputComponent* EnhancedInput = Cast&amp;lt;UEnhancedInputComponent&amp;gt;(PlayerInputComponent))
    {
        // IA를 가져오기 위해 현재 소유 중인 Controller를 AMainPlayerController로 캐스팅
        if (AMainPlayerController* PlayerController = Cast&amp;lt;AMainPlayerController&amp;gt;(GetController()))
        {
        	// null check
            if (PlayerController-&amp;gt;MoveAction)
            {
                // IA_Move 액션 키를 &quot;키를 누르고 있는 동안&quot; Move() 호출
                EnhancedInput-&amp;gt;BindAction(
                    PlayerController-&amp;gt;MoveAction,
                    ETriggerEvent::Triggered,
                    this,
                    &amp;amp;AMainCharacter::Move
                );
            }
            
            if (PlayerController-&amp;gt;JumpAction)
            {
                // IA_Jump 액션 키를 &quot;키를 누르고 있는 동안&quot; StartJump() 호출
                EnhancedInput-&amp;gt;BindAction(
                    PlayerController-&amp;gt;JumpAction,
                    ETriggerEvent::Triggered,
                    this,
                    &amp;amp;AMainCharacter::StartJump
                );
                
                // IA_Jump 액션 키에서 &quot;손을 뗀 순간&quot; StopJump() 호출
                EnhancedInput-&amp;gt;BindAction(
                    PlayerController-&amp;gt;JumpAction,
                    ETriggerEvent::Completed,
                    this,
                    &amp;amp;AMainCharacter::StopJump
                );
            }
            
            if (PlayerController-&amp;gt;LookAction)
            {
                // IA_Look 액션 마우스가 &quot;움직일 때&quot; Look() 호출
                EnhancedInput-&amp;gt;BindAction(
                    PlayerController-&amp;gt;LookAction,
                    ETriggerEvent::Triggered,
                    this,
                    &amp;amp;AMainCharacter::Look
                );
            }
            
            if (PlayerController-&amp;gt;SprintAction)
            {
                // IA_Sprint 액션 키를 &quot;누르고 있는 동안&quot; StartSprint() 호출
                EnhancedInput-&amp;gt;BindAction(
                    PlayerController-&amp;gt;SprintAction,
                    ETriggerEvent::Triggered,                   
                    this, 
                    &amp;amp;AMainCharacter::StartSprint
                );
                // IA_Sprint 액션 키에서 &quot;손을 뗀 순간&quot; StopSprint() 호출
                EnhancedInput-&amp;gt;BindAction(
                    PlayerController-&amp;gt;SprintAction, 
                    ETriggerEvent::Completed, 
                    this, 
                    &amp;amp;AMainCharacter::StopSprint
                );
            }    
        }
    }

}

void AMainCharacter::Move(const FInputActionValue&amp;amp; value)
{
	// 컨트롤러가 있어야 방향 계산이 가능
	if (!Controller) return;

	// Value는 Axis2D로 설정된 IA_Move의 입력값 (WASD)을 담고 있음
	// 예) (X=1, Y=0) &amp;rarr; 전진 / (X=-1, Y=0) &amp;rarr; 후진 / (X=0, Y=1) &amp;rarr; 오른쪽 / (X=0, Y=-1) &amp;rarr; 왼쪽
	const FVector2D MoveInput = value.Get&amp;lt;FVector2D&amp;gt;();

	// IsNearlyZero
	// 부동소수점들은 딱 0으로 안 떨어 질 수도 있기 때문에 작은 오차들은 0으로 처리 하기 위한 함수
	if (!FMath::IsNearlyZero(MoveInput.X))
	{		
		// 캐릭터가 바라보는 방향(정면)으로 X축 이동
		AddMovementInput(GetActorForwardVector(), MoveInput.X);
	}

	if (!FMath::IsNearlyZero(MoveInput.Y))
	{
		// 캐릭터의 오른쪽 방향으로 Y축 이동
		AddMovementInput(GetActorRightVector(), MoveInput.Y);
	}
}

void AMainCharacter::Look(const FInputActionValue&amp;amp; value)
{
	// 마우스의 X, Y 움직임을 2D 축으로 가져옴
	FVector2D LookInput = value.Get&amp;lt;FVector2D&amp;gt;();

	// X는 좌우 회전 (Yaw), Y는 상하 회전 (Pitch)
	// 좌우 회전
	AddControllerYawInput(LookInput.X);
	
	// 상하 회전
	// IA에서 반전해둔 상태
	// 여기엔 추후 변경 가능한 옵션 추가해주자
	AddControllerPitchInput(LookInput.Y);
}

void AMainCharacter::StartJump(const FInputActionValue&amp;amp; value)
{
	// Jump 함수는 Character가 기본 제공
	if (value.Get&amp;lt;bool&amp;gt;())
	{
		Jump();
	}
}
void AMainCharacter::StopJump(const FInputActionValue&amp;amp; value)
{	
	// StopJumping 함수도 Character가 기본 제공
	if (!value.Get&amp;lt;bool&amp;gt;())
	{
		StopJumping();
	}	
}

void AMainCharacter::StartSprint(const FInputActionValue&amp;amp; value)
{
	// Shift 키를 누른 순간 이 함수가 호출된다고 가정
	// 스프린트 속도를 적용
	if (GetCharacterMovement())
	{
		// 중간에 변경시 
		SprintSpeed = NormalSpeed * SprintSpeedMultiplier;		
		
		GetCharacterMovement()-&amp;gt;MaxWalkSpeed = SprintSpeed;
	}

}
void AMainCharacter::StopSprint(const FInputActionValue&amp;amp; value)
{
	// Shift 키를 뗀 순간 이 함수가 호출
	// 평상시 속도로 복귀
	if (GetCharacterMovement())
	{
		GetCharacterMovement()-&amp;gt;MaxWalkSpeed = NormalSpeed;
	}
}


float AMainCharacter::GetHealth() const
{
	return Health;
}

// 체력 회복 함수
void AMainCharacter::AddHealth(float  Amount)
{
	// 체력을 회복시킴. 최대 체력을 초과하지 않도록 제한함
	Health = FMath::Clamp(Health + Amount, 0.0f, MaxHealth);
	//UE_LOG(LogTemp, Log, TEXT(&quot;Health increased to: %f&quot;), Health);
	
	if (GEngine)
	{ 
		GEngine-&amp;gt;AddOnScreenDebugMessage(
				-1, 2.f, FColor::Green,
				 TEXT(&quot;Health Increased to: %f&quot;), Health);
	}
}

// 데미지 처리 함수
float  AMainCharacter::TakeDamage(float  DamageAmount, FDamageEvent const&amp;amp; DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
	// 기본 데미지 처리 로직 호출 (필수는 아님)
	int32 ActualDamage = Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);

	// 체력을 데미지만큼 감소시키고, 0 이하로 떨어지지 않도록 Clamp
	Health = FMath::Clamp(Health - DamageAmount, 0.0f, MaxHealth);
	//UE_LOG(LogTemp, Warning, TEXT(&quot;Health decreased to: %f&quot;), Health);
	if (GEngine)
	{ 
		GEngine-&amp;gt;AddOnScreenDebugMessage(
				-1, 2.f, FColor::Yellow,
				 TEXT(&quot;Health decreased to: %f&quot;), Health);
	}

	// 체력이 0 이하가 되면 사망 처리
	if (Health &amp;lt;= 0.0f)
	{
		OnDeath();
	}

	// 실제 적용된 데미지를 반환
	return ActualDamage;
}

// 사망 처리 함수
void AMainCharacter::OnDeath()
{
	//UE_LOG(LogTemp, Error, TEXT(&quot;Character is Dead!&quot;));
	if (GEngine)
	{ 
		GEngine-&amp;gt;AddOnScreenDebugMessage(
				-1, 2.f, FColor::Red,
				 TEXT(&quot;Character is Dead!&quot;));
	}

	// 사망 후 로직
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3️⃣ 지뢰 아이템 데미지 함수 수정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지뢰 아이템 (MineItem)이 폭발할 때, 주변 액터에게 데미지를 주려면 &lt;b&gt;UGameplayStatics::ApplyDamage&lt;/b&gt; 함수를 호출해 해당 액터의 TakeDamage()가 실행되도록 하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UGamePlayStatics::ApplyDamage() 라는 UE Static 제공 함수.&lt;/li&gt;
&lt;li&gt;#include &quot;Kismet/GameplayStatics.h&quot; 해줘야 합니다.&lt;/li&gt;
&lt;li&gt;UGameplayStatics::ApplyDamage는 언리얼 엔진에서 액터에게 손쉽게 데미지를 가하고 대상의 TakeDamage() 함수를 트리거하는 핵심 함수입니다&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781160420449&quot; class=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;UGameplayStatics::ApplyDamage(
    AActor* DamagedActor,           // 데미지를 받을 대상 액터
    float BaseDamage,               // 기본 데미지 양
    AController* EventInstigator,   // 데미지를 입힌 주체의 컨트롤러 (데스 카운트 등에 사용)
    AActor* DamageCauser,           // 데미지를 실제로 발생시킨 액터 (무기, 투사체 등)
    TSubclassOf&amp;lt;UDamageType&amp;gt; DamageTypeClass // 데미지 타입 클래스
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;ApplyDamage()&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;대상 액터(Actor)가 존재하는지 확인.&lt;/li&gt;
&lt;li&gt;대상 액터의 TakeDamage() 함수를 호출합니다.&lt;/li&gt;
&lt;li&gt;DamageType은 여러 가지 파생 클래스를 만들어 물리/화염/독 등 다양한 데미지 유형을 정의할 수 있습니다 (지금은 기본값 사용).&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;지뢰는 독립적으로 스폰된 뒤 폭발하므로 EventInstigator를 nullptr로 둡니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;멀티플레이에서 &amp;ldquo;누가 지뢰를 설치했느냐&amp;rdquo;를 추적하려면, 생성 시점에 &lt;b&gt;Instigator&lt;/b&gt;나 &lt;b&gt;Controller&lt;/b&gt; 정보를 넣어줄 수도 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781161936444&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;MineItem.h&quot;
#include &quot;Components/SphereComponent.h&quot;
#include &quot;Kismet/GameplayStatics.h&quot;

AMineItem::AMineItem()
{
	ExplosionDelay = 5.0f;
	ExplosionRadius = 300.0f;
	ExplosionDamage = 30.0f;
	ItemType = &quot;Mine&quot;;
    
	ExplosionCollision = CreateDefaultSubobject&amp;lt;USphereComponent&amp;gt;(TEXT(&quot;ExplosionCollision&quot;));
	ExplosionCollision-&amp;gt;InitSphereRadius(ExplosionRadius);
	//ExplosionCollision-&amp;gt;SetCollisionProfileName(TEXT(&quot;OverlapAllDynamic&quot;)); 
	ExplosionCollision-&amp;gt;SetCollisionProfileName(CollisionProfile_OverlapAllDynamic); 
	ExplosionCollision-&amp;gt;SetupAttachment(Scene);
}

void AMineItem::ActivateItem(AActor* Activator)
{
	// 5초 후 폭발 실행
	GetWorld()-&amp;gt;GetTimerManager().SetTimer(ExplosionTimerHandle, this, &amp;amp;AMineItem::Explode, ExplosionDelay);
}

void AMineItem::Explode()
{
	TArray&amp;lt;AActor*&amp;gt; OverlappingActors;
	ExplosionCollision-&amp;gt;GetOverlappingActors(OverlappingActors);

	for (AActor* Actor : OverlappingActors)
	{
		if (Actor &amp;amp;&amp;amp; Actor-&amp;gt;ActorHasTag(&quot;Player&quot;))
		{
			//GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, FString::Printf(TEXT(&quot;Player damaged %d by MineItem&quot;), ExplosionDamage));
			
			// 데미지를 발생시켜 Actor-&amp;gt;TakeDamage()가 실행되도록 함
			UGameplayStatics::ApplyDamage(
				Actor,                      // 데미지를 받을 액터
				ExplosionDamage,            // 데미지 양
				nullptr,                    // 데미지를 유발한 주체 (지뢰를 설치한 캐릭터가 없으므로 nullptr)
				this,                       // 데미지를 유발한 오브젝트(지뢰)
				UDamageType::StaticClass()  // 기본 데미지 유형
			);
			
			
		}
	}

	// 지뢰 제거
	DestroyItem();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4️⃣ 힐링 아이템 체력 회복 함수 수정&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아래 코드는 &lt;b&gt;힐링 아이템&lt;/b&gt;(HealingItem)이 플레이어를 회복시킵니다. AddHealth() 함수를 직접 호출해 체력을 증가시킵니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ActorHasTag(&quot;Player&quot;)로 플레이어인지 판별하는 단순 로직입니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;캐릭터를 구분하는 더 안전한 방법(예: Cast&amp;lt;AMainCharacter&amp;gt;(Activator))을 쓰거나, &lt;b&gt;Collision 채널&lt;/b&gt;을 이용하는 식으로도 바꿀 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;AddHealth()에서 FMath::Clamp를 사용해 &lt;b&gt;최대 체력 이상&lt;/b&gt;으로 올라가지 않도록 제한합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style2&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a4&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;점수 관리 시스템 구현하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣ &lt;b&gt;GameMode와 GameState의 연계 이해하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;언리얼 엔진에서 &lt;b&gt;GameMode&lt;/b&gt;와 &lt;b&gt;GameState&lt;/b&gt;는 게임의 전역 정보를 유지하고, 필요할 경우 멀티플레이어 환경에서 해당 정보를 &lt;b&gt;서버&lt;/b&gt;와 &lt;b&gt;클라이언트&lt;/b&gt; 간에 동기화하는 역할을 합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;GameMode&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;ldquo;게임의 규칙(룰)&amp;rdquo;을 정의하고 관리합니다.&lt;/li&gt;
&lt;li&gt;어떤 캐릭터를 스폰할지, 플레이어가 사망했을 때 어떻게 처리할지를 결정합니다.&lt;/li&gt;
&lt;li&gt;멀티플레이에서는 &lt;b&gt;서버 전용&lt;/b&gt;으로 동작합니다(클라이언트에는 존재하지 않음).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GameState&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;게임 플레이 전반에서 &amp;ldquo;공유되어야 하는 전역 상태&amp;rdquo;를 저장합니다. GameState는 기본적으로 &amp;ldquo;레벨당 1개&amp;rdquo; 존재하며, 엔진 내부에서 데이터 동기화를 고려해 설계되었기에 전역 데이터 관리용으로 적합합니다.&lt;/li&gt;
&lt;li&gt;대표적으로 점수, 남은 시간, 현재 게임 단계(Phase), 스폰된 오브젝트의 총 개수 등을 저장합니다.&lt;/li&gt;
&lt;li&gt;멀티플레이에서는 서버가 관리하고, 클라이언트는 이를 &lt;b&gt;자동으로 동기화&lt;/b&gt; 받아볼 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;싱글 플레이&lt;/b&gt;에서도 GameState가 굳이 필요 없을 것 같지만, &amp;ldquo;전역적으로 공유해야 할 정보&amp;rdquo;를 한 군데서 관리하면 유지보수가 더 편해집니다. &amp;ldquo;몇 개의 아이템이 스폰되었는지&amp;rdquo;, &amp;ldquo;현재 게임 진행도는 어느 정도인지&amp;rdquo; 같은 데이터를 GameState에서 일괄 관리할 수 있기 때문입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예시: 전역적인 스폰 제한 로직&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;ldquo;현재 게임에 스폰된 아이템이 30개를 넘으면, 더 이상 아이템을 스폰하지 않는다.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;이 로직을 &lt;b&gt;GameState&lt;/b&gt;에 두고 관리한다면:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;GameState 내부에서 &amp;ldquo;스폰된 아이템 개수&amp;rdquo; 변수를 관리&lt;/li&gt;
&lt;li&gt;스폰이 일어날 때마다 이 변수를 증가시키고, 30개를 초과하는지 체크&lt;/li&gt;
&lt;li&gt;초과 시 GameMode(또는 스폰 시스템)에서 &amp;ldquo;더 이상 스폰 금지&amp;rdquo; 로직 적용&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;이처럼 전역적으로 공유되어야 할 데이터(점수, 스폰 개수, 타이머 등)는 GameState에 저장하고, 게임 규칙이나 흐름을 제어하는 로직은 GameMode 또는 별도의 매니저 클래스로 분리하는 것이 일반적입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2️⃣ &lt;b&gt;GameState에 점수 데이터 및 함수 추가&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이번에는 전역 점수를 GameState에 저장하고, &lt;b&gt;누군가 점수를 획득할 때마다 AddScore()를 호출&lt;/b&gt;해 점수가 증가하도록 구현해봅니다.&lt;/li&gt;
&lt;li&gt;언리얼 에디터에서 &lt;b&gt;C++ Class &amp;rarr; GameStateBase&lt;/b&gt;를 선택하고, 클래스 이름을 MainGameStateBase 라고 짓습니다.&lt;/li&gt;
&lt;li&gt;Main GameStateBase.h와 MainGameStateBase.cpp에 아래와 같이 코드를 작성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;915&quot; data-origin-height=&quot;558&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baNQgR/dJMcaaySmjR/f4yLmGXMtTeg4UjMykaH0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baNQgR/dJMcaaySmjR/f4yLmGXMtTeg4UjMykaH0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baNQgR/dJMcaaySmjR/f4yLmGXMtTeg4UjMykaH0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaNQgR%2FdJMcaaySmjR%2Ff4yLmGXMtTeg4UjMykaH0k%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;915&quot; height=&quot;558&quot; data-origin-width=&quot;915&quot; data-origin-height=&quot;558&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1781163242821&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pragma once

#include &quot;CoreMinimal.h&quot;
#include &quot;GameFramework/GameState.h&quot;
#include &quot;MainGameState.generated.h&quot;


UCLASS()
class BC_CH3_ASSIGNMENT_5_API AMainGameState : public AGameState
{
	GENERATED_BODY()
	
public:
	AMainGameState();	
	
	// === Variables ===
	// 전역 점수를 저장하는 변수
	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category=&quot;Score&quot;)
	int32 Score;

	
	// === Func ===
	// 현재 점수를 읽는 함수
	UFUNCTION(BlueprintPure, Category=&quot;Score&quot;)
	int32 GetScore() const;
	
	// 점수를 추가해주는 함수
	UFUNCTION(BlueprintCallable, Category=&quot;Score&quot;)
	void AddScore(int32 Amount);
	
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1781163255534&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;MainGameState.h&quot;

AMainGameState::AMainGameState()
{
	
}

int32 AMainGameState::GetScore() const
{
	return Score;
}

void AMainGameState::AddScore(int32 Amount)
{
	Score += Amount;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3️⃣ &lt;b&gt;GameMode와 GameState 연동&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로, 기존에 만들었던 &lt;b&gt;GameMode&lt;/b&gt; 클래스에서 &lt;b&gt;GameStateClass&lt;/b&gt; 멤버를 우리가 만든 MainGameState로 설정해줍니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;방금 만든 MainGameState 에 대한 C++ 코드가 컴파일되면, 언리얼 에디터에서 해당 클래스를 인식하게 됩니다.&lt;/li&gt;
&lt;li&gt;MainGameState 를 더 확장하거나 블루프린트 비주얼 스크립팅을 사용하기 위해, C++ 클래스를 부모로 하는 블루프린트(BP_ MainGameState)를 만들어서 사용합니다.&lt;/li&gt;
&lt;li&gt;Project Settings 적용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Edit &amp;rarr; Project Settings &amp;rarr; Maps &amp;amp; Modes&lt;/b&gt;로 들어가서 &lt;b&gt;Default GameMode&lt;/b&gt;를 우리 커스텀 게임 모드( MainGameState 또는 그 블루프린트 클래스)로 설정합니다.&lt;/li&gt;
&lt;li&gt;그 뒤 &lt;b&gt;Game State Class&lt;/b&gt;도 BP_MainGameState (또는 MainGameState )로 맞춰주면, 전역적으로 이 설정이 적용됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;World Settings에서 설정 (레벨별로 오버라이드 가능)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;359&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SB4uQ/dJMcahSejF4/ohYb82rr8tTzAtCLkKtfqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SB4uQ/dJMcahSejF4/ohYb82rr8tTzAtCLkKtfqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SB4uQ/dJMcahSejF4/ohYb82rr8tTzAtCLkKtfqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSB4uQ%2FdJMcahSejF4%2FohYb82rr8tTzAtCLkKtfqK%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;773&quot; height=&quot;359&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;359&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1781163454959&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;MainGameMode.h&quot;
#include &quot;MainCharacter.h&quot;
#include &quot;MainPlayerController.h&quot;
#include &quot;MainGameState.h&quot;

AMainGameMode::AMainGameMode()
{
	// StaticClass(): 클래스 이름을 통해서 호출해주는것
	DefaultPawnClass = AMainCharacter::StaticClass();
	//
	PlayerControllerClass = AMainPlayerController::StaticClass();
	GameStateClass = AMainGameState::StaticClass();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span&gt;4️⃣&lt;/span&gt; &lt;span data-token-index=&quot;1&quot;&gt;코인 아이템 점수 획득 함수 수정&lt;/span&gt; &lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GetWorld()-&amp;gt;GetGameState&amp;lt;AMainGameState&amp;gt;()로 게임 스테이트를 가져오고, AddScore(PointValue) 함수를 호출해 점수를 올립니다.&lt;/li&gt;
&lt;li&gt;PointValue(int32)는 이 코인 아이템이 제공하는 점수량이며, ACoinItem의 멤버 변수로 관리하고 있습니다.&lt;/li&gt;
&lt;li&gt;이 과정을 통해 플레이어가 코인을 획득하면, &lt;b&gt;전역적으로 관리되는 GameState&lt;/b&gt;에서 점수가 증가하고, 코인은 사라져서 한 번만 획득되도록 처리됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781163659679&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;CoinItem.h&quot;
#include &quot;Engine/World.h&quot;
#include &quot;MainGameState.h&quot;

ACoinItem::ACoinItem()
{
	// 부모클래스라 안해도 되지만 
	// 점수 기본값을 0으로 설정
	PointValue = 0;
	ItemType = &quot;DefaultCoin&quot;;
}

void ACoinItem::ActivateItem(AActor* Activator)
{
	// 플레이어 태그 확인
	if (Activator &amp;amp;&amp;amp; Activator-&amp;gt;ActorHasTag(&quot;Player&quot;))
	{
		// 점수 획득 디버그 메시지
		GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, 
			FString::Printf(TEXT(&quot;Player Gained %i Points!&quot;), PointValue));
        
		if (UWorld* World = GetWorld())
		{
			if (AMainGameState* GameState = World-&amp;gt;GetGameState&amp;lt;AMainGameState&amp;gt;())
			{
				GameState-&amp;gt;AddScore(PointValue);
			}
		}
		
		// 부모 클래스 (BaseItem)에 정의된 아이템 파괴 함수 호출
		DestroyItem();
	}
}&lt;/code&gt;&lt;/pre&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;h3 style=&quot;padding: 0.3em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #5b63fb; font-weight: bold; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;추천&lt;/span&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/107&quot;&gt;[Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781164263603&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;인터페이스 기반 아이템 클래스 설계하기 인터페이스 이해하기1️⃣ 인터페이스란?인터페이스 (Interface)란 클래스 (또는 오브젝트)가 반드시 구현해야 할 함수 목록만을 미리 정의해 두고, 실제 &quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/107&quot; data-og-url=&quot;https://devcol.tistory.com/107&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/sA9RM/dJMb9frNEV7/mqumL986okRdsyJE9ASHo1/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/biAScA/dJMb9gxtHkU/Yh7zNXgwmwbeJInju0dqf1/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/ApySg/dJMb87geO5s/dnf4JtgjnftSvuuZiKWhhK/img.png?width=997&amp;amp;height=544&amp;amp;face=0_0_997_544&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/107&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/107&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/sA9RM/dJMb9frNEV7/mqumL986okRdsyJE9ASHo1/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/biAScA/dJMb9gxtHkU/Yh7zNXgwmwbeJInju0dqf1/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/ApySg/dJMb87geO5s/dnf4JtgjnftSvuuZiKWhhK/img.png?width=997&amp;amp;height=544&amp;amp;face=0_0_997_544');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스 기반 아이템 클래스 설계하기 인터페이스 이해하기1️⃣ 인터페이스란?인터페이스 (Interface)란 클래스 (또는 오브젝트)가 반드시 구현해야 할 함수 목록만을 미리 정의해 두고, 실제&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/108&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Unreal Engine/UE 기초] - 충돌 이벤트로 획득되는 아이템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781164265631&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;충돌 이벤트로 획득되는 아이템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;충돌 이벤트로 획득되는 아이템 구현하기 이전 포스팅에서는 클래스 구조만 짜고 로직은 비여있던 상태.이전 포스팅: [Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼 &quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/108&quot; data-og-url=&quot;https://devcol.tistory.com/108&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/jmWjD/dJMb82MLsPp/7QMxGqRnfqAFCn6p5k8tkk/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/JFK5Z/dJMb81G5Lvh/TXhxaBoI1kuEALcXwK5ByK/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/bHB478/dJMb9g5jhTi/zCDS1GY8Z9i42g4dal6kB0/img.png?width=1596&amp;amp;height=489&amp;amp;face=0_0_1596_489&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/108&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/108&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/jmWjD/dJMb82MLsPp/7QMxGqRnfqAFCn6p5k8tkk/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/JFK5Z/dJMb81G5Lvh/TXhxaBoI1kuEALcXwK5ByK/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/bHB478/dJMb9g5jhTi/zCDS1GY8Z9i42g4dal6kB0/img.png?width=1596&amp;amp;height=489&amp;amp;face=0_0_1596_489');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;충돌 이벤트로 획득되는 아이템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;충돌 이벤트로 획득되는 아이템 구현하기 이전 포스팅에서는 클래스 구조만 짜고 로직은 비여있던 상태.이전 포스팅: [Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/109&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Unreal Engine/UE 기초] - 아이템 스폰 및 레벨 데이터 관리하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781164269509&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;아이템 스폰 및 레벨 데이터 관리하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;아이템 스폰 및 레벨 데이터 관리하기 랜덤 위치에 아이템 스폰하기 1️⃣ 레벨 셋팅하기Resources 폴더에 Maps 폴더에는 3개의 레벨이 이미 존재합니다. 각각 난이도에 따라서 크기가 다른 맵이고, &quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/109&quot; data-og-url=&quot;https://devcol.tistory.com/109&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cLGxfm/dJMb8Yp3Jgs/XodaPA7Bq8Q2bwJcaYrOk1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/b3TL4M/dJMb81f0W7R/XxH3bkz7XP3Dxcl22AJkU1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/c4oxJD/dJMb89ylWzD/GSEuPUkAww5SFszPpPhOs1/img.png?width=940&amp;amp;height=571&amp;amp;face=0_0_940_571&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/109&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/109&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cLGxfm/dJMb8Yp3Jgs/XodaPA7Bq8Q2bwJcaYrOk1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/b3TL4M/dJMb81f0W7R/XxH3bkz7XP3Dxcl22AJkU1/img.gif?width=640&amp;amp;height=360&amp;amp;face=0_0_640_360,https://scrap.kakaocdn.net/dn/c4oxJD/dJMb89ylWzD/GSEuPUkAww5SFszPpPhOs1/img.png?width=940&amp;amp;height=571&amp;amp;face=0_0_940_571');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;아이템 스폰 및 레벨 데이터 관리하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;아이템 스폰 및 레벨 데이터 관리하기 랜덤 위치에 아이템 스폰하기 1️⃣ 레벨 셋팅하기Resources 폴더에 Maps 폴더에는 3개의 레벨이 이미 존재합니다. 각각 난이도에 따라서 크기가 다른 맵이고,&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/pages/Unreal-Engine-%EC%96%B8%EB%A6%AC%EC%96%BC-%EC%97%94%EC%A7%84&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;[페이지] Unreal Engine | 언리얼 엔진&lt;/b&gt;&lt;/a&gt;&lt;/h4&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;</description>
      <category>Unreal Engine/UE 기초</category>
      <category>C++</category>
      <category>Devlog</category>
      <category>Programming</category>
      <category>UE</category>
      <category>UE5</category>
      <category>Unreal engine</category>
      <category>게임 개발</category>
      <category>기초</category>
      <category>언리얼 엔진</category>
      <category>프로그래밍</category>
      <author>DevCol</author>
      <guid isPermaLink="true">https://devcol.tistory.com/110</guid>
      <comments>https://devcol.tistory.com/110#entry110comment</comments>
      <pubDate>Thu, 11 Jun 2026 16:48:24 +0900</pubDate>
    </item>
    <item>
      <title>아이템 스폰 및 레벨 데이터 관리하기 | [언리얼 엔진 C++ (Unreal Engine C++)]</title>
      <link>https://devcol.tistory.com/109</link>
      <description>&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt;아이템 스폰 및 레벨 데이터 관리하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a1&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;랜덤 위치에 아이템 스폰하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣ &lt;b&gt;레벨 셋팅하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Resources 폴더에 Maps 폴더에는 3개의 레벨이 이미 존재합니다. 각각 난이도에 따라서 크기가 다른 맵이고, BasicLevel- Intermediate Level- Advanced Level 순서로 크기가 작아집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;229&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NFGVs/dJMcabLlY6U/RArXwrd8EzcWwuIDcH3wg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NFGVs/dJMcabLlY6U/RArXwrd8EzcWwuIDcH3wg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NFGVs/dJMcabLlY6U/RArXwrd8EzcWwuIDcH3wg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNFGVs%2FdJMcabLlY6U%2FRArXwrd8EzcWwuIDcH3wg1%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;680&quot; height=&quot;229&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;229&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위 3개의 레벨을 Content - Maps 폴더로 이동 시킨 후, 기존에 사용하던 MainLevel에서 BasicLevel을 기본 레벨로 지정합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Edit - Project Settings - Maps &amp;amp; Modes에서 Defaults Maps를 BasicLevel로 변경을 해줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;MainLevel은 삭제를 해줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2️⃣ &lt;b&gt;콜리전 컴포넌트로 스폰 영역 지정하기&lt;/b&gt;&lt;/h2&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;b&gt;직접 지정한 박스(상자), 구체, 캡슐&lt;/b&gt; 등 원하는 형태의 &amp;lsquo;콜리전 컴포넌트&amp;rsquo; 내부에서 &lt;b&gt;임의의 좌표&lt;/b&gt;를 뽑아 아이템(액터)을 스폰할 수 있습니다.&lt;/li&gt;
&lt;li&gt;이번에는 우리가 만든 아이템들을 레벨 상에서 자연스럽게 랜덤 배치하려고 합니다. 가장 간단한 방법으로, 콜리전 컴포넌트인 UBoxComponent를 활용해보겠습니다.&lt;/li&gt;
&lt;li&gt;우선, 새로운 C++ 클래스 Actor를 상속한 클랫스로, SpawnVolume 이라는 이름으로 클래스를 하나 생성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;940&quot; data-origin-height=&quot;571&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/P0TZL/dJMcad3lwdT/QdYVxBE0EKPKwjfJuBn2wK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/P0TZL/dJMcad3lwdT/QdYVxBE0EKPKwjfJuBn2wK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/P0TZL/dJMcad3lwdT/QdYVxBE0EKPKwjfJuBn2wK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FP0TZL%2FdJMcad3lwdT%2FQdYVxBE0EKPKwjfJuBn2wK%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;940&quot; height=&quot;571&quot; data-origin-width=&quot;940&quot; data-origin-height=&quot;571&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;933&quot; data-origin-height=&quot;570&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N4eFc/dJMcagshD1D/iDEC3gKLMqEU1z2eutY5z1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N4eFc/dJMcagshD1D/iDEC3gKLMqEU1z2eutY5z1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N4eFc/dJMcagshD1D/iDEC3gKLMqEU1z2eutY5z1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN4eFc%2FdJMcagshD1D%2FiDEC3gKLMqEU1z2eutY5z1%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;933&quot; height=&quot;570&quot; data-origin-width=&quot;933&quot; data-origin-height=&quot;570&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;UBoxComponent* SpawningBox;&lt;/b&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;b&gt;박스 형태의 콜리전 영역&lt;/b&gt;을 나타냅니다.&lt;/li&gt;
&lt;li&gt;언리얼 엔진의 UBoxComponent는 박스 내부에서 오버랩(Overlap)이나 충돌(Collision)을 감지할 수 있는 컴포넌트입니다.&lt;/li&gt;
&lt;li&gt;실제로 눈에 보이는 3D 메시는 아니며, &amp;ldquo;박스 형태의 충돌 범위&amp;rdquo;만 제공합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;GetRandomPointInVolume()&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SpawningBox 범위 내부에서 랜덤 좌표(FVector)를 리턴합니다.&lt;/li&gt;
&lt;li&gt;이 좌표를 이용해 아이템을 생성하면 &amp;ldquo;직육면체 형태 범위 안에서&amp;rdquo; 임의의 위치에 아이템이 뜨는 효과를 낼 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; SpawnItem(TSubclassOf&amp;lt;AActor&amp;gt; ItemClass); &lt;/b&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;b&gt;SpawnVolume&lt;/b&gt; 내부의 랜덤 위치에 생성(SpawnActor)하는 함수입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TSubclassOf&amp;lt;AActor&amp;gt;&lt;/b&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;b&gt;TSoftClassPtr&amp;nbsp;&lt;/b&gt;도 존재합니다&lt;/li&gt;
&lt;li&gt;소프트 레퍼런스: 클래스의 경로만 유지합니다. 그래서 만약에 해단되는 어떤 클래스가 필요한 상황이 되면 그때 가서 메모리에 로드를 하게 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;GetScaledBoxExtent()&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;박스 컴포넌트의 실제 &amp;ldquo;가로/세로/높이 절반 길이(Extent)&amp;rdquo;를 반환합니다 (중심에서 끝부분 까지의 길이이기 때문에 절반 길이입니다). 에디터에서 Scale을 조절하면 여기에도 반영됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;GetComponentLocation()&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴포넌트의 위치 = 현재 우리가 사용하려는 BoxOrigin의 위치&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;FMath::FRandRange(a, b)&lt;/b&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;b&gt;a ~ b&lt;/b&gt; 사이 임의의 float 값을 반환합니다.&lt;/li&gt;
&lt;li&gt;여기서는 X, Y, Z 좌표마다 랜덤 값을 생성하여 BoxOrigin에 더해줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; SpawnActor&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AKAsset*&amp;nbsp;SpawnedActor1&amp;nbsp;=&amp;nbsp;(AKAsset*)&amp;nbsp;GetWorld()-&amp;gt;SpawnActor(AKAsset::StaticClass(),&amp;nbsp;NAME_None,&amp;nbsp;&amp;amp;Location);&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1781146313267&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;AActor* UWorld::SpawnActor
(
    UClass* Class,
    FName InName,
    FVector const* Location,
    FRotator const* Rotation,
    AActor* Template,
    bool bNoCollisionFail,
    bool bRemoteOwned,
    AActor* Owner,
    APawn* Instigator,
    bool bNoFail,
    ULevel* OverrideLevel,
    bool bDeferConstruction
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SpawnActor 관련 UE 공식문서&lt;/b&gt;: &lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/spawning-actors-in-unreal-engine?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dev.epicgames.com/documentation/unreal-engine/spawning-actors-in-unreal-engine?lang=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781146233243&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Spawning Actors in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&quot; data-og-description=&quot;Methods of creating new instances of Actors in gameplay code.&quot; data-og-host=&quot;dev.epicgames.com&quot; data-og-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/spawning-actors-in-unreal-engine?lang=ko&quot; data-og-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/spawning-actors-in-unreal-engine&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dZ7x1t/dJMb9dHwpR6/kiIjxjDkkE1fPkh5zj0TsK/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/bcgVam/dJMb81G5INQ/pBJp25rhy865hcnSrbBdT0/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/bg4EDr/dJMb82eVhbl/ktsLzaz0MQ50jvEslDI3N1/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/spawning-actors-in-unreal-engine?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/spawning-actors-in-unreal-engine?lang=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dZ7x1t/dJMb9dHwpR6/kiIjxjDkkE1fPkh5zj0TsK/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/bcgVam/dJMb81G5INQ/pBJp25rhy865hcnSrbBdT0/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/bg4EDr/dJMb82eVhbl/ktsLzaz0MQ50jvEslDI3N1/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Spawning Actors in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Methods of creating new instances of Actors in gameplay code.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.epicgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;SpawnVolume.h&lt;/p&gt;
&lt;pre id=&quot;code_1781145544154&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pragma once

#include &quot;CoreMinimal.h&quot;
#include &quot;GameFramework/Actor.h&quot;
#include &quot;SpawnVolume.generated.h&quot;

class UBoxComponent;

UCLASS()
class BC_CH3_ASSIGNMENT_5_API ASpawnVolume : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ASpawnVolume();
	
	// 우선 테스트라 public으로
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=&quot;Spawning&quot;)
    USceneComponent* Scene;
    // 스폰 영역을 담당할 박스 컴포넌트
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=&quot;Spawning&quot;)
    UBoxComponent* SpawningBox;

    // 스폰 볼륨 내부에서 무작위 좌표를 얻어오는 함수
    UFUNCTION(BlueprintCallable, Category=&quot;Spawning&quot;)
    FVector GetRandomPointInVolume() const;
    // 특정 아이템 클래스를 스폰하는 함수
    UFUNCTION(BlueprintCallable, Category=&quot;Spawning&quot;)
    void SpawnItem(TSubclassOf&amp;lt;AActor&amp;gt; ItemClass);
	virtual void Tick(float DeltaTime) override;

};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SpawnVolume .cpp&lt;/p&gt;
&lt;pre id=&quot;code_1781145782633&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;SpawnVolume.h&quot;
#include &quot;Components/BoxComponent.h&quot;
#include &quot;Engine/World.h&quot;
#include &quot;GameFramework/Actor.h&quot;

ASpawnVolume::ASpawnVolume()
{
	PrimaryActorTick.bCanEverTick = false;

	// 박스 컴포넌트를 생성하고, 이 액터의 루트로 설정
	Scene = CreateDefaultSubobject&amp;lt;USceneComponent&amp;gt;(TEXT(&quot;Scene&quot;));
	SetRootComponent(Scene);
    
	SpawningBox = CreateDefaultSubobject&amp;lt;UBoxComponent&amp;gt;(TEXT(&quot;SpawningBox&quot;));
	SpawningBox-&amp;gt;SetupAttachment(Scene);
}

FVector ASpawnVolume::GetRandomPointInVolume() const
{
	// 1) 박스 컴포넌트의 스케일된 Extent, 즉 x/y/z 방향으로 반지름(절반 길이)을 구함
	FVector BoxExtent = SpawningBox-&amp;gt;GetScaledBoxExtent();
	// 2) 박스 중심 위치
	FVector BoxOrigin = SpawningBox-&amp;gt;GetComponentLocation();

	// 3) 각 축별로 -Extent ~ +Extent 범위의 무작위 값 생성
	return BoxOrigin + FVector(
		FMath::FRandRange(-BoxExtent.X, BoxExtent.X),
		FMath::FRandRange(-BoxExtent.Y, BoxExtent.Y),
		FMath::FRandRange(-BoxExtent.Z, BoxExtent.Z)
	);
}

void ASpawnVolume::SpawnItem(TSubclassOf&amp;lt;AActor&amp;gt; ItemClass)
{
	if (!ItemClass) return;

	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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3️⃣ &lt;b&gt;아이템 랜덤 스폰 테스트하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빌드를 하고 언리얼 에디터로 돌아와서 이 SpawnVolume 클래스를 상속받은 BP_SpawnVolume Blueprint 클래스를 생성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;402&quot; data-origin-height=&quot;557&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFpbyt/dJMcah5QBul/l0N1P4Cw1NgZkeKVB8ltYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFpbyt/dJMcah5QBul/l0N1P4Cw1NgZkeKVB8ltYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFpbyt/dJMcah5QBul/l0N1P4Cw1NgZkeKVB8ltYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFpbyt%2FdJMcah5QBul%2Fl0N1P4Cw1NgZkeKVB8ltYk%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;402&quot; height=&quot;557&quot; data-origin-width=&quot;402&quot; data-origin-height=&quot;557&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;BP_SpawnVolume을 레벨에 드래그해 놓고, 적절히 위치와 스케일을 조정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;559&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NhvBs/dJMcad3lxka/KhnGKcoPwYEdRlKJQWj2pk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NhvBs/dJMcad3lxka/KhnGKcoPwYEdRlKJQWj2pk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NhvBs/dJMcad3lxka/KhnGKcoPwYEdRlKJQWj2pk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNhvBs%2FdJMcad3lxka%2FKhnGKcoPwYEdRlKJQWj2pk%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;649&quot; height=&quot;559&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;559&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;3개의 레벨 모두 이렇게 BP_SpawnVolume 을 맵의 크기에 맞게 적절하게 셋팅을 해줍니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a4&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;2. 아이템 스폰 확률 데이터 테이블 만들기&lt;/h3&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣&lt;b&gt;Item Data 구조체 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 아이템이 몇 % 확률로 스폰되는지를 &lt;b&gt;코드로 직접 하드코딩&lt;/b&gt;하면, 매번 수정할 때마다 빌드를 해줘야 해서 번거롭습니다.&lt;/li&gt;
&lt;li&gt;언리얼 엔진의 &lt;b&gt;데이터 테이블&lt;/b&gt;을 사용하면, 이를 &lt;b&gt;엑셀 (CSV)이나 JSON&lt;/b&gt; 파일로 관리해서 &lt;b&gt;엔진 안으로 임포트&lt;/b&gt;하고, &lt;b&gt;코드나 블루프린트&lt;/b&gt;에서 쉽게 불러 쓸 수 있습니다. 기획자나 디자이너도 엑셀에서 숫자만 바꾸면 되므로 매우 편리합니다.&lt;/li&gt;
&lt;li&gt;우선, 데이터 테이블의 각 &amp;ldquo;&lt;b&gt;행(Row)&lt;/b&gt;&amp;rdquo;을 C++ 구조체로 매핑해야 합니다. 언리얼 엔진은 FTableRowBase라는 기본 구조체를 제공하며, 이를 상속한 구조체를 만들면, 각 CSV (또는 JSON) 행을 FItemSpawnRow 구조체에서 정해준 형태로 받아올 수 있게 됩니다.&lt;/li&gt;
&lt;li&gt;이러한 구조체는 클래스가 아니기 때문에, 부모 클래스를 선택할 수 있는 옵션에 나타나지 않습니다. 따라서 None을 선택해서 ItemSpawnRow C++ 파일을 만들어줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;#pragma once

#include &quot;CoreMinimal.h&quot;
#include &quot;Engine/DataTable.h&quot; // FTableRowBase 정의가 들어있는 헤더
#include &quot;ItemSpawnRow.generated.h&quot;

USTRUCT(BlueprintType)
struct FItemSpawnRow : public FTableRowBase
{
	GENERATED_BODY()

public:
	// 아이템 이름
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	FName ItemName;
	
	// 어떤 아이템 클래스를 스폰할지
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	TSubclassOf&amp;lt;AActor&amp;gt; ItemClass; // 원래는 소프트 레퍼런스인 TSoftClassPtr 로 하는게 맞습니다.
	// 이 아이템의 스폰 확률
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	float SpawnChance;
};&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;FTableRowBase&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;언리얼 엔진에서 &amp;ldquo;이 구조체는 데이터 테이블로 쓸 수 있다&amp;rdquo;라고 인식하게 해주는 베이스 구조체입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;TSoftClassPtr&amp;lt;AActor&amp;gt;&lt;/b&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;필요할 때 Get()을 통해 실제 UClass*를 얻어 인스턴스를 생성할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;h2 data-ke-size=&quot;size26&quot;&gt;2️⃣ &lt;b&gt;CSV 파일 작성 및 임포트하기 (방법 1)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엑셀을 열고 2열부터 Column 이름을 작성합니다.&lt;/li&gt;
&lt;li&gt;1열은 &amp;ldquo;RowName&amp;rdquo;으로 인식됩니다. Key 값으로 사용할 값을 입력해줘야 합니다.&lt;/li&gt;
&lt;li&gt;2열부터는 각 아이템 (데이터) 정보를 한 줄씩 기록합니다.&lt;/li&gt;
&lt;li&gt;&lt;img id=&quot;img_1781147718839_0&quot; src=&quot;https://prod-files-secure.s3.us-west-2.amazonaws.com/83c75a39-3aba-4ba4-a792-7aefe4b07895/d9fe560a-68fe-48c3-b622-e56564155dd8/image.png&quot; /&gt;&lt;/li&gt;
&lt;li&gt;경로는 각 BP 클래스 &lt;b&gt;우클릭 &amp;rarr; Copy Reference&lt;/b&gt; 로 정확히 가져옵니다. 그리고 블루프린트의 경우 뒤에 &quot;_C&quot;가 붙어야 BP 클래스로 인식되니까 마지막에 반드시 붙여주세요.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Copy Reference는 언리얼 엔진 런타임에서 사용&lt;/b&gt;되는 &amp;ldquo;클래스/오브젝트&amp;rdquo; 경로입니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;블루프린트/C++로 자산 로드 시 &lt;b&gt;ConstructorHelpers::FClassFinder&lt;/b&gt; 등에서 활용.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;img id=&quot;img_1781147718839_1&quot; src=&quot;https://prod-files-secure.s3.us-west-2.amazonaws.com/83c75a39-3aba-4ba4-a792-7aefe4b07895/f5bcda0a-427c-4377-a7a9-9465c2af6e9a/image.png&quot; /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CSV로 저장&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;언리얼 콘텐츠 폴더가 아니라 본인이 편한 로컬 위치에 파일명 ItemSpawnTable.csv 로 **CSV UTF-8 (쉼표로 분리)**로 저장합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;언리얼 에디터&lt;/b&gt;로 돌아와, &lt;b&gt;Content Browser&lt;/b&gt;에서 Blueprints 폴더에서 &lt;b&gt;우클릭 &amp;rarr; Import to /Game/Blueprints&lt;/b&gt; 를 선택, 아래와 같이 옵션을 설정하고 Apply를 클릭해줍니다.&lt;/li&gt;
&lt;li&gt;&lt;img id=&quot;img_1781147718839_2&quot; src=&quot;https://prod-files-secure.s3.us-west-2.amazonaws.com/83c75a39-3aba-4ba4-a792-7aefe4b07895/31879d97-bec6-437b-bb5e-4d0b5a4232f0/image.png&quot; /&gt;&lt;/li&gt;
&lt;li&gt;그러면 다음과 같이 성공적으로 DatTable이 만들어진 것을 볼 수 있습니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약 CSV 파일에서 데이터가 업데이트되었을 경우 Reimport를 해주면 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;img id=&quot;img_1781147718839_3&quot; src=&quot;https://prod-files-secure.s3.us-west-2.amazonaws.com/83c75a39-3aba-4ba4-a792-7aefe4b07895/bd4edbf9-1c34-4e7e-9c06-ca665cbf2fab/image.png&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3️⃣ &lt;b&gt;언리얼 에디터에서 직접 데이터 테이블 수정하기 (방법 2)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CSV를 쓰는 대신, &lt;b&gt;언리얼 에디터 내에서 직접 편집&lt;/b&gt;하는 방법도 있습니다.
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Content Browser 창에서 &lt;b&gt;우클릭 &amp;rarr; Miscellaneous &amp;rarr; Data Table&lt;/b&gt; 선택&lt;/li&gt;
&lt;li&gt;팝업창에서 Row Structure로 FItemSpawnRow를 선택하고 OK&lt;/li&gt;
&lt;li&gt;새로 생성된 &lt;b&gt;DataTable&lt;/b&gt; 에셋을 열면, 에디터 UI 상에서 아래처럼 Row 정보를 바로 편집 가능합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Add Row&lt;/b&gt; 버튼을 눌러 행을 추가하고, Row Name, ItemName, ItemClass, SpawnChance 등을 원하는 값으로 넣습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;하지만 이런 방식은 Excel처럼 대량의 데이터를 한 번에 편집하기는 불편할 수 있습니다.&lt;/li&gt;
&lt;li&gt;상황에 따라 에디터 직접 편집 / CSV 임포트 모두 필요에 따라 병행할 수도 있습니다. &amp;lt;/aside&amp;gt;&amp;lt;aside&amp;gt;&lt;/li&gt;
&lt;li&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style2&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a4&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;아이템 스폰 확률 데이터 테이블 만들기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣&lt;b&gt;Item Data 구조체 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 아이템이 몇 % 확률로 스폰되는지를 &lt;b&gt;코드로 직접 하드코딩&lt;/b&gt;하면, 매번 수정할 때마다 빌드를 해줘야 해서 번거롭습니다.&lt;/li&gt;
&lt;li&gt;언리얼 엔진의 &lt;b&gt;데이터 테이블&lt;/b&gt;을 사용하면, 이를 &lt;b&gt;엑셀 (CSV)이나 JSON&lt;/b&gt; 파일로 관리해서 &lt;b&gt;엔진 안으로 임포트&lt;/b&gt;하고, &lt;b&gt;코드나 블루프린트&lt;/b&gt;에서 쉽게 불러 쓸 수 있습니다. 기획자나 디자이너도 엑셀에서 숫자만 바꾸면 되므로 매우 편리합니다.&lt;/li&gt;
&lt;li&gt;우선, 데이터 테이블의 각 &amp;ldquo;&lt;b&gt;행(Row)&lt;/b&gt;&amp;rdquo;을 C++ 구조체로 매핑해야 합니다. 언리얼 엔진은 FTableRowBase라는 기본 구조체를 제공하며, 이를 상속한 구조체를 만들면, 각 CSV (또는 JSON) 행을 FItemSpawnRow 구조체에서 정해준 형태로 받아올 수 있게 됩니다.&lt;/li&gt;
&lt;li&gt;이러한 구조체는 클래스가 아니기 때문에, 부모 클래스를 선택할 수 있는 옵션에 나타나지 않습니다. 따라서 None을 선택해서 ItemSpawnRow C++ 파일을 만들어줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;943&quot; data-origin-height=&quot;571&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/phAR8/dJMcadvtOFo/IbdQ25JaDRJK3RgCv4ZmIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/phAR8/dJMcadvtOFo/IbdQ25JaDRJK3RgCv4ZmIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/phAR8/dJMcadvtOFo/IbdQ25JaDRJK3RgCv4ZmIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FphAR8%2FdJMcadvtOFo%2FIbdQ25JaDRJK3RgCv4ZmIk%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;943&quot; height=&quot;571&quot; data-origin-width=&quot;943&quot; data-origin-height=&quot;571&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;943&quot; data-origin-height=&quot;568&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/czmAkM/dJMcaglva50/6XAjwRllk1kCDgZOdT9kw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/czmAkM/dJMcaglva50/6XAjwRllk1kCDgZOdT9kw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czmAkM/dJMcaglva50/6XAjwRllk1kCDgZOdT9kw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FczmAkM%2FdJMcaglva50%2F6XAjwRllk1kCDgZOdT9kw0%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;943&quot; height=&quot;568&quot; data-origin-width=&quot;943&quot; data-origin-height=&quot;568&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;FTableRowBase&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;언리얼 엔진에서 &amp;ldquo;이 구조체는 데이터 테이블로 쓸 수 있다&amp;rdquo;라고 인식하게 해주는 베이스 구조체입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;TSoftClassPtr&amp;lt;AActor&amp;gt;&lt;/b&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;필요할 때 Get()을 통해 실제 UClass*를 얻어 인스턴스를 생성할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ItemSpawnRow.h&lt;/p&gt;
&lt;pre id=&quot;code_1781148500341&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pragma once

#include &quot;CoreMinimal.h&quot;
#include &quot;Engine/DataTable.h&quot; // FTableRowBase 정의가 들어있는 헤더
#include &quot;ItemSpawnRow.generated.h&quot;

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;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #5b63fb; font-weight: bold; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;데이터 테이블 수정 하는 두 가지 방법 (언리얼 에디터에서 &amp;amp; CSV 파일로)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2️⃣&lt;b&gt;언리얼 에디터에서 직접 데이터 테이블 수정하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Content Browser 창에서 &lt;b&gt;우클릭 &amp;rarr; Miscellaneous &amp;rarr; Data Table&lt;/b&gt; 선택&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(Content Browser 에서 우클릭 -&amp;gt; Miscellaneous -&amp;gt; Data Table-&amp;gt; Pick Row Structure -&amp;gt; 위에서 만든 ItemSpawnRow 선택)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;495&quot; data-origin-height=&quot;650&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rGFY1/dJMcabqZ1MZ/wvfIzPFRWSZ1nrm9sDmY71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rGFY1/dJMcabqZ1MZ/wvfIzPFRWSZ1nrm9sDmY71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rGFY1/dJMcabqZ1MZ/wvfIzPFRWSZ1nrm9sDmY71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrGFY1%2FdJMcabqZ1MZ%2FwvfIzPFRWSZ1nrm9sDmY71%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;495&quot; height=&quot;650&quot; data-origin-width=&quot;495&quot; data-origin-height=&quot;650&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팝업창에서 Row Structure로 FItemSpawnRow를 선택하고 OK&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;357&quot; data-origin-height=&quot;159&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvOt8y/dJMcageK6CG/1NoQuYLWqqkckeVPYBJKd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvOt8y/dJMcageK6CG/1NoQuYLWqqkckeVPYBJKd0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvOt8y/dJMcageK6CG/1NoQuYLWqqkckeVPYBJKd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvOt8y%2FdJMcageK6CG%2F1NoQuYLWqqkckeVPYBJKd0%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;357&quot; height=&quot;159&quot; data-origin-width=&quot;357&quot; data-origin-height=&quot;159&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;1059&quot; data-origin-height=&quot;250&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUt8IU/dJMcaayRXBH/HYsVWCBGoLLhdAlUURQBBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUt8IU/dJMcaayRXBH/HYsVWCBGoLLhdAlUURQBBk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUt8IU/dJMcaayRXBH/HYsVWCBGoLLhdAlUURQBBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUt8IU%2FdJMcaayRXBH%2FHYsVWCBGoLLhdAlUURQBBk%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;1059&quot; height=&quot;250&quot; data-origin-width=&quot;1059&quot; data-origin-height=&quot;250&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt;DataTable&lt;/b&gt; 에셋을 열면, 에디터 UI 상에서 아래처럼 Row 정보를 바로 편집 가능합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Add Row&lt;/b&gt; 버튼을 눌러 행을 추가하고, Row Name, Item Name, ItemClass, SpawnChance 등을 원하는 값으로 넣습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt; Row Name:&amp;nbsp;&lt;/b&gt;Key 값으로 생각하시면 됩니다.고유 한 이름. !절대 중복될수 없습니다.(찾을 때 이 이름으로 찾습니다)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Item Name:&amp;nbsp;&lt;/b&gt;일종의 참고 사항 같은 것. FName 형태&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1153&quot; data-origin-height=&quot;623&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IW14G/dJMcai4DKuu/H9Hx95dYRemTO9HicSsKF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IW14G/dJMcai4DKuu/H9Hx95dYRemTO9HicSsKF1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IW14G/dJMcai4DKuu/H9Hx95dYRemTO9HicSsKF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIW14G%2FdJMcai4DKuu%2FH9Hx95dYRemTO9HicSsKF1%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;1153&quot; height=&quot;623&quot; data-origin-width=&quot;1153&quot; data-origin-height=&quot;623&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;786&quot; data-origin-height=&quot;646&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhUseT/dJMcacXIKB0/85XAM2DCSzjz63Kdnwny8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhUseT/dJMcacXIKB0/85XAM2DCSzjz63Kdnwny8k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhUseT/dJMcacXIKB0/85XAM2DCSzjz63Kdnwny8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhUseT%2FdJMcacXIKB0%2F85XAM2DCSzjz63Kdnwny8k%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;786&quot; height=&quot;646&quot; data-origin-width=&quot;786&quot; data-origin-height=&quot;646&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Iteam Class 의 경로 끝에 보면 .C 가 붙는데 참조를 하려면 이게 꼭 붙어 있어야 한다는 특징이 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;556&quot; data-origin-height=&quot;81&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dNBrzh/dJMcacpVgf7/WHe4AOi6k8kAG1fYBXcNg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dNBrzh/dJMcacpVgf7/WHe4AOi6k8kAG1fYBXcNg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dNBrzh/dJMcacpVgf7/WHe4AOi6k8kAG1fYBXcNg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdNBrzh%2FdJMcacpVgf7%2FWHe4AOi6k8kAG1fYBXcNg1%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;556&quot; height=&quot;81&quot; data-origin-width=&quot;556&quot; data-origin-height=&quot;81&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;274&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/coH5fG/dJMcahkui2n/c6UCit81QZS3X25o22JEV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/coH5fG/dJMcahkui2n/c6UCit81QZS3X25o22JEV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/coH5fG/dJMcahkui2n/c6UCit81QZS3X25o22JEV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcoH5fG%2FdJMcahkui2n%2Fc6UCit81QZS3X25o22JEV1%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;879&quot; height=&quot;274&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;274&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하지만 이런 방식은 Excel처럼 대량의 데이터를 한 번에 편집하기는 불편할 수 있습니다.&lt;/li&gt;
&lt;li&gt;상황에 따라 에디터 직접 편집 / CSV 임포트 모두 필요에 따라 병행할 수도 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3️⃣&lt;b&gt;CSV 파일 작성 및 임포트하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엑셀을 열고 2열부터 Column 이름을 작성합니다.&lt;/li&gt;
&lt;li&gt;1열은 &amp;ldquo;RowName&amp;rdquo;으로 인식됩니다. Key 값으로 사용할 값을 입력해줘야 합니다.&lt;/li&gt;
&lt;li&gt;2열부터는 각 아이템 (데이터) 정보를 한 줄씩 기록합니다.&lt;/li&gt;
&lt;li&gt;경로는&amp;nbsp;각&amp;nbsp;BP&amp;nbsp;클래스&amp;nbsp;우클릭&amp;nbsp;&amp;rarr;&amp;nbsp;Copy&amp;nbsp;Reference&amp;nbsp;로&amp;nbsp;정확히&amp;nbsp;가져옵니다.&amp;nbsp;그리고&amp;nbsp;블루프린트의&amp;nbsp;경우&amp;nbsp;뒤에&amp;nbsp;&quot;_C&quot;가&amp;nbsp;붙어야&amp;nbsp;BP&amp;nbsp;클래스로&amp;nbsp;인식되니까&amp;nbsp;마지막에&amp;nbsp;반드시&amp;nbsp;붙여주세요.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;/Script/Engine.Blueprint'/Game/Blueprint/BP_BigCoinItem.BP_BigCoinItem'&lt;/li&gt;
&lt;li&gt;그냥 복붙이후는 &quot;_C&quot; 가 안붙기 때문에 따로 꼭 붙여줘야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;366&quot; data-origin-height=&quot;741&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bH8Tiv/dJMcaiKmsjd/cxVKWVPwwliC2ghqCRk1mk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bH8Tiv/dJMcaiKmsjd/cxVKWVPwwliC2ghqCRk1mk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bH8Tiv/dJMcaiKmsjd/cxVKWVPwwliC2ghqCRk1mk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbH8Tiv%2FdJMcaiKmsjd%2FcxVKWVPwwliC2ghqCRk1mk%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;366&quot; height=&quot;741&quot; data-origin-width=&quot;366&quot; data-origin-height=&quot;741&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt;Copy Reference는 언리얼 엔진 런타임에서 사용&lt;/b&gt;되는 &amp;ldquo;클래스/오브젝트&amp;rdquo; 경로입니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;블루프린트/C++로 자산 로드 시 &lt;b&gt;ConstructorHelpers::FClassFinder&lt;/b&gt; 등에서 활용.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1137&quot; data-origin-height=&quot;213&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bE7VCF/dJMcahxY3mh/MpnHZS2kniyjoTuc1xcaQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bE7VCF/dJMcahxY3mh/MpnHZS2kniyjoTuc1xcaQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bE7VCF/dJMcahxY3mh/MpnHZS2kniyjoTuc1xcaQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbE7VCF%2FdJMcahxY3mh%2FMpnHZS2kniyjoTuc1xcaQK%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;1137&quot; height=&quot;213&quot; data-origin-width=&quot;1137&quot; data-origin-height=&quot;213&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;CSV로 저장&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;언리얼 콘텐츠 폴더가 아니라 본인이 편한 로컬 위치에 파일명 ItemSpawnTable.csv 로 CSV UTF-8 (쉼표로 분리)로 저장합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1127&quot; data-origin-height=&quot;628&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NKON0/dJMcahkuyom/zeIpRk5jn9voIz5vymSkmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NKON0/dJMcahkuyom/zeIpRk5jn9voIz5vymSkmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NKON0/dJMcahkuyom/zeIpRk5jn9voIz5vymSkmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNKON0%2FdJMcahkuyom%2FzeIpRk5jn9voIz5vymSkmK%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;1127&quot; height=&quot;628&quot; data-origin-width=&quot;1127&quot; data-origin-height=&quot;628&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;언리얼 에디터&lt;/b&gt;로 돌아와, &lt;b&gt;Content Browser&lt;/b&gt;에서 Blueprints 폴더에서 &lt;b&gt;우클릭 &amp;rarr; Import to /Game/Blueprints&lt;/b&gt; 를 선택, 아래와 같이 옵션을 설정하고 Apply를 클릭해줍니다.&lt;/li&gt;
&lt;li&gt;폴더 내에서 우클릭 후 Import to Current Folder 해도 괜찮습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;227&quot; data-origin-height=&quot;287&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLmETD/dJMcaaMm1zD/eKKnDG6gJ87oD9PtOQ0MK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLmETD/dJMcaaMm1zD/eKKnDG6gJ87oD9PtOQ0MK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLmETD/dJMcaaMm1zD/eKKnDG6gJ87oD9PtOQ0MK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLmETD%2FdJMcaaMm1zD%2FeKKnDG6gJ87oD9PtOQ0MK0%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;227&quot; height=&quot;287&quot; data-origin-width=&quot;227&quot; data-origin-height=&quot;287&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;415&quot; data-origin-height=&quot;318&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/smHBx/dJMcagshYPU/SIvkviHQYuCuICZNZP7SOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/smHBx/dJMcagshYPU/SIvkviHQYuCuICZNZP7SOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/smHBx/dJMcagshYPU/SIvkviHQYuCuICZNZP7SOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsmHBx%2FdJMcagshYPU%2FSIvkviHQYuCuICZNZP7SOk%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;415&quot; height=&quot;318&quot; data-origin-width=&quot;415&quot; data-origin-height=&quot;318&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;1010&quot; data-origin-height=&quot;648&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GiacG/dJMcabxI2p6/VeYZ25LfpLHAOfuMGqWO91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GiacG/dJMcabxI2p6/VeYZ25LfpLHAOfuMGqWO91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GiacG/dJMcabxI2p6/VeYZ25LfpLHAOfuMGqWO91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGiacG%2FdJMcabxI2p6%2FVeYZ25LfpLHAOfuMGqWO91%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;1010&quot; height=&quot;648&quot; data-origin-width=&quot;1010&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;데이터 테이블 관련 UE 공식 문서&lt;/b&gt;: &lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/coder-05-manage-item-and-data-in-an-unreal-engine-game?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dev.epicgames.com/documentation/unreal-engine/coder-05-manage-item-and-data-in-an-unreal-engine-game?lang=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781147824149&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Coder 05 Manage Item and Data in an Unreal Engine Game | Unreal Engine 5.7 Documentation | Epic Developer Community&quot; data-og-description=&quot;Learn to use Item Data Structs, Data Assets, and Data Tables to define items and store and organize item data for scalability in Unreal Engine.&quot; data-og-host=&quot;dev.epicgames.com&quot; data-og-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/coder-05-manage-item-and-data-in-an-unreal-engine-game?lang=ko&quot; data-og-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/coder-05-manage-item-and-data-in-an-unreal-engine-game&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b4sRet/dJMb8WMxWpH/F5PSycUAjCniJE8klncC81/img.jpg?width=384&amp;amp;height=96&amp;amp;face=0_0_384_96,https://scrap.kakaocdn.net/dn/cVmdFo/dJMb8QMkpJO/bIlUrvR71rSPmRjnC0k45K/img.jpg?width=384&amp;amp;height=96&amp;amp;face=0_0_384_96,https://scrap.kakaocdn.net/dn/OqYVL/dJMb8Z3zIFP/OhfZTlPV9jT4deKIBuUFeK/img.png?width=1079&amp;amp;height=670&amp;amp;face=0_0_1079_670&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/coder-05-manage-item-and-data-in-an-unreal-engine-game?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/coder-05-manage-item-and-data-in-an-unreal-engine-game?lang=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b4sRet/dJMb8WMxWpH/F5PSycUAjCniJE8klncC81/img.jpg?width=384&amp;amp;height=96&amp;amp;face=0_0_384_96,https://scrap.kakaocdn.net/dn/cVmdFo/dJMb8QMkpJO/bIlUrvR71rSPmRjnC0k45K/img.jpg?width=384&amp;amp;height=96&amp;amp;face=0_0_384_96,https://scrap.kakaocdn.net/dn/OqYVL/dJMb8Z3zIFP/OhfZTlPV9jT4deKIBuUFeK/img.png?width=1079&amp;amp;height=670&amp;amp;face=0_0_1079_670');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Coder 05 Manage Item and Data in an Unreal Engine Game | Unreal Engine 5.7 Documentation | Epic Developer Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Learn to use Item Data Structs, Data Assets, and Data Tables to define items and store and organize item data for scalability in Unreal Engine.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.epicgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a4&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;스폰에 확률 적용하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣ &lt;b&gt;데이터 테이블을 사용하여 스폰 로직 구현하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SpawnVolume 클래스로 돌아와서, 확률 로직으로 &amp;ldquo;어떤 아이템을 스폰할지&amp;rdquo; 결정하는 코드로 다시 수정을 해봅시다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;SpawnRandomItem()&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;ldquo;데이터 테이블에서 확률 계산으로 &lt;b&gt;Row 하나 선택&lt;/b&gt;&amp;rdquo; + &amp;ldquo;&lt;b&gt;스폰&lt;/b&gt;&amp;rdquo;을 분리해놓아 코드가 깔끔해집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GetRandomItem()&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테이블의 모든 Row를 가져와 확률합을 구하고, 확률에 따라 한 개를 뽑아 리턴합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Algo::Accumulate&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;언리얼 엔진에서 추가한 C++ 템플릿 함수로, STL의 std::accumulate와 유사하게 작동합니다.&lt;/li&gt;
&lt;li&gt;각 Row의 SpawnChance를 계속 더해 총 합을 구합니다.&lt;/li&gt;
&lt;li&gt;이것을 이용해서 누적형태로 랜덤 뽑기를 실행합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 14px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-tr-rsts=&quot;false&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 14px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 14px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-streaming-container=&quot;&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 14px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-processed=&quot;true&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 14px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-scope-id=&quot;turn&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 14px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot; data-subtree=&quot;aimc&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 14px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAAIARAA&quot; data-ved=&quot;2ahUKEwisw_uwtf6UAxVBsFYBHbKDEF0Q2O0OegYIAAgBEAA&quot; data-sfc-cb=&quot;&quot; data-wiz-uids=&quot;SO7knf_3&quot; data-sfc-root=&quot;c&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 14px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 14px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-processed=&quot;true&quot; data-ved=&quot;2ahUKEwisw_uwtf6UAxVBsFYBHbKDEF0Q3KYQegYIAAgBEAE&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-xid=&quot;VpUvz&quot; data-container-id=&quot;main-col&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-processed=&quot;true&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAAIAhAA&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-processed=&quot;true&quot; data-subtree=&quot;aimfl&quot;&gt;누적 확률 방식을 사용하는 이유는 컴퓨터가 &lt;/span&gt;&lt;b&gt;연속된 난수(Random Number)를 단 한 번만 생성하여 여러 항목 중 하나를 가장 빠르고 정확하게 결정&lt;/b&gt;할 수 있기 때문입니다.&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-processed=&quot;true&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAAIAhAA&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-processed=&quot;true&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-sae=&quot;&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAAIBBAA&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;컴퓨터 친화적 계산&lt;/b&gt;: 컴퓨터는 0과 1 사이의 소수나 0~100 사이의 난수를 만드는 데 최적화되어 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-sae=&quot;&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAAIBBAB&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;단 한 번의 난수 생성&lt;/b&gt;: 주사위를 여러 번 굴릴 필요 없이, 단 하나의 숫자로 당첨자를 바로 판별합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-sae=&quot;&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAAIBBAC&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;유연한 확률 제어&lt;/b&gt;: 소수점 단위의 아주 미세한 확률(예: 0.001%)도 완벽하게 구현할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-processed=&quot;true&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAAIAhAA&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 20px; font-weight: 600; margin: 24px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-sae=&quot;&quot; data-processed=&quot;true&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot; data-animation-nesting=&quot;&quot;&gt;장점&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-processed=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sae=&quot;&quot; data-hveid=&quot;CAAIBhAA&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;빠른 속도 (성능 우수)&lt;/b&gt;: 데이터를 정렬해 두면 이진 탐색(Binary Search) 알고리즘을 통해 수만 개의 아이템 중에서도 당첨 항목을 눈 깜짝할 사이에 찾습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-sae=&quot;&quot; data-processed=&quot;true&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAAIBhAD&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;확률 수정의 용이성&lt;/b&gt;: 특정 아이템의 가중치만 바꾸면 전체 누적 합산만 다시 계산하면 되므로 기획 변경에 유연합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sae=&quot;&quot; data-processed=&quot;true&quot; data-hveid=&quot;CAAIBhAG&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;정확성&lt;/b&gt;: 모든 확률의 총합이 100%가 되지 않더라도(예: 가중치 합이 450), 전체 가중치 합을 기준으로 난수를 만들면 비율에 맞춰 정확히 작동합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 20px; font-weight: 600; margin: 24px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-sae=&quot;&quot; data-processed=&quot;true&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot; data-animation-nesting=&quot;&quot;&gt;단점&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-processed=&quot;true&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-sae=&quot;&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAAICBAA&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;데이터 관리 비용&lt;/b&gt;: 아이템이 추가되거나 삭제될 때마다 누적 확률 배열을 매번 새로 계산(업데이트)해야 합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px 0px 12px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-sae=&quot;&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAAICBAB&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;span data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-complete=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;직관성 부족&lt;/b&gt;: 코드를 처음 보는 개발자나 기획자에게는 단순 주사위 굴리기 방식보다 직관적으로 이해하기 어려울 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&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 data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 0px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-processed=&quot;true&quot; data-subtree=&quot;aimfl&quot;&gt;천장 시스템(Pity System 혹은 보정 확률) 사용자가 일정 횟수 이상 실패했을 때 &lt;/span&gt;&lt;b&gt;최고 등급 아이템의 당첨 확률을 강제로 높이거나 확정 지급&lt;/b&gt;하는 안전장치를 구현하기도 합니다.&lt;/p&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-processed=&quot;true&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAAIAhAA&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;
&lt;pre id=&quot;code_1781154740583&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pragma once

#include &quot;CoreMinimal.h&quot;
#include &quot;GameFramework/Actor.h&quot;
#include &quot;ItemSpawnRow.h&quot;       // 우리가 정의한 구조체

#include &quot;SpawnVolume.generated.h&quot;

class UBoxComponent;

UCLASS()
class BC_CH3_ASSIGNMENT_5_API ASpawnVolume : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ASpawnVolume();
	
	UFUNCTION(BlueprintCallable, Category = &quot;Spawning&quot;)
	void SpawnRandomItem();
	
protected:
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=&quot;Spawning&quot;)
    USceneComponent* Scene;
    // 스폰 영역을 담당할 박스 컴포넌트
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=&quot;Spawning&quot;)
    UBoxComponent* SpawningBox;
	
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = &quot;Spawning&quot;)
	UDataTable* ItemDataTable;
	
	
	
	//
	FItemSpawnRow* GetRandomItem() const;
	
	// 특정 아이템 클래스를 스폰하는 함수
	UFUNCTION(BlueprintCallable, Category=&quot;Spawning&quot;)
	void SpawnItem(TSubclassOf&amp;lt;AActor&amp;gt; ItemClass);
	
	// 스폰 볼륨 내부에서 무작위 좌표를 얻어오는 함수
	UFUNCTION(BlueprintCallable, Category=&quot;Spawning&quot;)
	FVector GetRandomPointInVolume() const;	
	
	
};​&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-processed=&quot;true&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAAIAhAA&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-processed=&quot;true&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAAIAhAA&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;
&lt;pre id=&quot;code_1781154754579&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;SpawnVolume.h&quot;
#include &quot;Components/BoxComponent.h&quot;
#include &quot;Engine/World.h&quot;
#include &quot;GameFramework/Actor.h&quot;

ASpawnVolume::ASpawnVolume()
{
	PrimaryActorTick.bCanEverTick = false;

	// 박스 컴포넌트를 생성하고, 이 액터의 루트로 설정
	Scene = CreateDefaultSubobject&amp;lt;USceneComponent&amp;gt;(TEXT(&quot;Scene&quot;));
	SetRootComponent(Scene);
    
	SpawningBox = CreateDefaultSubobject&amp;lt;UBoxComponent&amp;gt;(TEXT(&quot;SpawningBox&quot;));
	SpawningBox-&amp;gt;SetupAttachment(Scene);
}

void ASpawnVolume::SpawnRandomItem()
{
	if (FItemSpawnRow* SelectedRow = GetRandomItem())
	{
		if (UClass* ActualClass = SelectedRow-&amp;gt;ItemClass.Get())
		{
			SpawnItem(ActualClass);
		}
	}
} 

FVector ASpawnVolume::GetRandomPointInVolume() const
{
	// 1) 박스 컴포넌트의 스케일된 Extent, 즉 x/y/z 방향으로 반지름(절반 길이)을 구함
	FVector BoxExtent = SpawningBox-&amp;gt;GetScaledBoxExtent();
	// 2) 박스 중심 위치
	FVector BoxOrigin = SpawningBox-&amp;gt;GetComponentLocation();

	// 3) 각 축별로 -Extent ~ +Extent 범위의 무작위 값 생성
	return BoxOrigin + FVector(
		FMath::FRandRange(-BoxExtent.X, BoxExtent.X),
		FMath::FRandRange(-BoxExtent.Y, BoxExtent.Y),
		FMath::FRandRange(-BoxExtent.Z, BoxExtent.Z)
	);
}


FItemSpawnRow* ASpawnVolume::GetRandomItem() const
{
	if (!ItemDataTable) 
		return nullptr;

	
	// 1) 모든 Row(행) 가져오기
	TArray&amp;lt;FItemSpawnRow*&amp;gt; AllRows;
	static const FString ContextString(TEXT(&quot;ItemSpawnContext&quot;)); // 디버깅 용도
	ItemDataTable-&amp;gt;GetAllRows(ContextString, AllRows);

	if (AllRows.IsEmpty()) return nullptr; 

	// 2) 전체 확률 합 구하기
	float TotalChance = 0.0f; // 초기화
	for (const FItemSpawnRow* Row : AllRows) // AllRows 배열의 각 Row를 순회
	{
		if (Row) // Row가 유효한지 확인
		{
			TotalChance += Row-&amp;gt;SpawnChance; // SpawnChance 값을 TotalChance에 더하기
		}
	}

	// 3) 0 ~ TotalChance 사이 랜덤 값
	const float RandValue = FMath::FRandRange(0.0f, TotalChance);
	float AccumulateChance = 0.0f; // 랜덤 값 보정
	//Algo::Accumulate( AllRows, AccumulateChance)
	
	// 4) 누적 확률로 아이템 선택
	for (FItemSpawnRow* Row : AllRows)
	{
		AccumulateChance += Row-&amp;gt;SpawnChance;
		if (RandValue &amp;lt;= AccumulateChance)
		{
			return Row;
		}
	}

	return nullptr;
}

void ASpawnVolume::SpawnItem(TSubclassOf&amp;lt;AActor&amp;gt; ItemClass)
{
	if (!ItemClass) return;

	GetWorld()-&amp;gt;SpawnActor&amp;lt;AActor&amp;gt;(
		ItemClass,
		GetRandomPointInVolume(),
		FRotator::ZeroRotator
	);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-processed=&quot;true&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAAIAhAA&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div data-copy-service-computed-style=&quot;font-family: Arial, sans-serif; font-size: 16px; font-weight: 400; margin: 12px 0px 16px; text-decoration: none; border-bottom: 0px rgb(230, 232, 240);&quot; data-processed=&quot;true&quot; data-complete=&quot;true&quot; data-hveid=&quot;CAAIAhAA&quot; data-sfc-cb=&quot;&quot; data-sfc-root=&quot;c&quot; data-sfc-cp=&quot;&quot;&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&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;후,&amp;nbsp;BP_SpawnVolume&amp;nbsp;로&amp;nbsp;돌아가서,&amp;nbsp;속성에서&amp;nbsp;Item&amp;nbsp;Data&amp;nbsp;Table에도&amp;nbsp;기존에&amp;nbsp;만들어둔&amp;nbsp;데이터테이블인&amp;nbsp;ItemSpawnTable&amp;nbsp;에셋을&amp;nbsp;할당해줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1760&quot; data-origin-height=&quot;663&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AyRcv/dJMcaci4ZXB/bcEJWZITAFPX7N6xJxX5K1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AyRcv/dJMcaci4ZXB/bcEJWZITAFPX7N6xJxX5K1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AyRcv/dJMcaci4ZXB/bcEJWZITAFPX7N6xJxX5K1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAyRcv%2FdJMcaci4ZXB%2FbcEJWZITAFPX7N6xJxX5K1%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;1760&quot; height=&quot;663&quot; data-origin-width=&quot;1760&quot; data-origin-height=&quot;663&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;이벤트&amp;nbsp;그래프&amp;nbsp;SpawnRandomItem()&amp;nbsp;함수를&amp;nbsp;스크린샷과&amp;nbsp;같이&amp;nbsp;10번의&amp;nbsp;호출을&amp;nbsp;하도록&amp;nbsp;로직&amp;nbsp;노드를&amp;nbsp;생성합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;575&quot; data-origin-height=&quot;170&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvnfJw/dJMcahLvmea/kk3KUzrBZjn2LAckTVqEJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvnfJw/dJMcahLvmea/kk3KUzrBZjn2LAckTVqEJK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvnfJw/dJMcahLvmea/kk3KUzrBZjn2LAckTVqEJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvnfJw%2FdJMcahLvmea%2Fkk3KUzrBZjn2LAckTVqEJK%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;575&quot; height=&quot;170&quot; data-origin-width=&quot;575&quot; data-origin-height=&quot;170&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;이후&amp;nbsp;플레이를&amp;nbsp;해보면&amp;nbsp;확률에&amp;nbsp;따라&amp;nbsp;5개의&amp;nbsp;아이템이&amp;nbsp;스폰되는&amp;nbsp;것을&amp;nbsp;확인할&amp;nbsp;수&amp;nbsp;있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Sslhj/dJMcagshWfD/vrvy3tnK6j1FHmEFxBDEwK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Sslhj/dJMcagshWfD/vrvy3tnK6j1FHmEFxBDEwK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Sslhj/dJMcagshWfD/vrvy3tnK6j1FHmEFxBDEwK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/Sslhj/dJMcagshWfD/vrvy3tnK6j1FHmEFxBDEwK/img.gif&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;640&quot; height=&quot;360&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;360&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;h2 data-ke-size=&quot;size26&quot;&gt;2️⃣ &lt;b&gt;레벨마다 다른 확률 데이터 적용하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;원래 기획 취지에 의하면 레벨별로 다른 확률&lt;/b&gt;을 가져야 합니다. 이를 구현하는 방법은 여러 가지가 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.레벨별로 서로 다른 DataTable 에셋을 사용&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CSV(또는 JSON)에 각각 다른 확률을 넣고, 레벨1 맵에서는 BP_SpawnVolume가 ItemSpawnTable_Level1을 바라보도록 설정.&lt;/li&gt;
&lt;li&gt;레벨2 맵에서는 ItemSpawnTable_Level2 할당&amp;hellip; 등등.&lt;/li&gt;
&lt;li&gt;관리가 직관적이며 간단합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2.단일 DataTable에 &amp;ldquo;레벨 구분&amp;rdquo; 컬럼 추가&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예: CSV에 LevelIndex (또는 LevelName) 같은 컬럼을 하나 더 두고, 각각 어느 레벨에 해당하는지 적습니다.&lt;/li&gt;
&lt;li&gt;코드를 수정하여, 현재 레벨이 1인지 2인지 확인 후 &amp;ldquo;필터링된 Row만&amp;rdquo; 확률 계산.&lt;/li&gt;
&lt;li&gt;한 DataTable에서 모든 레벨 정보를 한 번에 관리할 수 있는 장점이 있으나, 코드가 약간 복잡해집니다.&lt;/li&gt;
&lt;/ul&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;h3 id=&quot;a4&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;번외 | GetWorld() 관련 찾아본 내용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;액터 생성 (SpawnActor):&lt;/b&gt; 월드에 새로운 액터나 캐릭터를 동적으로 스폰할 때 사용합니다.코드를 사용할 때는 주의가 필요합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GetWorld()-&amp;gt;SpawnActor&amp;lt;AMyActor&amp;gt;(ActorClass, Location, Rotation);&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;타이머 매니저 (TimerManager):&lt;/b&gt; 일정 시간 뒤에 함수를 실행하거나 주기적으로 반복하는 타이머를 설정/해제합니다.코드를 사용할 때는 주의가 필요합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GetWorld()-&amp;gt;GetTimerManager().SetTimer(TimerHandle, this, &amp;amp;AMyClass::MyFunction, 2.0f, false);&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;게임 인스턴스 접근 (GetGameInstance):&lt;/b&gt; 씬 전환 시에도 유지되는 전역 데이터나 서브시스템을 가져올 때 사용합니다.코드를 사용할 때는 주의가 필요합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UGameInstance* GameInst = GetWorld()-&amp;gt;GetGameInstance();GetWorld()를 통해 게임 내 가상 공간의 인스턴스에 접근하고, 월드와 상호작용하는 다양한 관리자 및 시스템 함수를 사용할 수 있습니다. 주로 액터(Actor)나 컴포넌트(Component) 내부에서 사용됩니다.GetWorld()-&amp;gt; 뒤에 포인터 접근 연산자(-&amp;gt;)를 붙여 아래와 같은 기능들을 주로 호출합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p 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-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;nullptr 반환 가능성:&lt;/b&gt; 월드에 아직 배치되지 않은 순수 UObject나 일부 애니메이션 노티파이(NotifyState) 등에서는 GetWorld()가 유효하지 않아 nullptr을 반환할 수 있습니다. 호출 전 if (GetWorld() != nullptr) 검사를 하거나, 유효한 액터를 통해 간접 참조해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;오브젝트에서 사용:&lt;/b&gt; 기본 UObject 클래스에서 GetWorld()를 사용하려면 클래스 기본 생성자 설정에서 bWantsInitializeOnBeginPlay를 활성화하거나 가상 함수를 오버라이딩해야 정상적으로 월드를 반환받을 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
언리얼 엔진의 전체적인 월드 관리 시스템에 대한 더 자세한 내용은 언리얼 엔진 UWorld API 문서를 참고할 수 있습니다.&lt;/li&gt;
&lt;/ul&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;b&gt;주요 활용 기능&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;언리얼 엔진(UE)에서 GetWorld()-&amp;gt;는 &lt;b&gt;현재 게임 월드(UWorld) 객체에 접근하기 위해 호출하는 핵심 함수&lt;/b&gt;입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #5b63fb; font-weight: bold; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;추천&lt;/span&gt;&lt;/h3&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;b&gt;SpawnActor 관련 UE 공식문서&lt;/b&gt;: &lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/spawning-actors-in-unreal-engine?lang=ko&quot;&gt;https://dev.epicgames.com/documentation/unreal-engine/spawning-actors-in-unreal-engine?lang=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781146236002&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Spawning Actors in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&quot; data-og-description=&quot;Methods of creating new instances of Actors in gameplay code.&quot; data-og-host=&quot;dev.epicgames.com&quot; data-og-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/spawning-actors-in-unreal-engine?lang=ko&quot; data-og-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/spawning-actors-in-unreal-engine&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dZ7x1t/dJMb9dHwpR6/kiIjxjDkkE1fPkh5zj0TsK/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/bcgVam/dJMb81G5INQ/pBJp25rhy865hcnSrbBdT0/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/bg4EDr/dJMb82eVhbl/ktsLzaz0MQ50jvEslDI3N1/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/spawning-actors-in-unreal-engine?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/spawning-actors-in-unreal-engine?lang=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dZ7x1t/dJMb9dHwpR6/kiIjxjDkkE1fPkh5zj0TsK/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/bcgVam/dJMb81G5INQ/pBJp25rhy865hcnSrbBdT0/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/bg4EDr/dJMb82eVhbl/ktsLzaz0MQ50jvEslDI3N1/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Spawning Actors in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Methods of creating new instances of Actors in gameplay code.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.epicgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;b&gt;데이터 테이블 관련 UE 공식 문서&lt;/b&gt;: &lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/coder-05-manage-item-and-data-in-an-unreal-engine-game?lang=ko&quot;&gt;https://dev.epicgames.com/documentation/unreal-engine/coder-05-manage-item-and-data-in-an-unreal-engine-game?lang=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781147826338&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Coder 05 Manage Item and Data in an Unreal Engine Game | Unreal Engine 5.7 Documentation | Epic Developer Community&quot; data-og-description=&quot;Learn to use Item Data Structs, Data Assets, and Data Tables to define items and store and organize item data for scalability in Unreal Engine.&quot; data-og-host=&quot;dev.epicgames.com&quot; data-og-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/coder-05-manage-item-and-data-in-an-unreal-engine-game?lang=ko&quot; data-og-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/coder-05-manage-item-and-data-in-an-unreal-engine-game&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b4sRet/dJMb8WMxWpH/F5PSycUAjCniJE8klncC81/img.jpg?width=384&amp;amp;height=96&amp;amp;face=0_0_384_96,https://scrap.kakaocdn.net/dn/cVmdFo/dJMb8QMkpJO/bIlUrvR71rSPmRjnC0k45K/img.jpg?width=384&amp;amp;height=96&amp;amp;face=0_0_384_96,https://scrap.kakaocdn.net/dn/OqYVL/dJMb8Z3zIFP/OhfZTlPV9jT4deKIBuUFeK/img.png?width=1079&amp;amp;height=670&amp;amp;face=0_0_1079_670&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/coder-05-manage-item-and-data-in-an-unreal-engine-game?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/coder-05-manage-item-and-data-in-an-unreal-engine-game?lang=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b4sRet/dJMb8WMxWpH/F5PSycUAjCniJE8klncC81/img.jpg?width=384&amp;amp;height=96&amp;amp;face=0_0_384_96,https://scrap.kakaocdn.net/dn/cVmdFo/dJMb8QMkpJO/bIlUrvR71rSPmRjnC0k45K/img.jpg?width=384&amp;amp;height=96&amp;amp;face=0_0_384_96,https://scrap.kakaocdn.net/dn/OqYVL/dJMb8Z3zIFP/OhfZTlPV9jT4deKIBuUFeK/img.png?width=1079&amp;amp;height=670&amp;amp;face=0_0_1079_670');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Coder 05 Manage Item and Data in an Unreal Engine Game | Unreal Engine 5.7 Documentation | Epic Developer Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Learn to use Item Data Structs, Data Assets, and Data Tables to define items and store and organize item data for scalability in Unreal Engine.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.epicgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/pages/Unreal-Engine-%EC%96%B8%EB%A6%AC%EC%96%BC-%EC%97%94%EC%A7%84&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;[페이지] Unreal Engine | 언리얼 엔진&lt;/b&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Unreal Engine/UE 기초</category>
      <category>C++</category>
      <category>Devlog</category>
      <category>Programming</category>
      <category>UE</category>
      <category>UE5</category>
      <category>Unreal engine</category>
      <category>게임 개발</category>
      <category>기초</category>
      <category>언리얼 엔진</category>
      <category>프로그래밍</category>
      <author>DevCol</author>
      <guid isPermaLink="true">https://devcol.tistory.com/109</guid>
      <comments>https://devcol.tistory.com/109#entry109comment</comments>
      <pubDate>Thu, 11 Jun 2026 15:03:18 +0900</pubDate>
    </item>
    <item>
      <title>충돌 이벤트로 획득되는 아이템 구현하기 | [언리얼 엔진 C++ (Unreal Engine C++)]</title>
      <link>https://devcol.tistory.com/108</link>
      <description>&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;충돌 이벤트로 획득되는 아이템 구현하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ej5QHn/dJMcaiXSgnr/KfGJkKhDto5UPDV0yXfdw1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ej5QHn/dJMcaiXSgnr/KfGJkKhDto5UPDV0yXfdw1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ej5QHn/dJMcaiXSgnr/KfGJkKhDto5UPDV0yXfdw1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/ej5QHn/dJMcaiXSgnr/KfGJkKhDto5UPDV0yXfdw1/img.gif&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;432&quot; height=&quot;243&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;360&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;a href=&quot;https://devcol.tistory.com/107&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781097002981&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;인터페이스 기반 아이템 클래스 설계하기 인터페이스 이해하기1️⃣ 인터페이스란?인터페이스 (Interface)란 클래스 (또는 오브젝트)가 반드시 구현해야 할 함수 목록만을 미리 정의해 두고, 실제 &quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/107&quot; data-og-url=&quot;https://devcol.tistory.com/107&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/IKbwO/dJMb8Z3zEZq/unZA3phNFwQ0zWHxSrSRC0/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/bw5KjA/dJMb8T97TC8/YKA6Q3TxvjnSkYd6MXGSW0/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/dJoLKZ/dJMb8YXTUuR/0QBAw3B6ORrpPKar2HgPLk/img.png?width=997&amp;amp;height=544&amp;amp;face=0_0_997_544&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/107&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/107&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/IKbwO/dJMb8Z3zEZq/unZA3phNFwQ0zWHxSrSRC0/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/bw5KjA/dJMb8T97TC8/YKA6Q3TxvjnSkYd6MXGSW0/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/dJoLKZ/dJMb8YXTUuR/0QBAw3B6ORrpPKar2HgPLk/img.png?width=997&amp;amp;height=544&amp;amp;face=0_0_997_544');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스 기반 아이템 클래스 설계하기 인터페이스 이해하기1️⃣ 인터페이스란?인터페이스 (Interface)란 클래스 (또는 오브젝트)가 반드시 구현해야 할 함수 목록만을 미리 정의해 두고, 실제&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a1&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;충돌&amp;nbsp;(Collision) 이벤트로 획득되는 아이템 구현하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣ &lt;b&gt;충돌 (Collision) 이벤트 기반 아이템 획득 방식 이해하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언리얼 엔진에서 아이템을 &amp;ldquo;플레이어가 가까이 다가가기만 해도 자동으로 획득&amp;rdquo;시키고 싶다면, 보통 &lt;b&gt;콜리전 (충돌) 이벤트&lt;/b&gt;를 사용합니다. 충돌 영역을 설정해두면, 플레이어가 그 영역 안에 들어오거나 나갈 때 자동으로 이벤트를 발생시켜주기 때문에 별도의 함수 호출 없이도 간편하게 처리할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;369&quot; data-origin-height=&quot;373&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blchRQ/dJMcafGWMCy/iAqWciOu6OcATpLPDZViz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blchRQ/dJMcafGWMCy/iAqWciOu6OcATpLPDZViz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blchRQ/dJMcafGWMCy/iAqWciOu6OcATpLPDZViz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblchRQ%2FdJMcafGWMCy%2FiAqWciOu6OcATpLPDZViz0%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;369&quot; height=&quot;373&quot; data-origin-width=&quot;369&quot; data-origin-height=&quot;373&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt;충돌 영역 (Collision Volume)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아이템 액터 주변에 SphereComponent나 BoxComponent 같은 충돌 컴포넌트를 붙여둡니다.&lt;/li&gt;
&lt;li&gt;플레이어가 이 영역 안에 들어오면 &lt;b&gt;Overlap&lt;/b&gt; 이벤트가 발생하고, 이를 감지해 아이템 획득 로직을 실행할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Overlap 이벤트 vs. Hit 이벤트&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Overlap 이벤트&lt;/b&gt;: 물리적으로 부딪히는 것 없이 액터들이 서로 &amp;ldquo;&lt;b&gt;겹치기 시작&lt;/b&gt;&amp;rdquo;했을 때 발생합니다. 아이템 획득, 트리거 존 감지 같은 경우에 주로 사용합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;겹쳤다가 빠져 나갔을 때 등등의 이벤트도 구현되어 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Hit 이벤트&lt;/b&gt;: 실제 물리 충돌이 일어날 때 발생합니다 (예: 탄환이 벽에 부딪히는 장면). 아이템 획득처럼 &amp;ldquo;겹침&amp;rdquo;만 감지하면 되는 경우에는 Overlap 이벤트가 더욱 적합합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;아이템 획득 처리&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;충돌 영역 안에 플레이어가 들어오면 (Overlap 시작 시점), 아이템이 즉시 사라지거나(DestroyItem()), 점수를 올리거나 체력을 회복하는 등 다양한 로직을 실행할 수 있습니다.&lt;/li&gt;
&lt;li&gt;초중급 개발에서 많이 쓰이는 방식으로, 한 번 제대로 설정해두면 매우 편하게 사용할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2️⃣&lt;b&gt;ItemInterface 인터페이스 함수 시그니처 수정&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아이템들이 모두 가져야 할 최소한의 동작을 위한 인터페이스에 Overlap 이벤트 처리에 바인딩할 함수를 수정하도록 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;OnItempOverlap&lt;/b&gt;과 &lt;b&gt;OnItemEndOverlap&lt;/b&gt; 매개변수를 수정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ItemInterface.h&lt;/p&gt;
&lt;pre id=&quot;code_1781101265395&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pragma once

#include &quot;CoreMinimal.h&quot;
#include &quot;UObject/Interface.h&quot;
#include &quot;ItemInterface.generated.h&quot;

// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UItemInterface : public UInterface
{
	GENERATED_BODY()
};


class BC_CH3_ASSIGNMENT_5_API IItemInterface
{
	GENERATED_BODY()
	
public:
	// 구현할 아이템 종류 지뢰 , 힐링, 코인
	// 힐링, 코인: 즉시 발동형 | 오버랩
	// 지뢰: 5초뒤 발동 | 범위 내에 오버랩 
	
	
	// 플레이어가 이 아이템의 범위에 들어왔을 때 호출
	UFUNCTION()
	virtual void OnItemOverlap(
			UPrimitiveComponent* OverlappedComp,
			AActor* OtherActor,
			UPrimitiveComponent* OtherComp,
			int32 OtherBodyIndex,
			bool bFromSweep,
			const FHitResult&amp;amp; SweepResult) = 0;
	
	
	// 플레이어가 이 아이템의 범위를 벗어났을 때 호출
	UFUNCTION()
	virtual void OnItemEndOverlap(
			UPrimitiveComponent* OverlappedComp,
			AActor* OtherActor,
			UPrimitiveComponent* OtherComp,
			int32 OtherBodyIndex) = 0;
	
	
	// 아이템이 사용되었을 때 호출
	virtual void ActivateItem(AActor* Activator) = 0;
	// 이 아이템의 유형(타입)을 반환 (예: &quot;Coin&quot;, &quot;Mine&quot; 등)
	virtual FName GetItemType() const = 0;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt; UPrimitiveComponent* OverlappedComp:&lt;/b&gt; // 자기 자신 (원형) // 현재: 아이템&lt;/li&gt;
&lt;li&gt;&lt;b&gt;AActor* OtherActor&lt;/b&gt;: // 부딪힌 Actor // 현재: 플레이어&lt;/li&gt;
&lt;li&gt;&lt;b&gt;UPrimitiveComponent* OtherComp&lt;/b&gt;:&amp;nbsp; // 부딪힌 Actor에 붙어있던 1차적으로 충돌을 일으킨 원인인 컴포넌트&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UFUNCTION(): 의 경우 Interface 에 만 선언해두면 이후에 받아서 구현하는 클래스는 생략해도됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3️⃣기본 아이템 클래스(BaseItem)에 충돌 컴포넌트와 메시 컴포넌트 추가&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;BaseItem&lt;/b&gt; 클래스는 모든 아이템(코인, 포션, 무기 등)에 공통으로 필요한 기능을 담는 부모 클래스입니다. 여기에는 다음과 같은 컴포넌트와 함수를 포함합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;SceneComponent* Scene;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;액터(아이템)의 &lt;b&gt;루트 컴포넌트&lt;/b&gt;로 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;USphereComponent* Collision;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;플레이어가 범위 안에 들어오면 Overlap 이벤트를 발생시킬 충돌 컴포넌트입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;UStaticMeshComponent* StaticMesh;&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;CollisionComponent-&amp;gt;InitSphereRadius(100.0f);&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테스트용으로 100.0f를 사용했습니다. 실사용 시 적절한 범위로 조정하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CollisionComponent-&amp;gt;SetCollisionProfileName(TEXT(&quot;OverlapAllDynamic&quot;));&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SphereComponent가 다른 액터와 겹칠 때만 Overlap 이벤트를 발생시키도록 설정합니다. 물리적인 충돌(Hit)은 발생하지 않습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;OnComponentBeginOverlap.AddDynamic(this, &amp;amp;ABaseItem::OnItemOverlap);&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;플레이어가 범위 안에 들어올 때 자동으로 OnItemOverlap을 호출합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래는 Collision-&amp;gt;&lt;b&gt;OnComponentBeginOverlap&lt;/b&gt;() ; 인데 문제는 이렇게 할경우 매게변수가 매우 길어서 불편하기 때문에 &lt;b&gt;AddDynamic&lt;/b&gt;를 사용.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Delegate 에 Binding 하는 함수&amp;nbsp;&lt;/li&gt;
&lt;li&gt;관련 UE 공식문서: &lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/dynamic-delegates-in-unreal-engine?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dev.epicgames.com/documentation/unreal-engine/dynamic-delegates-in-unreal-engine?lang=ko&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1781103415438&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Dynamic Delegates in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&quot; data-og-description=&quot;Delegates that can be serialized and support reflection.&quot; data-og-host=&quot;dev.epicgames.com&quot; data-og-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/dynamic-delegates-in-unreal-engine?lang=ko&quot; data-og-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/dynamic-delegates-in-unreal-engine&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cyKEUv/dJMb81f0RKp/jHBEECeAU3fsKCTIcobz4K/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/bfG0HH/dJMb86n5PwP/9G01OfOBjdRrFppLH7JHtk/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/egrrkw/dJMb83SrdIu/111kh86IWp6bhUFyA5RXKK/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/dynamic-delegates-in-unreal-engine?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/dynamic-delegates-in-unreal-engine?lang=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cyKEUv/dJMb81f0RKp/jHBEECeAU3fsKCTIcobz4K/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/bfG0HH/dJMb86n5PwP/9G01OfOBjdRrFppLH7JHtk/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/egrrkw/dJMb83SrdIu/111kh86IWp6bhUFyA5RXKK/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Dynamic Delegates in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Delegates that can be serialized and support reflection.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.epicgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;b&gt;Event Binding의 장점&lt;/b&gt;&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;BaseItem.h&lt;/p&gt;
&lt;pre id=&quot;code_1781101285656&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pragma once

#include &quot;CoreMinimal.h&quot;
#include &quot;GameFramework/Actor.h&quot;
#include &quot;ItemInterface.h&quot;  // 만들어둔 인터페이스 헤더 포함

#include &quot;BaseItem.generated.h&quot;

class USphereComponent;

UCLASS()
class BC_CH3_ASSIGNMENT_5_API ABaseItem : public AActor, public IItemInterface
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ABaseItem();

protected:
	// 아이템 유형(타입)을 편집 가능하게 지정
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Item&quot;)
	FName ItemType;
	
	// 루트 컴포넌트 (씬)
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Item|Component&quot;)
	USceneComponent* Scene;
	// 충돌 컴포넌트 (플레이어 진입 범위 감지용)
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Item|Component&quot;)
	USphereComponent* Collision;
	// 아이템 시각 표현용 스태틱 메시
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Item|Component&quot;)
	UStaticMeshComponent* StaticMesh;
	
	virtual void OnItemOverlap(
			UPrimitiveComponent* OverlappedComp,
			AActor* OtherActor,
			UPrimitiveComponent* OtherComp,
			int32 OtherBodyIndex,
			bool bFromSweep,
			const FHitResult&amp;amp; SweepResult) override;
	virtual void OnItemEndOverlap(
			UPrimitiveComponent* OverlappedComp,
			AActor* OtherActor,
			UPrimitiveComponent* OtherComp,
			int32 OtherBodyIndex) override;
	
	virtual void ActivateItem(AActor* Activator) override;
	virtual FName GetItemType() const override;
	
	// 아이템을 제거하는 공통 함수 (추가 이펙트나 로직을 넣을 수 있음)
	virtual void DestroyItem();

};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BaseItem.cpp&lt;/p&gt;
&lt;pre id=&quot;code_1781101296296&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;BaseItem.h&quot;
#include &quot;Components/SphereComponent.h&quot;

ABaseItem::ABaseItem()
{
	PrimaryActorTick.bCanEverTick = false;
    
	// 루트 컴포넌트 생성 및 설정
	Scene = CreateDefaultSubobject&amp;lt;USceneComponent&amp;gt;(TEXT(&quot;Scene&quot;));
	SetRootComponent(Scene);

	// 충돌 컴포넌트 생성 및 설정
	Collision = CreateDefaultSubobject&amp;lt;USphereComponent&amp;gt;(TEXT(&quot;Collision&quot;));
	// 겹침만 감지하는 프로파일 설정
	Collision-&amp;gt;SetCollisionProfileName(TEXT(&quot;OverlapAllDynamic&quot;));
	// 루트 컴포넌트로 설정
	Collision-&amp;gt;SetupAttachment(Scene);
    
	// 스태틱 메시 컴포넌트 생성 및 설정
	StaticMesh = CreateDefaultSubobject&amp;lt;UStaticMeshComponent&amp;gt;(TEXT(&quot;StaticMesh&quot;));
	StaticMesh-&amp;gt;SetupAttachment(Collision);
	// 메시가 불필요하게 충돌을 막지 않도록 하기 위해, 별도로 NoCollision 등으로 설정할 수 있음.

	// Overlap 이벤트 바인딩
	Collision-&amp;gt;OnComponentBeginOverlap.AddDynamic(this, &amp;amp;ABaseItem::OnItemOverlap);
	Collision-&amp;gt;OnComponentEndOverlap.AddDynamic(this, &amp;amp;ABaseItem::OnItemEndOverlap);
}

void ABaseItem::OnItemOverlap(
			UPrimitiveComponent* OverlappedComp,
			AActor* OtherActor, 
			UPrimitiveComponent* OtherComp, 
			int32 OtherBodyIndex, 
			bool bFromSweep, 
			const FHitResult&amp;amp; SweepResult)
{
	// OtherActor가 플레이어인지 확인 (&quot;Player&quot; 태그 활용)
	if (OtherActor &amp;amp;&amp;amp; OtherActor-&amp;gt;ActorHasTag(&quot;Player&quot;))
	{
		GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, FString::Printf(TEXT(&quot;Overlap!!!&quot;)));
		// 아이템 사용 (획득) 로직 호출
		ActivateItem(OtherActor);
	}
}

void ABaseItem::OnItemEndOverlap(
			UPrimitiveComponent* OverlappedComp, 
			AActor* OtherActor, 
			UPrimitiveComponent* OtherComp, 
			int32 OtherBodyIndex)
{
}

void ABaseItem::ActivateItem(AActor* Activator)
{
	GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, FString::Printf(TEXT(&quot;Overlap!!&quot;)));
}

FName ABaseItem::GetItemType() const
{
	return ItemType;
}

void ABaseItem::DestroyItem()
{
	Destroy();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a4&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;아이템 Blueprint 생성 및 콜리전/메시 설정하기&lt;/b&gt;&lt;/h3&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣ &lt;b&gt;아이템 Blueprint 생성 및 Static Mesh 설정&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;C++ 클래스 기반 블루프린트 생성&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C++로 작성한 클래스들을 (BigCoinItem, SmallCoinItem, MineItem, HealingItem 4개만 해당) 언리얼 에디터에서 우클릭 &amp;rarr; Create Blueprint Class based on&amp;hellip;을 선택해 Blueprint를 생성합니다.&lt;/li&gt;
&lt;li&gt;각 아이템들 블루프린트로 상속해서 만들기: BP_BigCoinItem, BP_SmallCoinItem,&amp;nbsp;BP_MineItem, BP_HealingItem&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;174&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/69VvJ/dJMb99NpDsb/YLKZApaDWByTYcs6f5zAHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/69VvJ/dJMb99NpDsb/YLKZApaDWByTYcs6f5zAHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/69VvJ/dJMb99NpDsb/YLKZApaDWByTYcs6f5zAHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F69VvJ%2FdJMb99NpDsb%2FYLKZApaDWByTYcs6f5zAHk%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;225&quot; height=&quot;174&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;174&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt;Static Mesh 및 머티리얼 설정&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Components&lt;/b&gt; 패널에서 StaticMesh (UStaticMeshComponent)를 선택하세요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Details&lt;/b&gt; 패널에서 &lt;b&gt;Static Mesh&lt;/b&gt;를 원하는 에셋으로 설정합니다.&lt;/li&gt;
&lt;li&gt;메시를 선택한 상태에서 &lt;b&gt;Details&lt;/b&gt; 패널을 보면, &lt;b&gt;Material&lt;/b&gt; 항목이 있습니다. 원하는 머티리얼을 적용할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2️⃣ &lt;b&gt;콜리전 범위 (Sphere Radius) 조정&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Components&lt;/b&gt; 패널에서 SphereComponent를 선택하세요. 기본적으로 ABaseItem 클래스 내에서 충돌 컴포넌트가 생성되어 있을 것이며, 이는 BP 상속 시 그대로 노출됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Details 패널에서 크기 조정&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Sphere Radius&lt;/b&gt; (또는 Box의 경우 &lt;b&gt;Box Extent&lt;/b&gt;) 값을 변경하면 충돌 범위를 직관적으로 조절할 수 있습니다.&lt;/li&gt;
&lt;li&gt;범위를 키우거나 줄일 때, 바로 뷰포트 상에서 확인 가능하므로 적절한 크기로 맞추세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3️⃣ 아이템 액터의 콜리전 프리셋 설정&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;콜리전 컴포넌트 설정 확인&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;생성한 BP (예: BP_BigCoin, BP_HealingItem 등)를 더블클릭하여 열고, &lt;b&gt;Components&lt;/b&gt; 패널에서 SphereComponent(또는 BoxComponent)를 선택합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Details&lt;/b&gt; 패널에서 &lt;b&gt;Collision&lt;/b&gt; 섹션을 찾습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Collision Presets&lt;/b&gt;가 어떤 값으로 설정되어 있는지 확인합니다. 부모 클래스(ABaseItem)에서 OverlapAllDynamic로 설정해두었습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;콜리전 프리셋 (Collision Preset)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;언리얼 엔진은 여러 가지 &lt;b&gt;콜리전 프리셋&lt;/b&gt;을 제공합니다. 이 프리셋을 통해 어떤 액터 (또는 채널)와 충돌을 Block할지, Overlap할지, Ignore할지를 손쉽게 설정할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;주요 프리셋 옵션&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;NoCollision&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;충돌을 전혀 감지하지 않으므로, &lt;b&gt;Overlap&lt;/b&gt; 또는 &lt;b&gt;Hit 이벤트&lt;/b&gt;가 발생하지 않습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사용 예시&lt;/b&gt;: 단순 배경 오브젝트(하늘, 장식용 액터 등).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;BlockAll&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 객체와 충돌하여 막게 됩니다. 물리적으로 충돌하지만, Overlap 이벤트는 발생하지 않습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사용 예시&lt;/b&gt;: 벽, 바닥 같은 고정된 장치.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;OverlapAll&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 객체와 &lt;b&gt;Overlap 이벤트&lt;/b&gt;를 발생시킵니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사용 예시&lt;/b&gt;: 트리거 존, 감지 센서, 투명한 오브젝트.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;BlockAllDynamic&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;움직이는 (Dynamic) 객체만 충돌을 막습니다. 고정된 객체와는 충돌하지 않습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사용 예시:&lt;/b&gt; 움직이는 플레이어나 물리 오브젝트와 상호작용하는 문, 벽. 고정된 환경 요소와는 무관하게 작동.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;OverlapAllDynamic&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;움직이는 (Dynamic) 객체와 Overlap 이벤트를 발생시킵니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사용 예시&lt;/b&gt;: 플레이어가 근처에 있는지 확인하는 아이템, 센서. Overlap 이벤트가 필요하지만, 물리 충돌이 필요 없는 경우.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Pawn&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;플레이어나 AI처럼 &lt;b&gt;Pawn 타입&lt;/b&gt; 객체를 대상으로 충돌을 감지하거나 막습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사용 예시:&lt;/b&gt; 플레이어 전용 문, AI 전용 센서.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Custom&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 채널에 대해 충돌 응답(Overlap, Block, Ignore)을 객체별로 세부적으로 설정할 수 있습니다.&lt;/li&gt;
&lt;li&gt;보통은: &lt;b&gt;물리 반응 여부 (Collision Enabled)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;충돌이 켜져 있어도 물리적 반응이 없는 &amp;ldquo;Query Only&amp;rdquo;인지, 물리적인 반응까지 하는 &amp;ldquo;Query and Physics&amp;rdquo;인지 구분할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;NoCollision&lt;/b&gt;: 충돌 비활성화&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Query Only&lt;/b&gt;: Overlap, Hit 등 충돌 이벤트는 감지하지만, 물리적으로 튕기거나 밀리는 반응은 없음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Physics Only&lt;/b&gt;: 물리 반응만 일어나고, 이벤트 (Overlap/Hit)는 발생하지 않음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Query and Physics&lt;/b&gt;: 충돌 이벤트 + 물리 반응 모두 활성화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;b&gt;콜리전 관련 UE 공식문서&lt;/b&gt;: &lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/collision-response-reference-in-unreal-engine?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dev.epicgames.com/documentation/unreal-engine/collision-response-reference-in-unreal-engine?lang=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781102136356&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Collision Response Reference in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&quot; data-og-description=&quot;Reference guide to the Collision Presets section in Unreal Engine.&quot; data-og-host=&quot;dev.epicgames.com&quot; data-og-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/collision-response-reference-in-unreal-engine?lang=ko&quot; data-og-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/collision-response-reference-in-unreal-engine&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bMZbcn/dJMb8Yp3DMX/zCKp19USHwJlI0Bz3gCuHK/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/cnH4iz/dJMb8UHXtcR/fmrLK2DT0fEtPq1DyITIm1/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/KByAM/dJMb8QMkmlA/5CTAcE6G4BBWCmRbrGQ9M1/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/collision-response-reference-in-unreal-engine?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/collision-response-reference-in-unreal-engine?lang=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bMZbcn/dJMb8Yp3DMX/zCKp19USHwJlI0Bz3gCuHK/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/cnH4iz/dJMb8UHXtcR/fmrLK2DT0fEtPq1DyITIm1/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/KByAM/dJMb8QMkmlA/5CTAcE6G4BBWCmRbrGQ9M1/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Collision Response Reference in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Reference guide to the Collision Presets section in Unreal Engine.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.epicgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;h2 data-ke-size=&quot;size26&quot;&gt;4️⃣ 캐릭터 태그 부여 및 콜리전 프리셋 설정&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;플레이어 클래스에 &amp;ldquo;Player&amp;rdquo; 태그 부여&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Details&lt;/b&gt; 패널에서 플레이어 캐릭터를 선택하고, &lt;b&gt;Actor&lt;/b&gt; 섹션의 &lt;b&gt;Tags&lt;/b&gt; 항목에 &quot;Player&quot;를 추가합니다.&lt;/li&gt;
&lt;li&gt;C++ 코드에서 OtherActor-&amp;gt;ActorHasTag(&quot;Player&quot;)를 통해 플레이어인지 간단히 판별할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1596&quot; data-origin-height=&quot;489&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b69Xmi/dJMcag6Soor/PrwviBJqTz3W8K44tjJR0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b69Xmi/dJMcag6Soor/PrwviBJqTz3W8K44tjJR0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b69Xmi/dJMcag6Soor/PrwviBJqTz3W8K44tjJR0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb69Xmi%2FdJMcag6Soor%2FPrwviBJqTz3W8K44tjJR0K%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;1596&quot; height=&quot;489&quot; data-origin-width=&quot;1596&quot; data-origin-height=&quot;489&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt;플레이어 클래스 콜리전 채널 확인&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;BP_SpartaCharacter의 Capsule Component를 선택하고, &lt;b&gt;Details&lt;/b&gt; 패널의 &lt;b&gt;Collision&lt;/b&gt; 섹션을 살펴보세요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Collision Presets&lt;/b&gt;가 Pawn으로 설정되어 있으며, 이는 &amp;ldquo;OverlapAllDynamic&amp;rdquo;와 대체로 호환되어 Overlap 이벤트를 발생시킵니다.&lt;/li&gt;
&lt;li&gt;만약 Overlap 이벤트가 작동하지 않는다면, &lt;b&gt;Project Settings&lt;/b&gt; &amp;gt; &lt;b&gt;Collision&lt;/b&gt; 탭에서 &lt;b&gt;Pawn&lt;/b&gt; 채널과 &lt;b&gt;OverlapAllDynamic&lt;/b&gt; 채널의 상호작용을 재확인하거나 수정해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style2&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a4&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;아이템 클래스 충돌 처리 구현하기&lt;/h3&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;b&gt;아이템 클래스&lt;/b&gt;에서 실제로 Overlap 이벤트가 발생했을 때 어떤 로직을 수행할지 살펴봅시다. 예를 들어 &lt;b&gt;코인 아이템&lt;/b&gt;이라면 점수를 주고, &lt;b&gt;힐링 아이템&lt;/b&gt;이라면 체력을 회복시키며, &lt;b&gt;지뢰 아이템&lt;/b&gt;이라면 폭발 타이머를 돌려서 데미지를 주는 등의 동작을 구현할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣ CoinItem &lt;b&gt;코인 아이템 공통 부모 클래스 충돌 처리&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CoinItem은 &amp;ldquo;코인 아이템이 가져야 할 공통 기능(점수)&amp;rdquo;을 정의하고, 실제 점수 획득은 ActivateItem 함수에서 처리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781106825557&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pragma once

#include &quot;CoreMinimal.h&quot;
#include &quot;BaseItem.h&quot;
#include &quot;CoinItem.generated.h&quot;

UCLASS()
class BC_CH3_ASSIGNMENT_5_API ACoinItem : public ABaseItem
{
	GENERATED_BODY()
	
public:
	ACoinItem();
	
protected:	
	// 코인 획득 시 얻을 점수 (자식 클래스에서 상속받아 값만 바꿔줄 예정)
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Item&quot;)
	int32 PointValue;
	
	
	// 부모 클래스에서 상속받은 ActivateItem 함수를 오버라이드
	virtual void ActivateItem(AActor* Activator) override;
};&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1781106853128&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;CoinItem.h&quot;

ACoinItem::ACoinItem()
{
	// 점수 기본값을 0으로 설정
	PointValue = 0;
	ItemType = &quot;DefaultCoin&quot;;
}

void ACoinItem::ActivateItem(AActor* Activator)
{
	// 플레이어 태그 확인
	if (Activator &amp;amp;&amp;amp; Activator-&amp;gt;ActorHasTag(&quot;Player&quot;))
	{
		// 점수 획득 디버그 메시지
		GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, FString::Printf(TEXT(&quot;Player gained %d points!&quot;), PointValue));
        
		// 부모 클래스 (BaseItem)에 정의된 아이템 파괴 함수 호출
		DestroyItem();
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&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;h2 data-ke-size=&quot;size26&quot;&gt;2️⃣ BigCoinItem 빅 코인 아이템 충돌 처리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&amp;ldquo;빅 코인&amp;rdquo;&lt;/b&gt; 클래스는 CoinItem을 상속받아 점수만 50으로 설정해주면 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;#include &quot;BigCoinItem.h&quot;

ABigCoinItem::ABigCoinItem()
{
		// 상위 CoinItem의 PointValue를 50으로 덮어쓰기
    PointValue = 50;
    ItemType = &quot;BigCoin&quot;;
}

void ABigCoinItem::ActivateItem(AActor* Activator)
{
    // 부모의 기본 점수 획득 로직 사용
    Super::ActivateItem(Activator);

    // 빅 코인만의 추가 동작(이펙트, 사운드 재생 등)을 여기서 추가할 수 있음
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3️⃣ SmallCoinItem 스몰 코인 아이템 충돌 처리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&amp;ldquo;스몰 코인&amp;rdquo;&lt;/b&gt; 클래스도 CoinItem을 상속받아 점수를 10으로 지정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;#include &quot;SmallCoinItem.h&quot;

ASmallCoinItem::ASmallCoinItem()
{
    PointValue = 10;
    ItemType = &quot;SmallCoin&quot;;
}

void ASmallCoinItem::ActivateItem(AActor* Activator)
{
    // 부모의 기본 점수 획득 로직 사용
    Super::ActivateItem(Activator);

    // 스몰 코인만의 별도 동작은 여기에 추가
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4️⃣ HealingItem &lt;b&gt;힐링 아이템 충돌 처리&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;#pragma once

#include &quot;CoreMinimal.h&quot;
#include &quot;BaseItem.h&quot;
#include &quot;HealingItem.generated.h&quot;

UCLASS()
class SPARTAPROJECT_API AHealingItem : public ABaseItem
{
    GENERATED_BODY()

public
    AHealingItem();

protected:
		// 회복량
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Healing&quot;)
    int32 HealAmount;

    virtual void ActivateItem(AActor* Activator) override;
};&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;#include &quot;HealingItem.h&quot;

AHealingItem::AHealingItem()
{
	HealAmount = 20.0f;
	ItemType = &quot;Healing&quot;;
}

void AHealingItem::ActivateItem(AActor* Activator)
{
	if (Activator &amp;amp;&amp;amp; Activator-&amp;gt;ActorHasTag(&quot;Player&quot;))
	{
		// 회복 디버그 메시지
		GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, 
			//FString::Printf(TEXT(&quot;Player Gained %d HP!&quot;), HealAmount));
			FString::Printf(TEXT(&quot;Player Gained %i HP!&quot;), HealAmount));
        
		DestroyItem();
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이후 Activator가 캐릭터라는 전제하에, 플레이어의 체력 변수 혹은 함수를 호출해 직접 &lt;b&gt;체력 회복&lt;/b&gt;을 처리하는 구현을 해야합니다 (예: PlayerCharacter-&amp;gt;Heal(HealAmount)).&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5️⃣ MineItem (지뢰 아이템) 충돌 처리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이번에는 플레이어가 지뢰 범위에 들어오면 타이머를 시작하고, 일정 시간이 지난 후 폭발 범위 내 액터에게 데미지를 주는 지뢰 아이템입니다.
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;플레이어가 지뢰 발동 범위에 들어가면 지뢰가 활성화되고 타이머가 시작됩니다.&lt;/li&gt;
&lt;li&gt;발동 후 5초가 지나면 폭발하며, 폭발 범위 내에 있는 액터를 확인합니다.&lt;/li&gt;
&lt;li&gt;폭발 범위 내에 있는 액터 중 &lt;b&gt;발동 범위에 남아 있던 액터&lt;/b&gt;에게만 데미지를 입힙니다.&lt;/li&gt;
&lt;li&gt;지뢰는 폭발 후 사라집니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;#pragma once

#include &quot;CoreMinimal.h&quot;
#include &quot;BaseItem.h&quot;
#include &quot;MineItem.generated.h&quot;


UCLASS()
class BC_CH3_ASSIGNMENT_5_API AMineItem : public ABaseItem
{
	GENERATED_BODY()
	
public:
	AMineItem();
	
protected:
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = &quot;Item|Component&quot;)
	USphereComponent* ExplosionCollision;
	
	// 폭발까지 걸리는 시간
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=&quot;Mine&quot;)
	float ExplosionDelay;
	
	// 폭발 범위
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = &quot;Mine&quot;)
	float ExplosionRadius;

	// 폭발 데미지
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=&quot;Mine&quot;)
	int ExplosionDamage;
	
	// 지뢰 발동 여부
	FTimerHandle ExplosionTimerHandle;

	virtual void ActivateItem(AActor* Activator) override;
	
	void Explode();
};&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;bIsActivated&lt;/b&gt;: 이미 지뢰가 발동되었는지 여부를 체크하기 위한 불리언 변수입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ActivateItem&lt;/b&gt;: 발동 이후 타이머를 설정하고, 폭발 함수를 스케줄링합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Explode&lt;/b&gt;: 타이머가 만료되었을 때 실제 폭발 처리를 담당합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;#include &quot;MineItem.h&quot;
#include &quot;Components/SphereComponent.h&quot;

AMineItem::AMineItem()
{
	ExplosionDelay = 5.0f;
	ExplosionRadius = 300.0f;
	ExplosionDamage = 30.0f;
	ItemType = &quot;Mine&quot;;
    
	ExplosionCollision = CreateDefaultSubobject&amp;lt;USphereComponent&amp;gt;(TEXT(&quot;ExplosionCollision&quot;));
	ExplosionCollision-&amp;gt;InitSphereRadius(ExplosionRadius);
	ExplosionCollision-&amp;gt;SetCollisionProfileName(TEXT(&quot;OverlapAllDynamic&quot;));
	ExplosionCollision-&amp;gt;SetupAttachment(Scene);
}

void AMineItem::ActivateItem(AActor* Activator)
{
	// 5초 후 폭발 실행
	GetWorld()-&amp;gt;GetTimerManager().SetTimer(ExplosionTimerHandle, this, &amp;amp;AMineItem::Explode, ExplosionDelay);
}

void AMineItem::Explode()
{
	TArray&amp;lt;AActor*&amp;gt; OverlappingActors;
	ExplosionCollision-&amp;gt;GetOverlappingActors(OverlappingActors);

	for (AActor* Actor : OverlappingActors)
	{
		if (Actor &amp;amp;&amp;amp; Actor-&amp;gt;ActorHasTag(&quot;Player&quot;))
		{
			GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, FString::Printf(TEXT(&quot;Player damaged %d by MineItem&quot;), ExplosionDamage));
		}
	}

	// 지뢰 제거
	DestroyItem();
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;ActivateItem&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GetWorld()-&amp;gt;GetTimerManager().SetTimer를 사용해 5초 후 Explode()가 자동 실행되도록 지연 호출 (Delayed Call)합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Explode()&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;폭발이 일어날 때 주변 액터를 검사해, 지뢰 범위(ExplosionRadius) 안에 있고 &lt;b&gt;지뢰 콜리전 컴포넌트&lt;/b&gt;와 여전히 Overlap 상태인 플레이어에게 데미지를 주는 예시입니다.&lt;/li&gt;
&lt;li&gt;폭발 처리 후 DestroyItem()을 호출해 지뢰 아이템 자체를 제거합니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a4&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;아이템 배치 및 충돌 체크하기&lt;/h3&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣ 콜리전 비주얼 디버깅&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;언리얼 에디터에서 &lt;b&gt;Alt + C&lt;/b&gt; (기본 단축키)로 콜리전 디버그 모드를 켜면, Capsule Component뿐 아니라 Sphere, Box 같은 다른 콜리전 영역도 시각적으로 확인할 수 있습니다.&lt;/li&gt;
&lt;li&gt;콜리전이 비정상적으로 설정되어 있을 경우, 이 기능을 통해 빠르게 확인해 보세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style2&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;a4&quot; style=&quot;border-left: 10px solid #444444; border-bottom: 2px solid #444444; border-top: 10px solid #ffffff; color: #000000; font-weight: bold; margin: 0.5em 0em; padding: 0.2em 1em 0.4em 0.5em; border-radius: 0px; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;UE Collistion 관련 더 괜찮은 방식&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재는 ActorHasTag로 되어있어서, 중간에 Tag 변경, 오타, BP 에 잘못입력 등 실수하거나 확장성에 있어서 안좋기 때문에 추후에는 아래의 방식이 더 선호됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #191a1c; color: #d0d0d0;&quot;&gt;
&lt;pre class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;
void ABaseItem::OnItemOverlap(
			UPrimitiveComponent* OverlappedComp,
			AActor* OtherActor, 
			UPrimitiveComponent* OtherComp, 
			int32 OtherBodyIndex, 
			bool bFromSweep, 
			const FHitResult&amp;amp; SweepResult)
{
	
	/*
	추가 팁: 인터페이스(Interface) 활용하기만약 플레이어뿐만 아니라 '데미지를 입을 수 있는 모든 대상'을 판별하고 싶다면, 
	Cast 대신 언리얼 인터페이스(UInterface)를 사용해 OtherActor-&amp;gt;Implements&amp;lt;UMyDamageInterface&amp;gt;() 형태로 판별하는 것이 아키텍처 관점에서 훨씬 깔끔합니다.
	
	// 싱글 플레이어 게임이거나 0번 로컬 플레이어를 판별할 때 가장 간단하고 직관적인 방법입니다. 충돌한 액터가 현재 월드의 플레이어 폰과 같은지 메모리 주소를 직접 비교합니다.
	// 단점: 멀티플레이어 환경(다른 클라이언트의 플레이어 캐릭터)에서는 작동하지 않을 수 있습니다.
	if (OtherActor &amp;amp;&amp;amp; OtherActor == GetWorld()-&amp;gt;GetFirstPlayerController()-&amp;gt;GetPawn())
	{		
		GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 2.0f, FColor::Blue, FString::Printf(TEXT(&quot;플레이어가 충돌했습니다!!!&quot;)));
	}  
	
	// 멀티플레이어 환경에서 적 플레이어, 아군 플레이어 구분 없이 '유저가 잡고 있는 캐릭터'를 모두 판별해 냅니다. 
	// AI 캐릭터(IsBotControlled)는 자동으로 걸러집니다.
	// #include &quot;GameFramework/Pawn.h&quot; // 다른 곳에서 선언된거랑 가능한한 여기서도 선언해두자
	if (OtherActor)
	{
		// 우선 APawn으로 캐스팅 (모든 캐릭터는 폰의 일종입니다)
		APawn* TouchedPawn = Cast&amp;lt;APawn&amp;gt;(OtherActor);
		
		// 폰이 맞고, 현재 플레이어 컨트롤러가 빙의(Possess)한 상태인지 확인
		if (TouchedPawn &amp;amp;&amp;amp; TouchedPawn-&amp;gt;IsPlayerControlled())
		{
			GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, FString::Printf(TEXT(&quot;플레이어가 조종 중인 액터입니다!!!&quot;)));
		}
	}	
	
	// 플레이어와 AI를 동시에 분기 처리하기
	// 하나의 충돌 함수 안에서 플레이어와 AI를 나누어 각각 다른 로직
	// (예: 플레이어면 UI 연출, AI면 데미지만 처리)을 실행하고 싶다면 다음과 같이 작성합니다.
	
	if (OtherActor)
	{
		APawn* TouchedPawn = Cast&amp;lt;APawn&amp;gt;(OtherActor);
			if (TouchedPawn)
			{
				if (TouchedPawn-&amp;gt;IsPlayerControlled())
				{
					// 실제 플레이어 전용 로직
					UE_LOG(LogTemp, Log, TEXT(&quot;플레이어 충돌&quot;));
				}
				else if (TouchedPawn-&amp;gt;IsBotControlled())
				{
					//  AI 봇 전용 로직
					UE_LOG(LogTemp, Log, TEXT(&quot;AI 캐릭터 충돌&quot;));
				}
			}
	}

	 */
	
	
	// OtherActor가 플레이어인지 확인 (&quot;Player&quot; 태그 활용)
	if (OtherActor &amp;amp;&amp;amp; OtherActor-&amp;gt;ActorHasTag(&quot;Player&quot;))
	{
		GEngine-&amp;gt;AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, FString::Printf(TEXT(&quot;Overlap!!!&quot;)));
		// 아이템 사용 (획득) 로직 호출
		ActivateItem(OtherActor);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&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;h3 id=&quot;a5&quot; style=&quot;background: linear-gradient(to right, #00a0e9, #e4007f); color: #ffffff; font-weight: bold; margin: 0.5em 0em; padding: 15px 20px; border-radius: 20px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;Conclustion&lt;/span&gt;&lt;/b&gt;&lt;/h3&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #5b63fb; font-weight: bold; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;추천&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/107&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781103457480&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&quot; data-og-description=&quot;인터페이스 기반 아이템 클래스 설계하기 인터페이스 이해하기1️⃣ 인터페이스란?인터페이스 (Interface)란 클래스 (또는 오브젝트)가 반드시 구현해야 할 함수 목록만을 미리 정의해 두고, 실제 &quot; data-og-host=&quot;devcol.tistory.com&quot; data-og-source-url=&quot;https://devcol.tistory.com/107&quot; data-og-url=&quot;https://devcol.tistory.com/107&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/IKbwO/dJMb8Z3zEZq/unZA3phNFwQ0zWHxSrSRC0/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/bw5KjA/dJMb8T97TC8/YKA6Q3TxvjnSkYd6MXGSW0/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/dJoLKZ/dJMb8YXTUuR/0QBAw3B6ORrpPKar2HgPLk/img.png?width=997&amp;amp;height=544&amp;amp;face=0_0_997_544&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/107&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devcol.tistory.com/107&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/IKbwO/dJMb8Z3zEZq/unZA3phNFwQ0zWHxSrSRC0/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/bw5KjA/dJMb8T97TC8/YKA6Q3TxvjnSkYd6MXGSW0/img.png?width=244&amp;amp;height=204&amp;amp;face=0_0_244_204,https://scrap.kakaocdn.net/dn/dJoLKZ/dJMb8YXTUuR/0QBAw3B6ORrpPKar2HgPLk/img.png?width=997&amp;amp;height=544&amp;amp;face=0_0_997_544');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스 기반 아이템 클래스 설계하기 인터페이스 이해하기1️⃣ 인터페이스란?인터페이스 (Interface)란 클래스 (또는 오브젝트)가 반드시 구현해야 할 함수 목록만을 미리 정의해 두고, 실제&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devcol.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;콜리전 관련 UE 공식문서: &lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/collision-response-reference-in-unreal-engine?lang=ko&quot;&gt;https://dev.epicgames.com/documentation/unreal-engine/collision-response-reference-in-unreal-engine?lang=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781102136650&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Collision Response Reference in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&quot; data-og-description=&quot;Reference guide to the Collision Presets section in Unreal Engine.&quot; data-og-host=&quot;dev.epicgames.com&quot; data-og-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/collision-response-reference-in-unreal-engine?lang=ko&quot; data-og-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/collision-response-reference-in-unreal-engine&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bMZbcn/dJMb8Yp3DMX/zCKp19USHwJlI0Bz3gCuHK/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/cnH4iz/dJMb8UHXtcR/fmrLK2DT0fEtPq1DyITIm1/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/KByAM/dJMb8QMkmlA/5CTAcE6G4BBWCmRbrGQ9M1/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/collision-response-reference-in-unreal-engine?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/collision-response-reference-in-unreal-engine?lang=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bMZbcn/dJMb8Yp3DMX/zCKp19USHwJlI0Bz3gCuHK/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/cnH4iz/dJMb8UHXtcR/fmrLK2DT0fEtPq1DyITIm1/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/KByAM/dJMb8QMkmlA/5CTAcE6G4BBWCmRbrGQ9M1/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Collision Response Reference in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Reference guide to the Collision Presets section in Unreal Engine.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.epicgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AddDynamic 함수 관련 UE 공식문서: &lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/dynamic-delegates-in-unreal-engine?lang=ko&quot;&gt;https://dev.epicgames.com/documentation/unreal-engine/dynamic-delegates-in-unreal-engine?lang=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781103434283&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Dynamic Delegates in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&quot; data-og-description=&quot;Delegates that can be serialized and support reflection.&quot; data-og-host=&quot;dev.epicgames.com&quot; data-og-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/dynamic-delegates-in-unreal-engine?lang=ko&quot; data-og-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/dynamic-delegates-in-unreal-engine&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cyKEUv/dJMb81f0RKp/jHBEECeAU3fsKCTIcobz4K/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/bfG0HH/dJMb86n5PwP/9G01OfOBjdRrFppLH7JHtk/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/egrrkw/dJMb83SrdIu/111kh86IWp6bhUFyA5RXKK/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335&quot;&gt;&lt;a href=&quot;https://dev.epicgames.com/documentation/unreal-engine/dynamic-delegates-in-unreal-engine?lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.epicgames.com/documentation/unreal-engine/dynamic-delegates-in-unreal-engine?lang=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cyKEUv/dJMb81f0RKp/jHBEECeAU3fsKCTIcobz4K/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/bfG0HH/dJMb86n5PwP/9G01OfOBjdRrFppLH7JHtk/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/egrrkw/dJMb83SrdIu/111kh86IWp6bhUFyA5RXKK/img.png?width=1920&amp;amp;height=335&amp;amp;face=0_0_1920_335');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Dynamic Delegates in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Delegates that can be serialized and support reflection.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.epicgames.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;a href=&quot;https://devcol.tistory.com/pages/Unreal-Engine-%EC%96%B8%EB%A6%AC%EC%96%BC-%EC%97%94%EC%A7%84&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;[페이지] Unreal Engine | 언리얼 엔진&lt;/b&gt;&lt;/a&gt;&lt;/h4&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;</description>
      <category>Unreal Engine/UE 기초</category>
      <category>C++</category>
      <category>Devlog</category>
      <category>Programming</category>
      <category>UE</category>
      <category>UE5</category>
      <category>Unreal engine</category>
      <category>게임 개발</category>
      <category>기초</category>
      <category>언리얼 엔진</category>
      <category>프로그래밍</category>
      <author>DevCol</author>
      <guid isPermaLink="true">https://devcol.tistory.com/108</guid>
      <comments>https://devcol.tistory.com/108#entry108comment</comments>
      <pubDate>Thu, 11 Jun 2026 01:29:41 +0900</pubDate>
    </item>
  </channel>
</rss>