<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>CS Study</title>
        <link>https://velog.io/</link>
        <description>취미로 컴퓨터과학 공부하는 사람</description>
        <lastBuildDate>Wed, 23 Aug 2023 08:44:04 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>CS Study</title>
            <url>https://velog.velcdn.com/images/ryu-rxxt/profile/1c6ce695-63d1-4cf3-9f64-bed6902a8b1a/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. CS Study. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/ryu-rxxt" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[C++ STL] <math.h>와 <cmath>]]></title>
            <link>https://velog.io/@ryu-rxxt/C-STL-math.h%EC%99%80-cmath</link>
            <guid>https://velog.io/@ryu-rxxt/C-STL-math.h%EC%99%80-cmath</guid>
            <pubDate>Wed, 23 Aug 2023 08:44:04 GMT</pubDate>
            <description><![CDATA[<table>
<thead>
<tr>
<th>함수</th>
<th>기능</th>
</tr>
</thead>
<tbody><tr>
<td>sqrt(a)</td>
<td>루트 a</td>
</tr>
<tr>
<td>pow(a,n)</td>
<td>a의 n제곱</td>
</tr>
<tr>
<td>floor(d)</td>
<td>내림</td>
</tr>
<tr>
<td>ceil(d)</td>
<td>올림</td>
</tr>
<tr>
<td>round(d)</td>
<td>반올림</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[Chapter 2-2. 액터의 설계]]></title>
            <link>https://velog.io/@ryu-rxxt/Chapter-2-2.-%EC%95%A1%ED%84%B0%EC%9D%98-%EC%84%A4%EA%B3%84</link>
            <guid>https://velog.io/@ryu-rxxt/Chapter-2-2.-%EC%95%A1%ED%84%B0%EC%9D%98-%EC%84%A4%EA%B3%84</guid>
            <pubDate>Mon, 07 Aug 2023 12:38:25 GMT</pubDate>
            <description><![CDATA[<h1 id="📖액터의-설계">📖액터의 설계</h1>
<h2 id="👨🏭분수대-제작">👨‍🏭분수대 제작</h2>
<h3 id="📌컴포넌트-추가를-위한-설계">📌컴포넌트 추가를 위한 설계</h3>
<p><code>분수대 액터</code>는 <strong>분수대 구조물의 외관과 충돌을 담당할 스태틱메시 컴포넌트와 물의 외관을 담당할 스태틱메시 컴포넌트로 구성</strong>됨. </p>
<p>이때 분수대 구조물 스태틱메시 컴포넌트를 <strong>루트 컴포넌트로 지정</strong>함.</p>
<p><em>C++에서 액터가 두 개의 스태틱메시 컴포넌트를 가지려면</em> <strong>분수대 액터의 멤버 변수로 두 개의 UStaticMeshComponent 클래스의 포인터를 선언</strong>해주어야 함.</p>
<p>참고) 필자는 분수대 C++ 클래스의 이름을 <code>Fountain</code> 으로 명명하였음.</p>
<blockquote>
<p>🚨하단부의 내용이 이해가 안될 경우 <a href="https://velog.io/@ryu-rxxt/Chapter-1.-%EA%B0%9C%EB%B0%9C-%ED%99%98%EA%B2%BD-%EC%84%A4%EC%A0%95">Chapter 1. 개발 환경 설정</a> 참조</p>
</blockquote>
<hr>
<h3 id="📌컴포넌트-추가를-위한-fountainh-헤더-파일-수정">📌컴포넌트 추가를 위한 Fountain.h 헤더 파일 수정</h3>
<p><strong>UStaticMeshComponent 클래스는 포인터로 선언</strong>했으므로 <strong>구현부에서 메모리를 동적으로 할당해 대입할 것</strong>임. </p>
<p>이때 메모리 관리를 위해 <strong>매번 포인터를 직접 소멸시키는 것은 매우 성가신 일</strong>인데
<strong>언리얼 엔진</strong>은 언리얼 실행 환경을 통해 <strong>더 이상 사용되지 않는 객체에 할당된 메모리를 자동으로 소멸시키는 기능을 제공</strong>함. </p>
<p><strong>이 기능을 사용하려면 멤버 변수 선언부 상단에 UPROPERTY 매크로를 작성</strong>해주면 됨. </p>
<p><strong>매크로 선언을 누락할 경우 메모리 누수가 발생해 원인을 파악하기 힘든 에러가 발생</strong>하므로 <strong>항상 잊지 않고 넣어주도록 주의</strong>해야 함. </p>
<p>이때 <strong>UPROPERTY 매크로 안에</strong> <code>VisibleAnywhere</code> <strong>키워드를 추가</strong>하면 <strong>언리얼 에디터 내부의 디테일 창에서 컴포넌트의 속성 편집이 가능</strong>해짐.</p>
<p>최종적인 Fountain.h 헤더 파일의 코드는 아래와 같음.</p>
<pre><code class="language-cpp">// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include &quot;EngineMinimal.h&quot;
#include &quot;GameFramework/Actor.h&quot;
#include &quot;Fountain.generated.h&quot;

UCLASS()
class ARENABATTLE_API AFountain : public AActor
{
    GENERATED_BODY()

public:    
    // Sets default values for this actor&#39;s properties
    AFountain();

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

public:    
    // Called every frame
    virtual void Tick(float DeltaTime) override;

    UPROPERTY(VisibleAnywhere)
    UStaticMeshComponent* Body;

    UPROPERTY(VisibleAnywhere)
    UStaticMeshComponent* Water;
};</code></pre>
<p>자동 생성된 Fountain.h 헤더 파일에서 </p>
<pre><code>#include &quot;CoreMinimal.h&quot;</code></pre><p>를</p>
<pre><code>#include &quot;EngineMinimal.h&quot;</code></pre><p>로 <strong>변경</strong>해주고</p>
<pre><code class="language-cpp">    UPROPERTY()
    UStaticMeshComponent* Body;

    UPROPERTY()
    UStaticMeshComponent* Water;</code></pre>
<p>위의 내용을 <strong>public 멤버 변수 선언부에 추가</strong>해주기만 하면 됨.</p>
<hr>
<h3 id="📌언리얼-오브젝트">📌언리얼 오브젝트</h3>
<p><strong>UPROPERTY() 매크로를 모든 객체에서 사용할 수 있는 것은 아님</strong>.</p>
<p>이 기능은 <code>언리얼 오브젝트</code><strong>라고 하는 객체에서만 사용 가능</strong>함.</p>
<p><code>언리얼 오브젝트</code>는 <strong>언리얼 실행 환경에 의해 관리되는 C++ 객체</strong>를 의미함.</p>
<p><strong>콘텐츠를 구성하는 객체는 모두 언리얼 오브젝트</strong>임.</p>
<hr>
<h3 id="📌c-클래스가-언리얼-오브젝트-클래스가-되기-위한-규칙">📌C++ 클래스가 언리얼 오브젝트 클래스가 되기 위한 규칙</h3>
<ul>
<li><p><code>클래스 선언 매크로</code>: 클래스가 <strong>언리얼 오브젝트임을 선언</strong>하기 위한 매크로. </p>
</li>
<li><p><em>클래스 선언부 윗줄*</em>에 <code>UCLASS</code>라는 <strong>매크로를 선언</strong>하고 </p>
</li>
<li><p><em>클래스 내부*</em>에는 <code>GENERATED_BODY</code> <strong>매크로를 선언</strong>함.</p>
</li>
<li><p><code>클래스 이름 접두사</code>: 항상 <strong>규칙에 맞는 접두사</strong>가 붙어야 함. 
<code>액터 클래스</code>에는 <strong>A 접두사</strong>, <code>액터가 아닌 클래스</code>에는 <strong>U 접두사</strong>가 붙음.</p>
</li>
<li><p><em>분수대는 액터*</em>이므로 <strong>AFountain</strong>, <strong>액터의 구성 요소인 스태틱메시 컴포넌트는 액터가 아니</strong>므로** UStaticMeshComponent**라는 클래스 이름을 가져야 함.</p>
</li>
<li><p><code>generated.h 헤더 파일</code>: <strong>소스 코드를 컴파일하기 이전</strong>에 언리얼 엔진은 <code>언리얼 헤더 툴(Unreal Header Tool)</code>을 사용해 <strong>클래스 선언을 분석하고 언리얼 실행 환경에 필요한 부가 정보를 별도의 파일에 생성</strong>함. 
이때 <strong>언리얼 헤더 툴에 의해 자동으로 생성되는 부가 파일</strong>이 <strong>generated.h 헤더 파일</strong>임.</p>
</li>
<li><p><code>외부 모듈에의 공개 여부</code>: <strong>윈도우의 DLL 시스템</strong>은 <strong>DLL 내 클래스 정보를 외부에 공개할지 결정하는 _declspec(dllexport) 키워드를 제공</strong>함. </p>
</li>
<li><p><em>언리얼 엔진에서 이 키워드를 사용하려면*</em> <code>모듈명_API</code> <strong>키워드를 클래스 선언 앞에 추가</strong>해야 함. <strong>이 키워드가 없으면 다른 모듈에서 해당 객체에 접근 불가</strong>함.</p>
</li>
</ul>
<hr>
<h3 id="📌fountaincpp-파일-수정">📌Fountain.cpp 파일 수정</h3>
<p>앞에서 <strong>분수대 액터의 선언을 위해 Fountain.h 헤더 파일을 수정</strong>함.</p>
<p><strong>Fountain.cpp 파일은 분수대 액터의 정의와 관련된 파일</strong>임.</p>
<p><strong>이 파일에서는 스태틱메시 컴포넌트를 실제로 생성하는 로직을 구현</strong>함.</p>
<p><strong>생성자 코드에서 컴포넌트를 생성</strong>하는 용도로 <strong>언리얼 엔진</strong>은 new가 아닌 <code>CreateDefaultSubobject API 함수</code> <strong>를 제공</strong>함.</p>
<p><strong>분수대 액터의 구축</strong>은 <strong>AFountain 클래스의 생성자 코드</strong>에서 <code>CreateDefaultSubobject API 함수</code> <strong>를 사용하여 진행</strong>함.</p>
<p>또한 <strong>두 컴포넌트를 생성하기 때문에 그 중 액터를 대표할 루트 컴포넌트를 지정</strong>해야 함. 위에서 <strong>분수대 구조물을 루트 컴포넌트로 지정</strong>하기로 했기 때문에 <strong>Body 컴포넌트 루트 컴포넌트로 지정하는 코드도 작성</strong>해주어야 함.</p>
<p>최종적인 Fountain.cpp 파일의 코드는 아래와 같음.</p>
<pre><code class="language-cpp">// Fill out your copyright notice in the Description page of Project Settings.


#include &quot;Fountain.h&quot;

// Sets default values
AFountain::AFountain()
{
     // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don&#39;t need it.
    PrimaryActorTick.bCanEverTick = true;
    Body = CreateDefaultSubobject&lt;UStaticMeshComponent&gt;(TEXT(&quot;BODY&quot;));
    Water = CreateDefaultSubobject&lt;UStaticMeshComponent&gt;(TEXT(&quot;WATER&quot;));

}

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

}

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

}</code></pre>
<p>자동 생성된 Fountain.cpp 파일에서</p>
<pre><code class="language-cpp">    Body = CreateDefaultSubobject&lt;UStaticMeshComponent&gt;(TEXT(&quot;BODY&quot;));
    Water = CreateDefaultSubobject&lt;UStaticMeshComponent&gt;(TEXT(&quot;Water&quot;));

    RootComponent = Body;
    Water-&gt;SetupAttachment(Body);</code></pre>
<p>위의 내용을 <strong>AFountain 생성자 내부에 추가</strong>해주고 <strong>프로젝트 파일을 빌드</strong>해주면 됨.</p>
<hr>
<h3 id="📌참고-createdefaultsubobject-api-함수와-hash-값-생성">📌참고) CreateDefaultSubobject API 함수와 Hash 값 생성</h3>
<p><strong>CreateDefaultSubobject API에 사용하는 문자열 값</strong>은 <strong>액터에 속한 컴포넌트를 구별하기 위한 Hash 값 생성에 사용</strong>됨.</p>
<p>따라서 <strong>문자열 값은 다른 컴포넌트와 중복되지 않는 한 어떤 값을 넣어도 상관없음</strong>.</p>
<p><strong>언리얼 엔진</strong>은 <strong>문자열을 생성할 때 모든 플랫폼에서 동일하게 2바이트 문자열 체계를 유지</strong>시키는 <code>TEXT 매크로</code>를 제공함.</p>
<hr>
<h3 id="📌언리얼-에디터에서-fountain-액터-생성-및-편집">📌언리얼 에디터에서 Fountain 액터 생성 및 편집</h3>
<p><img src="https://velog.velcdn.com/images/ryu-rxxt/post/0bb65c82-d6e8-42f5-942f-1d80c49cebdd/image.png" alt=""></p>
<p>빌드가 완료됐다면 위에 첨부된 사진과 같이 <strong>언리얼 에디터에서 콘텐츠 브라우저&gt;C++ 클래스&gt;Arena Battle 폴더로 이동</strong> 후 <strong>Fountain 액터를 뷰포트로 드래그해 분수대 액터를 생성</strong>하면 됨.</p>
<p>분수대 액터가 정상적으로 생성된 후 뷰포트에 뭔가가 보이진 않지만 <strong>아웃라이너 창과 디테일 창을 확인</strong>해보면 아래의 사진처럼 <code>Fountain1</code> <strong>액터</strong>, 그리고 <code>Body</code>와 <code>Water</code> <strong>스태틱메시 컴포넌트가 생성되어 있는 것을 확인</strong>할 수 있음.</p>
<p><img src="https://velog.velcdn.com/images/ryu-rxxt/post/0c2eae03-e633-4e7e-b57b-05f9844bb88d/image.png" alt=""></p>
<p>이후 분수대 액터의 루트 컴포넌트인 <code>Body</code>를 선택하고 아래 사진처럼 <strong>스태틱메시 섹션의 드롭다운 버튼</strong>을 눌러 <code>SM_Plains_Castle_Fountain_01</code> <strong>애셋을 선택</strong>해주면 분수대가 뷰포트 창에서 보이게 됨.</p>
<p><img src="https://velog.velcdn.com/images/ryu-rxxt/post/6867f9d0-d598-425a-9d10-151576039870/image.png" alt=""></p>
<p>동일한 방법으로 <code>Water</code> 컴포넌트의 <strong>스태틱메시를 선택</strong> 후 드롭다운에서 <code>SM_Plains_Fountain_02</code> <strong>애셋을 선택</strong>한 뒤에 <strong>트랜스폼의 위치 Z값을 135로 변경</strong>하면 아래 사진처럼 물이 흐르는 분수대가 완성됨.</p>
<p><img src="https://velog.velcdn.com/images/ryu-rxxt/post/3e7a4c51-05f0-4023-acc1-ebc0de31d2ab/image.png" alt=""></p>
<p>Z값을 변경하고 난 후 <strong>오른쪽에 생성되는 화살표를 누르면 Z값이 변경하기 이전의 값으로 되돌아감</strong>.</p>
<p>분수대를 바닥면에 붙이려면 <strong>뷰포트에서 분수대 액터를 선택</strong> 후 <code>End</code> <strong>키를 누르면 됨</strong>. 이때 분수대가 <strong>바닥보다 낮은 위치에 있으면 아무런 변화가 없음</strong>.</p>
<hr>
<h3 id="📌액터-기능의-확장">📌액터 기능의 확장</h3>
<h4 id="➡️setrelativelocation을-사용한-액터의-기본값-설정">➡️SetRelativeLocation을 사용한 액터의 기본값 설정</h4>
<p>액터의 생성자에서 Water 컴포넌트에 <code>SetRelativeLocation</code>을 사용하면 <strong>루트 컴포넌트인 Body에 대하여 Water 컴포넌트의 상대적 위치를 결정</strong>해줄 수 있음.</p>
<p><strong>위치의 좌표값</strong>은 _언리얼 엔진이 제공하는 구조체_인 <code>FVector</code>를 <strong>사용하여 전달</strong>함.</p>
<pre><code>    Water-&gt;SetRelativeLocation(FVector(0.0f, 0.0f, 135.0f));</code></pre><p>위의 코드를 <strong>생성자 내부에 추가</strong>해주면 됨.</p>
<p>언리얼 오브젝트의 <strong>생성자 코드에서 설정한 값</strong>은 언리얼 오브젝트의 <strong>기본값</strong>이 됨.</p>
<blockquote>
<p>✅ 클래스 이름에 붙은 <strong>F 접두사</strong>는 <strong>언리얼 오브젝트와 관련없는 일반 C++ 클래스 혹은 구조체</strong>를 의미함.</p>
</blockquote>
<h4 id="➡️조명-및-이펙트-추가">➡️조명 및 이펙트 추가</h4>
<p><strong>조명과 이펙트</strong>는 각각 <code>UPointLightComponent</code>와  <code>UParticleSystemComponent</code> <strong>클래스를 사용</strong>하면 됨.</p>
<p><code>Body</code>와 <code>Water</code>를 선언할 때와 같이 <strong>해당 클래스 포인터로 선언</strong>하고</p>
<p><strong>윗줄에</strong> <code>UPROPERTY(VisibleAnywhere)</code> <strong>키워드를 헤더 파일에 추가</strong>해주면 됨.</p>
<p>최종적인 Fountain.h 헤더 파일의 코드는 아래와 같음.</p>
<pre><code class="language-cpp">// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include &quot;EngineMinimal.h&quot;
#include &quot;GameFramework/Actor.h&quot;
#include &quot;Fountain.generated.h&quot;

UCLASS()
class ARENABATTLE_API AFountain : public AActor
{
    GENERATED_BODY()

public:    
    // Sets default values for this actor&#39;s properties
    AFountain();

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

public:    
    // Called every frame
    virtual void Tick(float DeltaTime) override;

    UPROPERTY(VisibleAnywhere)
    UStaticMeshComponent* Body;

    UPROPERTY(VisibleAnywhere)
    UStaticMeshComponent* Water;

    UPROPERTY(VisibleAnywhere)
    UPointLightComponent* Light;

    UPROPERTY(VisibleAnywhere)
    UParticleSystemComponent* Splash;

};</code></pre>
<p>생성자 코드(Fountain.cpp 파일)에서도 동일하게 </p>
<p><code>CreateDefaultSubobject</code> 함수로 <strong>컴포넌트를 생성</strong>해주고</p>
<p><code>SetupAttachment</code> 함수를 사용해 <strong>루트 컴포넌트의 자식이 되도록 계층 구조를 설정</strong>해준 후</p>
<p><strong>조명과 이펙트의 위치를 조정</strong>해주면 됨.</p>
<p>최종적인 Fountain.cpp 파일의 코드는 아래와 같음.</p>
<pre><code class="language-cpp">// Fill out your copyright notice in the Description page of Project Settings.


#include &quot;Fountain.h&quot;

// Sets default values
AFountain::AFountain()
{
     // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don&#39;t need it.
    PrimaryActorTick.bCanEverTick = true;
    Body = CreateDefaultSubobject&lt;UStaticMeshComponent&gt;(TEXT(&quot;BODY&quot;));
    Water = CreateDefaultSubobject&lt;UStaticMeshComponent&gt;(TEXT(&quot;WATER&quot;));
    Light = CreateDefaultSubobject&lt;UPointLightComponent&gt;(TEXT(&quot;LIGHT&quot;));
    Splash = CreateDefaultSubobject&lt;UParticleSystemComponent&gt;(TEXT(&quot;SPLASH&quot;));

    RootComponent = Body;
    Water-&gt;SetupAttachment(Body);
    Light-&gt;SetupAttachment(Body);
    Splash-&gt;SetupAttachment(Body);

    Water-&gt;SetRelativeLocation(FVector(0.0f, 0.0f, 135.0f));
    Light-&gt;SetRelativeLocation(FVector(0.0f, 0.0f, 195.0f));
    Splash-&gt;SetRelativeLocation(FVector(0.0f, 0.0f, 195.0f));
}

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

}

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

}
</code></pre>
<p><img src="https://velog.velcdn.com/images/ryu-rxxt/post/d1f729db-4802-4e8a-8a14-221299846710/image.png" alt=""></p>
<p>이후 언리얼 에디터에서 <code>Splash</code>를 <strong>선택</strong>한 후</p>
<p><strong>파티클&gt;템플릿</strong>에서 <code>P_Water_Fountain_Splash_Base_01</code> <strong>애셋을 지정</strong>해주면 물이 찰랑이는 효과가 부여됨.</p>
<h4 id="➡️애셋의-지정">➡️애셋의 지정</h4>
<p><strong>애셋 지정</strong>을 언리얼 에디터가 아닌 <strong>C++ 코드에서 하면 애셋이 자동으로 로딩</strong>되도록 할 수 있음.</p>
<p>언리얼 에디터에서 <strong>콘텐츠 브라우저&gt;InfinityBladeGrassLands 폴더를 선택</strong>한 후</p>
<p><strong>검색어로 Fountain을 입력해주면 아래 사진과 같아짐</strong>.</p>
<p><img src="https://velog.velcdn.com/images/ryu-rxxt/post/c440490d-09b9-4394-ad0e-f51b796907f0/image.png" alt=""></p>
<p>이제 분수대에 사용한 <strong>스태틱메시 애셋을 우클릭</strong>해 <code>StaticMesh.h 열기</code> 메뉴를 눌러줌.</p>
<p><img src="https://velog.velcdn.com/images/ryu-rxxt/post/2876daf9-be4a-48d1-af1f-e42056ddb2ee/image.png" alt=""></p>
<p>C++ 코드에서 애셋을 불러들이려면 <strong>애셋의 키 값을 파악</strong>하고 <strong>애셋 관리 시스템에 키 값을 입력해 애셋의 포인터를 가져와야 함</strong>.</p>
<p>언리얼 엔진은 <strong>애셋의 키 값을 경로 값으로 사용</strong>하며, <strong>애셋 위에 마우스를 올려 확인 가능</strong>함.</p>
<p><strong>경로 값을 이용</strong>하려면 <strong>애셋을 우클릭한 후 레퍼런스 복사 메뉴를 선택</strong>하면 됨.</p>
<p>혹은 <strong>애셋을 선택한 후</strong> <code>Ctrl + C</code> <strong>단축키를 눌러도 무방</strong>함.</p>
<p>이후 복사한 레퍼런스를 이용해 아래의 코드를 AFountain 생성자 코드 내에 작성해주면 됨.</p>
<pre><code>ConstructorHelpers::FObjectFinder&lt;UStaticMesh&gt;
    SM_BODY(TEXT(&quot;/Script/Engine.StaticMesh&#39;/Game/InfinityBladeGrassLands/Environments/Plains/Env_Plains_Ruins/StaticMesh/SM_Plains_Castle_Fountain_01.SM_Plains_Castle_Fountain_01&#39;&quot;));</code></pre><p>위의 코드에서 <code>ConstructorHelpers::FObjectFinder</code>는 <code>ConstructorHelpers</code> 클래스의 <code>FObjectFinder</code>를 사용해 <strong>변수를 선언</strong>한다는 의미임. 이 변수에 <strong>경로 값을 전달</strong>하면 됨.</p>
<p>또한 이 변수는 <strong>스태틱메시 애셋의 포인터</strong>이므로 이를 <strong>스태틱메시 컴포넌트의 SetStaticMesh 함수에 전달해주면 기능이 완성</strong>됨.</p>
<p>마지막으로 <strong>애셋의 경로 정보</strong>는 게임 실행 중에 변경되지 않으므로 <strong>static으로 선언해 여러 번 초기화되는 것을 막는 것이 바람직</strong>함.</p>
<p>이 모든 사항을 반영한 최종적인 Fountain.cpp 파일 코드는 아래와 같음.</p>
<pre><code class="language-cpp">// Fill out your copyright notice in the Description page of Project Settings.


#include &quot;Fountain.h&quot;

// Sets default values
AFountain::AFountain()
{
     // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don&#39;t need it.
    PrimaryActorTick.bCanEverTick = true;
    Body = CreateDefaultSubobject&lt;UStaticMeshComponent&gt;(TEXT(&quot;BODY&quot;));
    Water = CreateDefaultSubobject&lt;UStaticMeshComponent&gt;(TEXT(&quot;WATER&quot;));
    Light = CreateDefaultSubobject&lt;UPointLightComponent&gt;(TEXT(&quot;LIGHT&quot;));
    Splash = CreateDefaultSubobject&lt;UParticleSystemComponent&gt;(TEXT(&quot;SPLASH&quot;));

    RootComponent = Body;
    Water-&gt;SetupAttachment(Body);
    Light-&gt;SetupAttachment(Body);
    Splash-&gt;SetupAttachment(Body);

    Water-&gt;SetRelativeLocation(FVector(0.0f, 0.0f, 135.0f));
    Light-&gt;SetRelativeLocation(FVector(0.0f, 0.0f, 195.0f));
    Splash-&gt;SetRelativeLocation(FVector(0.0f, 0.0f, 195.0f));

    static ConstructorHelpers::FObjectFinder&lt;UStaticMesh&gt;
        SM_BODY(TEXT(&quot;/Script/Engine.StaticMesh&#39;/Game/InfinityBladeGrassLands/Environments/Plains/Env_Plains_Ruins/StaticMesh/SM_Plains_Castle_Fountain_01.SM_Plains_Castle_Fountain_01&#39;&quot;));

    if (SM_BODY.Succeeded())
    {
        Body-&gt;SetStaticMesh(SM_BODY.Object);
    }

    static ConstructorHelpers::FObjectFinder&lt;UStaticMesh&gt;
        SM_WATER(TEXT(&quot;/Script/Engine.StaticMesh&#39;/Game/InfinityBladeGrassLands/Effects/FX_Meshes/Env/SM_Plains_Fountain_02.SM_Plains_Fountain_02&#39;&quot;));

    if (SM_WATER.Succeeded())
    {
        Water-&gt;SetStaticMesh(SM_WATER.Object);
    }

    static ConstructorHelpers::FObjectFinder&lt;UParticleSystem&gt;
        PS_SPLASH(TEXT(&quot;/Script/Engine.ParticleSystem&#39;/Game/InfinityBladeGrassLands/Effects/FX_Ambient/Water/P_Water_Fountain_Splash_Base_01.P_Water_Fountain_Splash_Base_01&#39;&quot;));

    if (PS_SPLASH.Succeeded())
    {
        Splash-&gt;SetTemplate(PS_SPLASH.Object);
    }
}

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

}

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

}</code></pre>
<h2 id="📜객체-유형과-값-유형">📜객체 유형과 값 유형</h2>
<p>언리얼 오브젝트의 <strong>속성 값</strong>은 <strong>객체를 관리</strong>하는 <code>객체 유형</code>과 <strong>값을 관리</strong>하는 <code>값 유형</code>으로 나뉨.</p>
<h3 id="📌값-유형">📌값 유형</h3>
<ul>
<li><code>바이트</code>: uint8</li>
<li><code>정수</code>: int32</li>
<li><code>실수</code>: float</li>
<li><code>문자열</code>: FString, FName</li>
<li><code>구조체</code>: FVector, FRotator, FTransform</li>
</ul>
<p>값 유형으로 <strong>클래스 멤버 변수를 선언</strong>하고 <strong>UPROPERTY 매크로를 설정</strong>해주면 매크로 선언과 동시에 미리 예약된 <strong>기본값이 지정</strong>됨. </p>
<p>예를 들어 <strong>정수 유형의 멤버 변수</strong>에 UPROPERTY 매크로 선언 시 <strong>초기 값으로 0이 할당</strong>됨.</p>
<p><strong>값 유형과 객체 유형 모두</strong> <code>VisibleAnywhere</code> 키워드를 사용하면 <strong>해당 속성의 데이터를 변경할 수 없음</strong>.</p>
<p>그러나 객체 유형의 경우, <strong>객체에 속한 속성들은 에디터에서 편집</strong>할 수 있음.</p>
<p>만약 <strong>언리얼 에디터에서 객체의 속성 데이터를 변경</strong>하고 싶다면 <code>UPROPERTY(VisibleAnywhere)</code> 대신 <code>UPROPERTY(EditAnywhere)</code>의 형태로 <strong>EditAnywhere 키워드를 사용</strong>하면 됨.</p>
<hr>
<blockquote>
<p>본 게시글은 &#39;이득우의 언리얼 C++ 게임 개발의 정석&#39; 교재를 참고하여 정리하였음을 알립니다.
본 작성자는 저작권법을 준수하기 위해 최선을 다할 것입니다.
적법하지 않은 내용이 포함되어 있을 경우 작성자에게 알려주시면 시정하겠습니다.
향후 별도의 안내 없이 게시글 내용 일부 수정 혹은 비공개 조치될 수 있음에 양해의 말씀 드립니다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Chapter 2-1. 언리얼 콘텐츠의 구성 요소]]></title>
            <link>https://velog.io/@ryu-rxxt/Chapter-2-1.-%EC%96%B8%EB%A6%AC%EC%96%BC-%EC%BD%98%ED%85%90%EC%B8%A0%EC%9D%98-%EA%B5%AC%EC%84%B1-%EC%9A%94%EC%86%8C</link>
            <guid>https://velog.io/@ryu-rxxt/Chapter-2-1.-%EC%96%B8%EB%A6%AC%EC%96%BC-%EC%BD%98%ED%85%90%EC%B8%A0%EC%9D%98-%EA%B5%AC%EC%84%B1-%EC%9A%94%EC%86%8C</guid>
            <pubDate>Thu, 03 Aug 2023 09:16:02 GMT</pubDate>
            <description><![CDATA[<h1 id="🖥️언리얼-콘텐츠의-구성-요소">🖥️언리얼 콘텐츠의 구성 요소</h1>
<h2 id="🌎월드world">🌎월드(World)</h2>
<h3 id="📌월드의-의미">📌월드의 의미</h3>
<p><img src="https://velog.velcdn.com/images/ryu-rxxt/post/e525d3fe-0243-4994-828a-2fe12583e616/image.png" alt=""></p>
<p>위 사진에서 <strong>붉은색으로 표시된 영역</strong>을 <code>뷰포트</code>라고 부름.</p>
<p><strong>뷰포트 창 내부에 보이는 작업공간</strong>은 <code>월드</code>라고 부름.</p>
<p><code>월드</code>는 <strong>게임 콘텐츠를 구동하기 위해 필요한 필수적인 환경</strong>을 의미함.</p>
<h3 id="📌월드의-구성-요소">📌월드의 구성 요소</h3>
<ul>
<li><p><code>공간(Space)</code>: <strong>가상 세계를 구성하는 3차원 영역</strong>. 게임 콘텐츠를 구성하는 물체가 월드의 영역 내부에 존재하도록 만들기 위해 <code>트랜스폼(Transform)</code>이라 하는 구조체 제공. 기본 단위는 <code>cm</code>.</p>
</li>
<li><p><code>시간(Time)</code>: <strong>가상 공간에서 흐르는 시간</strong>.  현실 세계와 동일하게 <strong>초 단위</strong>로  흘러가지만, 시간을 멈추거나 느리게, 혹은 빠르게 흘러가도록 <strong>시간의 스케일 조절 가능</strong>.</p>
</li>
<li><p><code>물리(Physics)</code>: <strong>월드 공간에 배치된 물체에 작용하는 물리적인 환경</strong>. 가장 대표적인 예시로 <strong>중력</strong>이 있음. <em>공간에 배치된 물체가 월드로부터 물리적인 영향을 받으려면</em> <code>콜리전(Collision)</code> 정보가 있어야 함.</p>
</li>
<li><p><code>렌더링(Rendering)</code>: <strong>엔진이 제공하는 시각적인 기능</strong>. <code>빛(Light)</code>과 이에 반응하는 <code>머티리얼(Material)</code>로 구성. 현실 세계와 유사하게 동작하도록 <code>물리 기반 렌더링 시스템(Physically Based Rendering System)</code> 제공.</p>
</li>
</ul>
<p>이외에도 다양한 기능이 제공되며 아래 사진에서 붉은색 영역으로 표시된 <strong>세팅&gt;월드 세팅</strong> 메뉴를 통해 확인 할 수 있음.
<img src="https://velog.velcdn.com/images/ryu-rxxt/post/52143f82-df86-4bb8-8d30-e383d174f7d6/image.png" alt=""></p>
<hr>
<h2 id="🎞️액터actor">🎞️액터(Actor)</h2>
<h3 id="📌액터의-의미">📌액터의 의미</h3>
<p><code>액터</code>는 언리얼 엔진에서 <strong>콘텐츠를 구성하는 최소 단위의 물체</strong>. </p>
<p>게임 월드의 특정 공간에서 <strong>자신의 역할을 수행하는 물체</strong>를 의미함.</p>
<p><strong>월드에 존재하는 액터들의 목록</strong>은 아래 사진에서 붉은 영역으로 표시된 <code>아웃라이너</code> 창을 통해 확인할 수 있으며, <strong>뷰포트에서 선택한 액터의 속성</strong>은 <code>아웃라이너</code> 창 아래에 위치한 <code>디테일</code> 창을 통해 볼 수 있음.
<img src="https://velog.velcdn.com/images/ryu-rxxt/post/6a0490c7-78ab-49ed-8ca1-fc24eedad33c/image.png" alt=""></p>
<h3 id="📌액터의-구성-요소">📌액터의 구성 요소</h3>
<ul>
<li><p><code>이름</code>: <strong>액터에 부여된 명칭</strong>. 같은 이름을 가질 수 있음.</p>
</li>
<li><p><code>유형</code>: <strong>게임플레이에서 수행할 액터의 역할</strong>. <em>프로그래밍 관점에서는 액터의 클래스 이름</em>.</p>
</li>
<li><p><code>트랜스폼</code>: 액터는 반드시 월드에 존재해야 하므로 항상 트랜스폼이 부여됨.</p>
</li>
<li><p><code>프로퍼티</code>: <strong>액터에 설정된 속성 값</strong>. <strong>액터의 유형에 따라 서로 다른 속성</strong>이 제공됨. <em>속성 값을 디테일 창에서 편집하여 같은 유형의 액터가 서로 다른 일을 하게 만들 수 있음.</em></p>
</li>
<li><p><code>게임 로직</code>: 액터가 <strong>특정 상황에 처했을 때</strong> 이에 대응할 <strong>구체적인 행동을 명령하는 프로그래밍 코드</strong>. <code>블루프린트</code>와 <code>C++</code>이 있음.</p>
</li>
</ul>
<hr>
<h2 id="🎚️레벨level">🎚️레벨(Level)</h2>
<h3 id="📌레벨의-의미">📌레벨의 의미</h3>
<p><code>레벨</code>은 _게임 개발 관점_에서 <strong>플레이어에게 주어지는 스테이지</strong>를 의미함. </p>
<p>_언리얼 엔진_에서는 <strong>월드에 배치된 액터들의 집합</strong>을 의미함.</p>
<p>에디터 뷰포트 공간에서 액터를 만들고 속성을 설정하는 등의 행위는 _플레이어에게 제공할 스테이지를 조립하는 일_인데, 이러한 활동을 <strong>레벨을 설계한다</strong>고 표현함.</p>
<h3 id="📌플레이-기능과-레벨의-테스트">📌플레이 기능과 레벨의 테스트</h3>
<p>레벨을 완성한 후에는 레벨이 잘 동작하는지 <strong>테스트하는 과정</strong>이 필요함. </p>
<p><strong>이를 위해 제공하는 기능</strong>이 <code>플레이</code> 버튼임. </p>
<p><code>플레이</code> 버튼을 누르면 <strong>레벨을 구성하는 기존에 만들어진 액터</strong>와 <strong>플레이어와 관련된 새로운 액터들이 생성</strong>됨. </p>
<p><strong>레벨을 구성하는 기존에 만들어진 액터</strong>는 <strong>흰색</strong>으로 표시되고, </p>
<p><strong>새롭게 생성되는 액터</strong>는 <strong>노란색</strong>으로 표시됨.</p>
<p>아래 사진에서 붉은색 영역으로 표시된 부분이 플레이 버튼임.
<img src="https://velog.velcdn.com/images/ryu-rxxt/post/e6a8ffe7-1e37-4856-8096-a23440bb9906/image.png" alt=""></p>
<hr>
<h2 id="🔩컴포넌트component">🔩컴포넌트(Component)</h2>
<h3 id="📌액터의-주요-기능과-컴포넌트의-의미">📌액터의 주요 기능과 컴포넌트의 의미</h3>
<p><code>액터</code>의 주요 기능은 아래와 같은 세가지로 구분됨.</p>
<ul>
<li><p><code>시각적 기능</code>: 플레이어에게 어떻게 보여질 것인가?</p>
</li>
<li><p><code>물리적 기능</code>: 액터의 이동과 액터들 간의 상호 동작을 어떻게 할 것인가?</p>
</li>
<li><p><code>움직임</code>: 액터가 어떤 움직임을 가질 것인가?</p>
</li>
</ul>
<p><strong>액터의 역할에 따라 각 기능의 사용 여부가 결정됨</strong>. </p>
<p>플레이어가 특정 공간을 벗어나지 못하도록 하는 <strong>투명 벽의 경우 시각적 기능이 필요 없고</strong>, </p>
<p>플레이어가 땅 밑으로 떨어지지 않도록 하는 <strong>바닥의 경우 움직임 기능이 필요 없음</strong>.</p>
<p>이런 <strong>다양한 경우에 유연하게 대처할 수 있도록</strong> 언리얼 엔진은 <strong>액터의 세가지 기능을 독립적으로 규격화하고 액터의 종류에 따라 이들을 조합하는 방식으로 설계</strong>하였고, 이러한 <strong>규격화된 기능</strong>을 <code>컴포넌트(Component)</code>라고 함.</p>
<h3 id="📌언리얼-엔진에서-제공하는-주요-컴포넌트">📌언리얼 엔진에서 제공하는 주요 컴포넌트</h3>
<ul>
<li><p><code>스태틱메시 컴포넌트(StaticMesh Component)</code>: <strong>시각적인 기능과 물리적인 기능을 제공</strong>하는 모듈. <strong>주로 배경 물체에 사용</strong>.</p>
</li>
<li><p><code>스켈레탈메시 컴포넌트(SkeletalMesh Component)</code>: <strong>시각적인 기능과 애니메이션, 그리고 캐릭터의 물리 기능을 제공</strong>하는 모듈. <strong>주로 캐릭터에 사용</strong>.</p>
</li>
<li><p><code>콜리전 컴포넌트(Collision Component)</code>: <strong>구/박스/캡슐로 지정한 영역에 물리적인 기능을 설정하기 위해 제공</strong>하는 모듈. <strong>시각적인 기능 없음</strong>.</p>
</li>
<li><p><code>카메라 컴포넌트(Camera Component)</code>: <strong>가상 세계에서 보여지는 현재 상황을 플레이어의 모니터 화면에 출력</strong>해주는 기능.</p>
</li>
<li><p><code>오디오 컴포넌트(Audio Component)</code>: <strong>가상 세계에서 소리를 발생</strong>시키는 데 사용하는 기능.</p>
</li>
<li><p><code>파티클 시스템 컴포넌트(Particle System Component)</code>: <strong>파티클 시스템으로 설계된 이펙트를 화면에 출력</strong>해주는 기능.</p>
</li>
<li><p><code>라이트 컴포넌트(Light Component)</code>: 전구 등과 같이 <strong>물체에 광원 효과를 부여</strong>하는 기능.</p>
</li>
<li><p><code>무브먼트 컴포넌트(Movement Component)</code>: <strong>물체에 특정한 움직임을 부여</strong>하는 기능.</p>
</li>
</ul>
<p>액터에 속한 <strong>컴포넌트도 그 종류에 따라 독특한 속성을 가지며</strong>, 이는 <code>디테일</code> 창에서 확인할 수 있음. (아래 사진 참고)
<img src="https://velog.velcdn.com/images/ryu-rxxt/post/f4b38250-43ec-483c-a51e-a26b5bc175bd/image.png" alt=""></p>
<h3 id="📌컴포넌트의-성질과-루트-컴포넌트root-component">📌컴포넌트의 성질과 루트 컴포넌트(Root Component)</h3>
<p><strong>하나의 액터는 여러 개의 컴포넌트를 가질 수 있음</strong>. </p>
<p>이때 이들을 <strong>대표하는 하나의 컴포넌트를 반드시 지정</strong>해야 하는데</p>
<p>이를 <code>루트 컴포넌트</code>라고 함.</p>
<hr>
<blockquote>
<p>본 게시글은 &#39;이득우의 언리얼 C++ 게임 개발의 정석&#39; 교재를 참고하여 정리하였음을 알립니다. 
본 작성자는 저작권법을 준수하기 위해 최선을 다할 것입니다.
적법하지 않은 내용이 포함되어 있을 경우 작성자에게 알려주시면 시정하겠습니다. 
향후 별도의 안내 없이 게시글 내용 일부 수정 혹은 비공개 조치될 수 있음에 양해의 말씀 드립니다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Chapter 1. 개발 환경 설정]]></title>
            <link>https://velog.io/@ryu-rxxt/Chapter-1.-%EA%B0%9C%EB%B0%9C-%ED%99%98%EA%B2%BD-%EC%84%A4%EC%A0%95</link>
            <guid>https://velog.io/@ryu-rxxt/Chapter-1.-%EA%B0%9C%EB%B0%9C-%ED%99%98%EA%B2%BD-%EC%84%A4%EC%A0%95</guid>
            <pubDate>Mon, 31 Jul 2023 07:35:54 GMT</pubDate>
            <description><![CDATA[<h1 id="프로젝트-생성-결과">프로젝트 생성 결과</h1>
<h2 id="프로젝트-폴더">프로젝트 폴더</h2>
<p>언리얼 엔진에서 프로젝트를 생성 시 사전에 설정한 디렉토리에 프로젝트 폴더가 생성된다. 이 프로젝트 폴더 내에는 Config, Content, Intermediate, Saved 폴더와 (프로젝트명).uproject 파일이 아래와 같이 생성된다.</p>
<p><img src="https://velog.velcdn.com/images/ryu-rxxt/post/f98f31e8-026e-4cb2-9406-89768489c72c/image.png" alt=""></p>
<p>여기서 각 폴더의 역할과 .uproject 파일에 대해 알아보자.</p>
<ul>
<li><p><code>Config</code>: <strong>프로젝트의 설정 값을 보관</strong>하는 공간. 즉, 항상 보관해야 함.</p>
</li>
<li><p><code>Content</code>: <strong>프로젝트에 사용하는 애셋을 관리</strong>하는 공간. 마찬가지로 항상 보관해야함.</p>
</li>
<li><p><code>Intermediate</code>: 프로젝트 관리에 필요한 <strong>임시 파일이 저장</strong>되는 공간. 항상 보관할 필요는 없으나, 제거해도 에디터에 의해 자동으로 재생성됨.</p>
</li>
<li><p><code>Save</code>: 세이브 파일, 스크린샷 등의 <strong>에디터 작업 중 생성된 결과물이 저장</strong>되는 공간. 제거 시 폴더에 있는 세이브 파일, 스크린샷 등이 삭제되지만 프로젝트에는 영향 없음.</p>
</li>
<li><p><code>.uproject</code>: 프로젝트를 언리얼 에디터로 불러들이기 위한 정보가 <strong>JSON 형식</strong>으로 기록되어 있음.</p>
</li>
</ul>
<hr>
<h1 id="블루프린트-스크립팅-기반-프로젝트에서-c-클래스-추가하기">블루프린트 스크립팅 기반 프로젝트에서 C++ 클래스 추가하기</h1>
<h2 id="c-클래스-추가">C++ 클래스 추가</h2>
<p>언리얼 엔진의 경우 블루프린트 스크립팅 기반 프로젝트에서도 C++ 클래스를 추가할 수 있다. 그 방법에 대해 알아보자.
<img src="https://velog.velcdn.com/images/ryu-rxxt/post/0bb15a8f-6125-4be2-8cf4-65fbc62c1503/image.png" alt=""></p>
<p>먼저 왼쪽 위에서 *<em>툴 &gt; 새로운 C++ 클래스를 선택 후 *</em>
<img src="https://velog.velcdn.com/images/ryu-rxxt/post/45f30726-35f4-47f4-97ab-3c12e2cde5a8/image.png" alt=""></p>
<p>부모 클래스를 <strong>액터로 선택 후 다음을 누른 후</strong>
<img src="https://velog.velcdn.com/images/ryu-rxxt/post/7786c43e-862a-4bd6-853b-6ffc86b39982/image.png" alt=""></p>
<p><strong>액터 이름과 디렉토리를 설정</strong>해주면 된다. 
<del>라고 했지만 사실 디렉토리는 건드리지 않는 게 현명하다.</del></p>
<h2 id="c-클래스-추가-후-프로젝트-폴더">C++ 클래스 추가 후 프로젝트 폴더</h2>
<p>C++ 프로젝트로 확장 후(C++ 클래스 추가와 같은 말) 프로젝트 폴더를 다시 한 번 살펴보자.
<img src="https://velog.velcdn.com/images/ryu-rxxt/post/dfd02277-4c67-4cdf-a43c-36e068913bb2/image.png" alt=""></p>
<p>기존에 없던 Binaries, Source 폴더와 (프로젝트명).sln 파일이 생성되어있음을 알 수 있다. 각 폴더의 역할과 .sln 파일에 대해 알아보자.</p>
<ul>
<li><p><code>Binaries</code>: <strong>C++ 소스 코드가 컴파일된 결과물을 저장</strong>하는 공간. 제거해도 코드 빌드 시 재생성됨.</p>
</li>
<li><p><code>Source</code>: <strong>C++ 소스 코드를 저장</strong>하는 공간. 이외의 언리얼 엔진의 빌드 설정을 담은 C# 소스 파일이 있음. 제거 시 프로젝트 구성이 망가지므로 주의가 필요함.</p>
</li>
<li><p><code>.sln</code>: C++ 프로젝트를 관리하는 <strong>비주얼 스튜디오의 솔루션 파일</strong>. 솔루션 산하에 있는 각 프로젝트 파일은 Intermediate &gt; ProjectFiles에 저장되어 있음. 프로젝트 파일 및 솔루션 파일은 삭제하더라도 .uproject 파일 우클릭 &gt; Generate Visual Studio project file 메뉴를 선택하면 재생성 가능.</p>
</li>
</ul>
<h2 id="모듈">모듈</h2>
<p><strong>Binaries &gt; Win64 폴더에 들어가면</strong> 아래 사진과 같은 파일이 들어있을 것이다.
<img src="https://velog.velcdn.com/images/ryu-rxxt/post/a890e73a-6c20-49cb-9c0a-a7a76177cf0a/image.png" alt=""></p>
<p>여기서 UnrealEditor-(프로젝트명).dll은 프로젝트를 실행하면 함께 로딩되는 C++ 모듈이다.</p>
<ul>
<li><code>모듈</code> : C++ 코드를 컴파일한 결과물</li>
<li><code>게임 모듈</code> : 게임 로직을 담은 모듈</li>
</ul>
<h2 id="모듈-생성-결과">모듈 생성 결과</h2>
<p>모듈 생성 후 프로젝트를 불러와서 <strong>왼쪽 아래애 위치한 콘텐츠 브라우저</strong>를 확인해보자. 
<img src="https://velog.velcdn.com/images/ryu-rxxt/post/57f2befa-0233-450c-a29a-baa4d6def8bf/image.png" alt=""></p>
<p>언리얼 에디터가 모듈을 성공적으로 로딩했다면 위의 사진과 같이 <strong>C++ 클래스라는 폴더</strong>와 <strong>그 하위 폴더인 (프로젝트명)</strong>, 그리고 <strong>(프로젝트명) 폴더 안에 **(액터명) C++ 클래스 파일</strong>이 있을 것이다.</p>
<h2 id="주의사항">주의사항</h2>
<p><strong>프로젝트 폴더의 디렉토리 경로 상에 한글로 된 폴더가 있으면 안된다</strong>. 한글로 된 폴더가 중간에 있다면 <strong>C++ 클래스가 Visual Studio 상에서 빌드가 되지 않을 것</strong>이다.</p>
<p><img src="https://velog.velcdn.com/images/ryu-rxxt/post/d10c9ba8-f65e-45c0-a24b-0e17ce870668/image.png" alt=""></p>
<p>위의 사진은 경로 상에 한글로 된 폴더가 존재할 때 소스 코드를 빌드한 결과이다. 
그럼 필자는 이렇게 하면 안된다는 것을 어떻게 알았을까? <em><del>저도 알고싶지 않았어요..</del></em></p>
<hr>
<h1 id="visual-studio-개발-환경-설정">Visual Studio 개발 환경 설정</h1>
<h2 id="c-프로젝트-빌드-구성">C++ 프로젝트 빌드 구성</h2>
<p>아래의 사진은 Visual Studio의 화면 상단을 캡처한 것이다.
<img src="https://velog.velcdn.com/images/ryu-rxxt/post/855331f5-6de7-4398-bcfa-3e29b5e5893e/image.png" alt=""></p>
<p>여기서 <strong>Win64(혹은 Win32)의 좌측에 위치한 드롭다운 메뉴를 클릭</strong>하면 아래 사진과 같이 <strong>다섯 종류의 빌드 구성이 존재</strong>하는 것을 알 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/ryu-rxxt/post/30b12e1c-5bc8-4319-a6e6-bf2660713c89/image.png" alt=""></p>
<p>각 빌드 구성의 특징은 아래 테이블과 같다.</p>
<table>
<thead>
<tr>
<th align="left">빌드 구성</th>
<th align="right">목적</th>
<th align="right">최적화 수준</th>
<th align="right">생성물</th>
</tr>
</thead>
<tbody><tr>
<td align="left">DebugGame</td>
<td align="right">자세한 디버깅</td>
<td align="right">X</td>
<td align="right">exe 파일(게임 실행용)</td>
</tr>
<tr>
<td align="left">DebugGame Editor</td>
<td align="right">자세한 디버깅</td>
<td align="right">X</td>
<td align="right">dll 파일(에디터용)</td>
</tr>
<tr>
<td align="left">Development</td>
<td align="right">디버깅</td>
<td align="right">△</td>
<td align="right">exe 파일(게임 실행용)</td>
</tr>
<tr>
<td align="left">Development Editor</td>
<td align="right">디버깅</td>
<td align="right">△</td>
<td align="right">dll 파일(에디터용)</td>
</tr>
<tr>
<td align="left">Shipping</td>
<td align="right">게임의 최종 배포</td>
<td align="right">○</td>
<td align="right">exe 파일(게임 실행용)</td>
</tr>
</tbody></table>
<h2 id="실행-파일로-게임을-실행하고-싶다면">실행 파일로 게임을 실행하고 싶다면?</h2>
<p><strong>생성물은 Binaries 폴더에 저장</strong>된다.
<strong>exe 파일은 게임 실행 파일이지만</strong> 파일이 위치한 <strong>Binaries 폴더에는 리소스가 없기 때문에 실행되지 않는다.</strong>
만약 <strong>exe 파일로 게임을 실행하고 싶다면 리소스와 실행 파일이 묶인 패키지 형태</strong>로 만들어줘야 한다.
패키지를 제작하려면 언리얼 에디터의 <strong>파일 &gt; 패키지 프로젝트</strong> 메뉴를 사용하면 된다.</p>
<h1 id="언리얼-에디터-설정">언리얼 에디터 설정</h1>
<h2 id="프로젝트-세팅">프로젝트 세팅</h2>
<p> 프로젝트 세팅이란 <strong>언리얼 에디터를 실행할 때 기본으로 실행하도록 하는 레벨을 지정</strong>하는 것을 의미한다.</p>
<p> 아래의 사진과 같이 언리얼 에디터 상단의 <strong>편집 &gt; 프로젝트 세팅...</strong>을 선택한다.</p>
<p> <strong><em>언리얼 엔진4의 경우</em></strong> 툴바 가운데에 위치한 <strong>세팅 &gt; 프로젝트 세팅...</strong>을 선택해주면 된다.
 <img src="https://velog.velcdn.com/images/ryu-rxxt/post/8319885e-110d-4840-928d-f6a0fed98299/image.png" alt="">
이후 뜨는 창에서 <strong>좌측의 프로젝트에 있는 맵 &amp; 모드 섹션</strong>을 선택해주면 아래의 사진과 같은 창이 보일 것이다.
<img src="https://velog.velcdn.com/images/ryu-rxxt/post/a2d7139f-b6ff-4e88-9053-66c1c633ad99/image.png" alt=""></p>
<p><strong>Default Maps</strong>에서 <strong>에디터 시작 맵과 게임 기본 맵을 자동으로 실행되도록 하고자 하는 레벨로 설정</strong>해주면 된다.</p>
<blockquote>
<p>본 게시글은 &#39;이득우의 언리얼 C++ 게임 개발의 정석&#39; 교재를 참고하여 정리하였음을 알립니다. 
본 작성자는 저작권법을 준수하기 위해 최선을 다할 것입니다.
적법하지 않은 내용이 포함되어 있을 경우 작성자에게 알려주시면 시정하겠습니다. 
향후 별도의 안내 없이 게시글 내용 일부 수정 혹은 전체 삭제 조치될 수 있음에 양해의 말씀 드립니다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[알고리즘의 복잡도와 빅오 표기법]]></title>
            <link>https://velog.io/@ryu-rxxt/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EC%9D%98-%EB%B3%B5%EC%9E%A1%EB%8F%84%EC%99%80-%EB%B9%85%EC%98%A4-%ED%91%9C%EA%B8%B0%EB%B2%95</link>
            <guid>https://velog.io/@ryu-rxxt/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EC%9D%98-%EB%B3%B5%EC%9E%A1%EB%8F%84%EC%99%80-%EB%B9%85%EC%98%A4-%ED%91%9C%EA%B8%B0%EB%B2%95</guid>
            <pubDate>Thu, 27 Jul 2023 10:55:56 GMT</pubDate>
            <description><![CDATA[<p>어떤 문제를 논리적 사고 과정을 통해 논리적인 비약이나 오류가 없는 정답을 도출해내는 것은 문제를 해결하고자 하는 사람에게 있어 최우선적인 목표임과 동시에 쉽지만은 않은 일입니다. 그런데 우리에게는 정답을 도출해내는 것 못지않게, 어쩌면 더 중요한 문제가 하나 더 있습니다.</p>
<blockquote>
<h1 id="얼마나-효율적으로-문제를-해결했는가">얼마나 효율적으로 문제를 해결했는가?</h1>
</blockquote>
<p>잘 공감이 되지 않으시는 분들을 위해 예를 하나 들어드리겠습니다.</p>
<blockquote>
<ol>
<li>1부터 5까지의 합을 구하시오.</li>
<li>1부터 100까지의 합을 구하시오.</li>
<li>1부터 2,147,483,648까지의 합을 구하시오.</li>
</ol>
</blockquote>
<p>1번은 보자마자 문제를 푸셨을 겁니다. 
1부터 5까지 하나씩 더해나가기만 하면 되니까요. </p>
<p>2번은 어떤가요? 
힘들고 번거롭더라도, 1번을 풀 때와 같은 방식으로 구할 수 있습니다. </p>
<p>그렇다면 3번은 1번 문제를 풀때와 같은 방식으로 풀 수 있을까요?
이론적으로는 가능합니다만, 현실적인 측면에서는 불가능하다고 해도 과언이 아닙니다.</p>
<p>1번을 풀 때 사용한 방식을 사용해 1부터 n까지의 합을 구하는 코드를 작성해봅시다.
여기서 n은 1 이상의 자연수이며 사용 언어는 파이썬입니다.</p>
<pre><code class="language-python">total = 0
n = int(input())
for i in range(1,n+1):
    total += i</code></pre>
<p>이 방식의 경우 대입 연산 n+2회, 덧셈 연산 n회로 총 연산 횟수는 2n+2입니다.
n이 5일 경우 총 연산 횟수는 12, 100일 경우는 202, 2,147,483,648일 경우는 4,294,967,298가 되겠네요.
n이 증가할수록 연산 횟수도 늘어나는 것을 알 수 있습니다.</p>
<p>이번에는 등차수열의 개념을 도입해 새로운 코드를 작성해보겠습니다.
마찬가지로 n은 1 이상의 자연수이며 사용 언어는 파이썬입니다.</p>
<pre><code class="language-python">n = int(input())
total = n * (n+1) / 2</code></pre>
<p>이 방식의 경우 대입 연산 2회, 곱셈 연산 1회, 나눗셈 연산 1회로 총 연산 횟수는 4입니다.
이 경우에는 n의 값에 관계없이 항상 연산 횟수가 4로 고정되네요.</p>
<p>놀라운건 이는 한 가지 예시에 불과하며, 이보다 더 기하급수적으로 연산 횟수가 늘어나는 예시도 존재한다는 것인데요. 이 정도면 효율적인 알고리즘의 필요성에 대해서 충분히 인식했다고 생각하고 본론으로 넘어가도록 하겠습니다.</p>
<hr>
<p>알고리즘의 복잡도를 표현하는 방법에 대해서 알아봅시다.
$n$이 무한대로 커질 때의 알고리즘(함수)의 실행 시간의 추이를 표현하는 표기법인 점근적 표기법을 이용해 $lim_{n \to \infty}T(n)$의 형태로 복잡도를 표현할 것입니다.
여기서 $n$은 입력값을 의미하며, $T(n)$은 알고리즘(함수)의 총 실행 시간을 의미합니다.</p>
<p>점근적 표기법은 빅오 표기법, 빅오메가 표기법, 빅세타 표기법이 존재합니다.</p>
<ul>
<li><p>빅오 표기법(Big-oh notation): 최악인 경우의 알고리즘 수행 시간을 나타냄.
$n$이 충분히 클 때 차수가 가장 큰 항이 가장 큰 영향을 미치고 다른 항들은 상대적으로 무시할 수 있을 정도로 작다는 사실을 이용함. $T(n)$의 최고차항 차수가 $k$일 경우 $T(n)$의 복잡도를 빅오 표기법으로 표기하면 $O(n^k)$.</p>
</li>
<li><p>빅오메가 표기법(Big-omega notation): 최소한의 수행시간을 나타냄.
빅오 표기법과 반대되는 개념. $T(n)$의 복잡도가 빅세타 표기법으로 표기했을 때 $\Omega(n^k)$일 경우 $T(n)$은 아무리 빨라도 $n^k$이상의 복잡도를 가진다는 것을 의미함.</p>
</li>
<li><p>빅세타 표기법(Big-theta notation): 빅오와 빅오메가를 동시에 만족시키는 증가함수. $T(n)=O(f(n))$이면서 $T(n) = \Omega(f(n))$이면 $T(n) = \theta(n)$.</p>
</li>
</ul>
<p>시간 복잡도의 크기는 $O(1)&lt;O(logn)&lt;O(n)&lt;O(nlogn)&lt;O(n^2)&lt;O(n^3)&lt;\cdot\cdot\cdot&lt;O(2^n)&lt;O(3^n)&lt;\cdot\cdot\cdot&lt;O(n!)$ 순입니다.
알고리즘(함수)의 <strong><em>시간 복잡도가 $O(n^2)$을 초과하는 경우</em></strong>, 우리는 더 나은 알고리즘을 모색해야 합니다.</p>
<p>빅오 표기법 외의 표기법은 통상적으로 거의 사용되지 않으므로 아래 연습 문제에서는 빅오 표기법만 다룹니다.</p>
<blockquote>
<p><strong>연습 문제</strong>
다음을 시간 복잡도 함수인 빅오 표기법으로 표기</p>
</blockquote>
<p>1) $T(n) = n^2 + n + 1$
2) $T(n) = n^3 + 10000n^2 + 50n$ 
3) $T(n) = n^2log_2n + n^3 + 3$
4) $T(n) = 7(2^n) + 3^n$
5) $T(n) = 3^n + n!$ </p>
<blockquote>
<p>정답</p>
</blockquote>
<p>1) $O(n^2)$ 2) $O(n^3)$ 3) $O(n^3)$ 4) $O(3^n)$ 5) $O(n!)$</p>
<blockquote>
<p>다음 알고리즘의 시간 복잡도를 빅오 표기법으로 표기
1)</p>
</blockquote>
<pre><code class="language-pseudo">multi = 1
for i &lt;- 1 to n do:
    for j&lt;- i+1 to n step 2 do:
        multi = multi*j</code></pre>
<p>2)</p>
<pre><code class="language-pseudo">sum_one = 0
while n &gt; 1:
    n = n // 2
    sum_one = sun_one + 1</code></pre>
<blockquote>
<p>정답</p>
</blockquote>
<p>1) $O(n^2)$ 2) $O(logn)$</p>
]]></description>
        </item>
    </channel>
</rss>