<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>나만의 연습장</title>
    <link>https://openmynotepad.tistory.com/</link>
    <description>엄준식이 좋아요.</description>
    <language>ko</language>
    <pubDate>Fri, 7 Aug 2026 21:07:14 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>엄준식사생팬</managingEditor>
    <image>
      <title>나만의 연습장</title>
      <url>https://tistory1.daumcdn.net/tistory/3034873/attach/6073d8a060f042b4b34fe265b02ac2b9</url>
      <link>https://openmynotepad.tistory.com</link>
    </image>
    <item>
      <title>언리얼엔진의 FText는 조사를 어떻게 판별할까?</title>
      <link>https://openmynotepad.tistory.com/135</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 FText를 통해 Localization을 진행할 때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한글에서는 적절한 조사를 붙이기 위해 다음과 같이 처리한 것이 있을 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1752329569693&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{0}|hpp(은,는)

여기서 정의는
{0}|hpp(받침이 들어올 때 쓰일 조사, 받침이 들어오지 않을 때 쓰일 조사)&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;그런데 언리얼엔진은 {0}에 어떤 텍스트가 들어올지 어떻게 알고 은, 는을 따로 나누어서 붙여주는 것일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 실제로 포매팅이 진행될 &lt;b&gt;FTextFormatData::Format_NoLock&lt;/b&gt; 까지 들어가야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(여기서 Lock이 있는 이유는, 포매팅에 대해 Multithread도 지원할 수 있기 때문이다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1752329840914&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FString FTextFormatData::Format_NoLock(const FPrivateTextFormatArguments&amp;amp; InFormatArgs)
{
	// Impl
	ArgumentModifierToken-&amp;gt;TextFormatArgumentModifier-&amp;gt;Evaluate(*PossibleArgumentValue, InFormatArgs, ResultString);
}&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;여기서 &lt;b&gt;TextFormatArgumentModifier&lt;/b&gt;는 해당 텍스트가 한글이라면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;FTextFormatArgumentModifier_HangulPostPositions&lt;/b&gt;가 들어온다.&lt;/p&gt;
&lt;pre id=&quot;code_1752329892867&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void FTextFormatArgumentModifier_HangulPostPositions::Evaluate(const FFormatArgumentValue&amp;amp; InValue, const FPrivateTextFormatArguments&amp;amp; InFormatArgs, FString&amp;amp; OutResult) const&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;이 부분의 Implementation을 확인하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 하나하나 봐보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1752329998525&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if ((LastArgChar &amp;gt;= 0xAC00 &amp;amp;&amp;amp; LastArgChar &amp;lt;= 0xD7A3) || (LastArgChar &amp;gt;= TEXT('0') &amp;amp;&amp;amp; LastArgChar &amp;lt;= TEXT('9')))&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;LastArgChar가 &lt;b&gt;[0xAC00, 0xD7A3]&lt;/b&gt; 안에 있거나 &lt;b&gt;[0, 9]&lt;/b&gt; 에 있는지 확인한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;b&gt;0xAC00&lt;/b&gt; 의 유니코드는 '&lt;b&gt;가&lt;/b&gt;'&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;0xD7A3&lt;/b&gt;의 유니코드는 '&lt;b&gt;힣&lt;/b&gt;' 이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉&lt;/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;pre id=&quot;code_1752330108944&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;bool bIsConsonant = ((LastArgChar - 0xAC00) % 28 != 0) || LastArgChar == TEXT('0') || LastArgChar == TEXT('1') || LastArgChar == TEXT('3') || LastArgChar == TEXT('6') || LastArgChar == TEXT('7') || LastArgChar == TEXT('8');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숫자부터&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;LastArgChar&lt;/b&gt;가 0, 1, 3, 6, 7, 8 이라면 받침이 있는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를들어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'1은'&amp;nbsp; = '일은' 이고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'2는' = &quot;이는&quot; 이므로 0, 1, 3, 6, 7, 8 은 받침이 있는 조사로 처리되어야 할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(LastArgChar - 0xAC00) % 28 != 0&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;우리가 예를들어&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;길 이라는 텍스트를 쓴다고 해보자 이 길이라는 텍스트는&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;AE38&lt;/b&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;pre id=&quot;code_1752330381311&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;초성 * 21 * 28 + 중성 * 28 + 종성&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;여기서 초성 | 중성 | 종성은 우리의 자음 모음 순서이다.&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;인덱스는 0, 20, 8 이다.&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;한글은 19개의 자음과 10개의 모음인데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 ㅣ 은 인덱스가 20 이고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ㄹ은 인덱스가 8일까?&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;&lt;b&gt;초성 인덱스&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;ㄱ&lt;/td&gt;
&lt;td&gt;기본 자음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;ㄲ&lt;/td&gt;
&lt;td&gt;된소리(쌍기역)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;ㄴ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;ㄷ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;ㄸ&lt;/td&gt;
&lt;td&gt;된소리(쌍디귿)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;ㄹ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;ㅁ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;ㅂ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;ㅃ&lt;/td&gt;
&lt;td&gt;된소리(쌍비읍)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;ㅅ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;ㅆ&lt;/td&gt;
&lt;td&gt;된소리(쌍시옷)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;ㅇ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;ㅈ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;ㅉ&lt;/td&gt;
&lt;td&gt;된소리(쌍지읒)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;ㅊ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;ㅋ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;ㅌ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;ㅍ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;ㅎ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;ㅏ&lt;/td&gt;
&lt;td&gt;기본 단모음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;ㅐ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;ㅑ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;ㅒ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;ㅓ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;ㅔ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;ㅕ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;ㅖ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;ㅗ&lt;/td&gt;
&lt;td&gt;단모음 (복합 조합 가능한 모음)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;ㅘ&lt;/td&gt;
&lt;td&gt;ㅗ + ㅏ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;ㅙ&lt;/td&gt;
&lt;td&gt;ㅗ + ㅐ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;ㅚ&lt;/td&gt;
&lt;td&gt;ㅗ + ㅣ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;ㅛ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;ㅜ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;ㅝ&lt;/td&gt;
&lt;td&gt;ㅜ + ㅓ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;ㅞ&lt;/td&gt;
&lt;td&gt;ㅜ + ㅔ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;ㅟ&lt;/td&gt;
&lt;td&gt;ㅜ + ㅣ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;ㅠ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;ㅡ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;td&gt;ㅢ&lt;/td&gt;
&lt;td&gt;ㅡ + ㅣ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;ㅣ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;(없음)&lt;/td&gt;
&lt;td&gt;받침 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;ㄱ&lt;/td&gt;
&lt;td&gt;기본 자음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;ㄲ&lt;/td&gt;
&lt;td&gt;쌍기역&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;ㄳ&lt;/td&gt;
&lt;td&gt;ㄱ + ㅅ (겹받침)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;ㄴ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;ㄵ&lt;/td&gt;
&lt;td&gt;ㄴ + ㅈ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;ㄶ&lt;/td&gt;
&lt;td&gt;ㄴ + ㅎ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;ㄷ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;ㄹ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;ㄺ&lt;/td&gt;
&lt;td&gt;ㄹ + ㄱ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;ㄻ&lt;/td&gt;
&lt;td&gt;ㄹ + ㅁ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;ㄼ&lt;/td&gt;
&lt;td&gt;ㄹ + ㅂ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;ㄽ&lt;/td&gt;
&lt;td&gt;ㄹ + ㅅ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;ㄾ&lt;/td&gt;
&lt;td&gt;ㄹ + ㅌ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;ㄿ&lt;/td&gt;
&lt;td&gt;ㄹ + ㅍ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;ㅀ&lt;/td&gt;
&lt;td&gt;ㄹ + ㅎ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;ㅁ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;ㅂ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;ㅄ&lt;/td&gt;
&lt;td&gt;ㅂ + ㅅ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;td&gt;ㅅ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;ㅆ&lt;/td&gt;
&lt;td&gt;쌍시옷&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;td&gt;ㅇ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;ㅈ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;23&lt;/td&gt;
&lt;td&gt;ㅊ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;td&gt;ㅋ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;ㅌ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;26&lt;/td&gt;
&lt;td&gt;ㅍ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;27&lt;/td&gt;
&lt;td&gt;ㅎ&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;종성은 없을수도 있고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초성과 다른 복합자음(겹받침)이 받침으로 들어갈 수 있기 때문이다.&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 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;길은 ㄱ + ㅣ + ㄹ 이며&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;인덱스는 0, 20, 8 이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 인덱스를 위의 식에 계산해본다면 길은 568 이라는 값이 나오고&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;한글 유니코드의 시작인 &lt;b&gt;0xAC00&lt;/b&gt; 에 568를 더하면 0xAE38 이 나온다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그럼 다시 위의 FText 코드로 돌아가본다면&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(LastArgChar - 0xAC00) % 28 != 0&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이는 결국&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;LastArgChar가 종성 28개로 Modular 연산을 했을때 0이 아니라면 받침이 있다는 뜻이다. 라는것으로 확인할 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;한글의 뒷 글자가 받침이 있다면 이것은 &lt;b&gt;'받침이 있을 때 들어오는 조사'&lt;/b&gt; 로 포매팅 되어야 한다는 것이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1752331190974&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const bool bIsRieul = ((LastArgChar - 0xAC00) % 28 == 8) || LastArgChar == TEXT('1') || LastArgChar == TEXT('7') || LastArgChar == TEXT('8');
if (bIsRieul)
{
	bIsConsonant = false;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;bIsRieul은 해당 문자가 ㄹ 받침을 쓰는지 확인한다&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;'ㄹ' 은 인덱스로 8 이므로 &lt;b&gt;LastArgChar - 0xAC00 % 28&lt;/b&gt; (종성갯수) 했을 때 8이 나오면 이는 ㄹ이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;ㄹ받침인 경우에는&lt;b&gt; '받침이 없는 조사'&lt;/b&gt;가 들어와야 한다는 것이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1752331291069&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (bIsConsonant)
{
	OutResult.AppendChars(ConsonantSuffix.StringPtr, ConsonantSuffix.StringLen);
}
else
{
	OutResult.AppendChars(VowelSuffix.StringPtr, VowelSuffix.StringLen);
}&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;받침이 있다는 것은 곧, 자음이 이곳에 들어왔다는 것이고 그래서 bIsConsonant를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 true 라면 '은' 이 붙을 것이고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;false라면 '는' 이 붙을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>UnrealEngine/Impl</category>
      <category>UnrealEngine</category>
      <author>엄준식사생팬</author>
      <guid isPermaLink="true">https://openmynotepad.tistory.com/135</guid>
      <comments>https://openmynotepad.tistory.com/135#entry135comment</comments>
      <pubDate>Sat, 12 Jul 2025 23:42:29 +0900</pubDate>
    </item>
    <item>
      <title>[Unreal Engine 5] World Partition</title>
      <link>https://openmynotepad.tistory.com/134</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;월드 파티션(World Partition)&lt;/b&gt;은 대규모 월드를 관리하기 위한 자동 데이터 관리 및 거리 기반 레벨 스트리밍 시스템이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에는 셀로 나눠진 Persistant Level에 월드를 저장하고, 커다란 레벨을 서브 레벨로 나눴어야 했는데&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;월드 파티션을 알기 위해선 이전의 레벨 스트리밍에 대한 정보를 알아야 한다.&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;레벨 스트리밍 (Level Streaming)&lt;/b&gt; 은 게임이 실행되는 동안 전체 맵을 한 번에 로드하는 것이 아닌, 필요한 부분만 동적으로&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로드 / 언로드 하는 기술이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 기술을 사용하면 큰 월드에서도 성능을 최적화 하고, 메모리 사용량을 줄일 수 있다.&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;기존의 언리얼 엔진4에서는 서브 레벨 기반 스트리밍을 사용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Persistent Level (기본 레벨)&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;월드 파티션의 핵심 개념은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 자동 그리드 기반 레벨 스트리밍&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;월드를 자동으로 그리드 (Cell) 단위로 나누어서 관리한다.&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;size18&quot;&gt;&lt;b&gt;2. HLOD&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;size18&quot;&gt;&lt;b&gt;3. Data Layer&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;월드에서 특정 오브젝트들을 Layer로 묵을 수 있다.&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;size18&quot;&gt;&lt;b&gt;4. 스트리밍 소스 (Streaming Source)&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;기본적으로는 플레이어의 위치를 기준으로 잡히고 있는데, 추가하고 싶다면 UWorldPartitionSubsystem 에 등록해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;월드 파티션을 사용하려면 특정 세팅을 먼저 해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Project를 생성할 때, 프로젝트 템플릿들에는 지금 월드 파티션 템플릿이 기본적으로 포함되어 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1193&quot; data-origin-height=&quot;635&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bC80ns/btsMtqdzsOu/Fv8mgeisFgTugkfbS6L0y1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bC80ns/btsMtqdzsOu/Fv8mgeisFgTugkfbS6L0y1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bC80ns/btsMtqdzsOu/Fv8mgeisFgTugkfbS6L0y1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbC80ns%2FbtsMtqdzsOu%2FFv8mgeisFgTugkfbS6L0y1%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;1193&quot; height=&quot;635&quot; data-origin-width=&quot;1193&quot; data-origin-height=&quot;635&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;World Settings&lt;/b&gt; 로 가서 &lt;b&gt;Enable Streaming&lt;/b&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;Blank, First Person, Third Person, Top Down, Vehicle Advanced&lt;/b&gt; 에서만 나타난다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;506&quot; data-origin-height=&quot;453&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zNs33/btsMsMV1iQ1/jsUvs3DFHT7TIp8dFlgyw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zNs33/btsMsMV1iQ1/jsUvs3DFHT7TIp8dFlgyw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zNs33/btsMsMV1iQ1/jsUvs3DFHT7TIp8dFlgyw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzNs33%2FbtsMsMV1iQ1%2FjsUvs3DFHT7TIp8dFlgyw0%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;506&quot; height=&quot;453&quot; data-origin-width=&quot;506&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리의 기존 프로젝트가 월드 파티션 템플릿을 포함하게 하기 위해선 다음과 같이 하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. &lt;b&gt;Tools -&amp;gt; Convert Level&lt;/b&gt; 을 사용하여 월드 파티션 변환을 사용하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. &lt;b&gt;Commandlet&lt;/b&gt; 을 사용하여 월드 파티션 변환 하기&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/M1NdH/btsMtaPzH7g/ijmbshZlu3SiSYrhpCzik0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/M1NdH/btsMtaPzH7g/ijmbshZlu3SiSYrhpCzik0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/M1NdH/btsMtaPzH7g/ijmbshZlu3SiSYrhpCzik0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FM1NdH%2FbtsMtaPzH7g%2FijmbshZlu3SiSYrhpCzik0%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;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;UnrealEditor.exe QAGame -run=WorldPartitionConvertCommandlet Playground.umap -AllowCommandletRendering&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;&lt;b&gt;그리드 세팅&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;529&quot; data-origin-height=&quot;558&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgrkBN/btsMtt9dSdz/LL1to1JLqPScdvunYfBZn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgrkBN/btsMtt9dSdz/LL1to1JLqPScdvunYfBZn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgrkBN/btsMtt9dSdz/LL1to1JLqPScdvunYfBZn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgrkBN%2FbtsMtt9dSdz%2FLL1to1JLqPScdvunYfBZn0%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;529&quot; height=&quot;558&quot; data-origin-width=&quot;529&quot; data-origin-height=&quot;558&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;World Settings&lt;/b&gt;의 &lt;b&gt;World Partition Setup&lt;/b&gt;을 선택하여 월드 파티션의 런타임 세팅을 할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;여기선 그리드에 대한 다양한 데이터 설정과 HLOD Data layer 등을 설정할 수 있는데.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Cell Size인 25600 이 궁금할 수도 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;언리얼에서는 단위가 cm 이므로 25600cm 이고, 이는 한 셀의 크기가 256미터 임을 알 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위의 Preview Grids 를 클릭하면, 에디터 뷰포트 내에서 그리드가 어떻게 나누어져있는지를 볼 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;995&quot; data-origin-height=&quot;490&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sjjW2/btsMrDZux0s/kcSeUFNKXYLBU6kenkvcC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sjjW2/btsMrDZux0s/kcSeUFNKXYLBU6kenkvcC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sjjW2/btsMrDZux0s/kcSeUFNKXYLBU6kenkvcC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsjjW2%2FbtsMrDZux0s%2FkcSeUFNKXYLBU6kenkvcC1%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;995&quot; height=&quot;490&quot; data-origin-width=&quot;995&quot; data-origin-height=&quot;490&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;로딩 범위가 이해가 안될 수도 있는데, 우리의 스트리밍 액터가 그리드로부터 768미터 떨어지기 시작하면, 정보가 사라지고, 로딩되기 시작합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;우리의 &lt;b&gt;PlayerController&lt;/b&gt;에도 &lt;b&gt;World Partition&lt;/b&gt;에 대한 정보가 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이는 &lt;b&gt;WorldPartitionStreamingSourceComponent&lt;/b&gt;를 포함하고 있는것인데, 현재의 모든 템플릿에는 기본적으로 포함되어 있습니다&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;여기서의&lt;b&gt; Runtime Grid&lt;/b&gt; 이름은 우리가 World Settings - World Partition에서 설정한 Grid 이름입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위의 예시로 들자면 MainGrid가 되겠군요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1708&quot; data-origin-height=&quot;924&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cj82Xs/btsMudY62a5/bPG0DQqeNJ4V4viie6lEo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cj82Xs/btsMudY62a5/bPG0DQqeNJ4V4viie6lEo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cj82Xs/btsMudY62a5/bPG0DQqeNJ4V4viie6lEo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcj82Xs%2FbtsMudY62a5%2FbPG0DQqeNJ4V4viie6lEo1%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;1708&quot; height=&quot;924&quot; data-origin-width=&quot;1708&quot; data-origin-height=&quot;924&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;우리가 월드 파티션을 사용할 때는 World Partition Editor 를 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Window - World Partition Editor 를 클릭합니다.&lt;/p&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;533&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkWiVg/btsMt57OaoO/c0C1ulWaHWIuzKzSDnLk1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkWiVg/btsMt57OaoO/c0C1ulWaHWIuzKzSDnLk1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkWiVg/btsMt57OaoO/c0C1ulWaHWIuzKzSDnLk1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkWiVg%2FbtsMt57OaoO%2Fc0C1ulWaHWIuzKzSDnLk1k%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;533&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;533&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;p data-ke-size=&quot;size16&quot;&gt;이 곳에서 다음과 같은 처리를 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 그리드들을 드래그 한 후, 우클릭하면 Selection이 나타나게 됩니다.&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;691&quot; data-origin-height=&quot;692&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Nb4KQ/btsMuMzYMQU/1iSjaU9X4Gy7Mx0i8x1tk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Nb4KQ/btsMuMzYMQU/1iSjaU9X4Gy7Mx0i8x1tk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Nb4KQ/btsMuMzYMQU/1iSjaU9X4Gy7Mx0i8x1tk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNb4KQ%2FbtsMuMzYMQU%2F1iSjaU9X4Gy7Mx0i8x1tk1%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;691&quot; height=&quot;692&quot; data-origin-width=&quot;691&quot; data-origin-height=&quot;692&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;p data-ke-size=&quot;size16&quot;&gt;Level Instance 나 Virtrual Texture .. 같은 내용은 여기서 다루지 않습니다.&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;ref : &lt;a href=&quot;https://youtu.be/LnoCwJBdUPM?si=-cqk6FbuSRRa2s-H&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://youtu.be/LnoCwJBdUPM?si=-cqk6FbuSRRa2s-H&lt;/a&gt;&lt;/p&gt;</description>
      <category>UnrealEngine/기능</category>
      <category>UnrealEngine</category>
      <author>엄준식사생팬</author>
      <guid isPermaLink="true">https://openmynotepad.tistory.com/134</guid>
      <comments>https://openmynotepad.tistory.com/134#entry134comment</comments>
      <pubDate>Sun, 23 Feb 2025 17:09:19 +0900</pubDate>
    </item>
    <item>
      <title>Unreal Engine의 FText 내부까지 알아보기</title>
      <link>https://openmynotepad.tistory.com/133</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 Unreal Engine으로 게임을 제작하다보면 UI를 만들거나, 혹은 현지화 작업을 할 때 FText를 만지게 되어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 내가 속해 있는 게임 개발팀에서도 FText를 이용하여 L10N 작업중이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Unreal Engine이 FText에 정의한 내용은 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1181&quot; data-origin-height=&quot;350&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CGDuN/btsIIJtsPOh/L80Ft5JSSHTBC4ZImaSjz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CGDuN/btsIIJtsPOh/L80Ft5JSSHTBC4ZImaSjz0/img.png&quot; data-alt=&quot;https://dev.epicgames.com/documentation/ko-kr/unreal-engine/ftext-in-unreal-engine&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CGDuN/btsIIJtsPOh/L80Ft5JSSHTBC4ZImaSjz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCGDuN%2FbtsIIJtsPOh%2FL80Ft5JSSHTBC4ZImaSjz0%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;1181&quot; height=&quot;350&quot; data-origin-width=&quot;1181&quot; data-origin-height=&quot;350&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://dev.epicgames.com/documentation/ko-kr/unreal-engine/ftext-in-unreal-engine&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글만봐서는 '텍스트 현지화'를 제공한다고 하는데, 어떻게 사용하고 어떻게 동작하는지에 대해 모호하게 적혀있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문서는 내가 직접 FText에 대해 분석하고, 어떻게 사용하는지에 대해 공유하는 문서이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. FText 타입 변수의 사용방법&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용 방법은 정말 간단하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 어떠한 문자열을 정의하고, 그것을 언리얼 엔진에게 알려주고 우리는 사용만 하면된다.&lt;/p&gt;
&lt;pre id=&quot;code_1721550657317&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// NSLOCTEXT(NamespaceName, KeyName, DefaultValue);
FText testText = NSLOCTEXT(&quot;A&quot;, &quot;B&quot;, &quot;C&quot;);&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;가장 기초적인 정의방법은 다음과 같다.&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;b&gt;&quot;A 라는 Namespace에서 B라는 Key를 가진 FText 값을 주세요. 만약 없다면 DefaultValue로 C를 사용하겠습니다.&quot;&lt;/b&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;모든 FText에 대해서 이렇게 작성하기가 귀찮을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럴땐 Namespace를 미리 지정하고, Key Value만 지정해도 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1721550987900&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#define LOCTEXT_NAMESPACE &quot;A&quot;
FText testText1 = LOCTEXT(&quot;B&quot;, &quot;C&quot;);
FText testText2 = LOCTEXT(&quot;D&quot;, &quot;E&quot;);
#undef&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;이렇게 사용한다면 NSLOCTEXT를 사용하지 않고 Key와 Value만을 사용하여 FText를 정의할 수 있다.&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;(Stringtable에 대한것은 밑에서 계속 작성하겠다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. Localization 하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 위에서 A Namespace에 있는 B Key 값을 정의했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이걸 Localization 해보자&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;언리얼 엔진을 켜고 Tools &amp;gt; Localization Dashboard를 클릭한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;253&quot; data-origin-height=&quot;842&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cI5ySr/btsIGtTELMJ/WXetdExSW296lDFQxp3TV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cI5ySr/btsIGtTELMJ/WXetdExSW296lDFQxp3TV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cI5ySr/btsIGtTELMJ/WXetdExSW296lDFQxp3TV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcI5ySr%2FbtsIGtTELMJ%2FWXetdExSW296lDFQxp3TV0%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;253&quot; height=&quot;842&quot; data-origin-width=&quot;253&quot; data-origin-height=&quot;842&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;이제 이곳에서 GatherText를 해주어야 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;919&quot; data-origin-height=&quot;282&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blxrf2/btsIHaFPsbL/CjMUTXjb0WK1Ttp9z5IK21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blxrf2/btsIHaFPsbL/CjMUTXjb0WK1Ttp9z5IK21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blxrf2/btsIHaFPsbL/CjMUTXjb0WK1Ttp9z5IK21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fblxrf2%2FbtsIHaFPsbL%2FCjMUTXjb0WK1Ttp9z5IK21%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;919&quot; height=&quot;282&quot; data-origin-width=&quot;919&quot; data-origin-height=&quot;282&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;Gather from Text Files를 체크하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Search Directories 에 다음과같이 최상위 폴더만 지정해주자&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;691&quot; data-origin-height=&quot;76&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNSF4Z/btsIGVvon15/8mGKdpXgsLtOgVCoGZzBIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNSF4Z/btsIGVvon15/8mGKdpXgsLtOgVCoGZzBIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNSF4Z/btsIGVvon15/8mGKdpXgsLtOgVCoGZzBIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNSF4Z%2FbtsIGVvon15%2F8mGKdpXgsLtOgVCoGZzBIk%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;691&quot; height=&quot;76&quot; data-origin-width=&quot;691&quot; data-origin-height=&quot;76&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Gather Text를 누르고, Compile Text를 해준다.&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;653&quot; data-origin-height=&quot;187&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/I1Gp9/btsIIiCWPew/nRsbYpacOqJ07MmzzHECu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/I1Gp9/btsIIiCWPew/nRsbYpacOqJ07MmzzHECu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/I1Gp9/btsIIiCWPew/nRsbYpacOqJ07MmzzHECu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FI1Gp9%2FbtsIIiCWPew%2FnRsbYpacOqJ07MmzzHECu1%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;653&quot; height=&quot;187&quot; data-origin-width=&quot;653&quot; data-origin-height=&quot;187&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 내 프로젝트 Content &amp;gt; Localization &amp;gt; Game에 다음과 같은 파일들이 생성되게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 정의한 FText를 보려면 en -&amp;gt; Game.po 파일을 메모장으로 열어보자&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;110&quot; data-origin-height=&quot;61&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XcWcJ/btsIHdoP23v/BzWLJVx3k7lsZnOEWIpFa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XcWcJ/btsIHdoP23v/BzWLJVx3k7lsZnOEWIpFa0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XcWcJ/btsIHdoP23v/BzWLJVx3k7lsZnOEWIpFa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXcWcJ%2FbtsIHdoP23v%2FBzWLJVx3k7lsZnOEWIpFa0%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;110&quot; height=&quot;61&quot; data-origin-width=&quot;110&quot; data-origin-height=&quot;61&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;msgctext에서 &quot;A,B&quot; 는 A namespace B key 라는 뜻이고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 value는 C가 된다는 뜻이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;en 상태일때는 C였으니 ko 일때는 다르게 출력하고 싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ko 일때의 Culture를 만들어주자&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;1423&quot; data-origin-height=&quot;88&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5xmVo/btsIHdbiHM8/Dzo5aZzy1uZkxKP6xpiQEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5xmVo/btsIHdbiHM8/Dzo5aZzy1uZkxKP6xpiQEK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5xmVo/btsIHdbiHM8/Dzo5aZzy1uZkxKP6xpiQEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5xmVo%2FbtsIHdbiHM8%2FDzo5aZzy1uZkxKP6xpiQEK%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;1423&quot; height=&quot;88&quot; data-origin-width=&quot;1423&quot; data-origin-height=&quot;88&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;다시 Localization dashboard를 켜서 밑에 Add New Culture를 누르고 Korean을 추가해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Gather Text를 해주자, 그 후 Export Text를 한 후, ko 에 있는 .po 파일을 열어보자&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;107&quot; data-origin-height=&quot;65&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cy474N/btsIII2pzSL/ysvRUM3mle3eWAp6F2BNmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cy474N/btsIII2pzSL/ysvRUM3mle3eWAp6F2BNmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cy474N/btsIII2pzSL/ysvRUM3mle3eWAp6F2BNmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcy474N%2FbtsIII2pzSL%2FysvRUM3mle3eWAp6F2BNmk%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;107&quot; height=&quot;65&quot; data-origin-width=&quot;107&quot; data-origin-height=&quot;65&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 msgstr에 우리가 쓸 문자열을 추가해준 뒤 Word Count를 해주면 다음과 같이 정상적으로 나타나게 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1335&quot; data-origin-height=&quot;79&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bz6bZh/btsIHlAlrfv/rcKTqXYWj4kv5SmOCMF9pk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bz6bZh/btsIHlAlrfv/rcKTqXYWj4kv5SmOCMF9pk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bz6bZh/btsIHlAlrfv/rcKTqXYWj4kv5SmOCMF9pk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbz6bZh%2FbtsIHlAlrfv%2FrcKTqXYWj4kv5SmOCMF9pk%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;1335&quot; height=&quot;79&quot; data-origin-width=&quot;1335&quot; data-origin-height=&quot;79&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;이제 우리가 게임의 Language를 EN -&amp;gt; KR 로 변환하게 되면 A.B 에 있는 FText의 Value는 &quot;씨&quot; 로 나타나게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 불편한데요?&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;결국 FText를 사용하려면 코드 어딘가에 NSLOCTEXT나 LOCTEXT로 (Key, Value) 쌍을 제공하고 컴파일 한 다음 에디터를 한번 켜야하네요? 불편한데..&quot;&lt;/b&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;이를 위해 언리얼 엔진은 StringTable이라는 것을 제공한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;590&quot; data-origin-height=&quot;805&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LjCCY/btsIIYKMewb/bu2GJ6Mq5QjTInbw8FLo10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LjCCY/btsIIYKMewb/bu2GJ6Mq5QjTInbw8FLo10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LjCCY/btsIIYKMewb/bu2GJ6Mq5QjTInbw8FLo10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLjCCY%2FbtsIIYKMewb%2Fbu2GJ6Mq5QjTInbw8FLo10%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;590&quot; height=&quot;805&quot; data-origin-width=&quot;590&quot; data-origin-height=&quot;805&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;Content browser &amp;gt; Miscellaneous &amp;gt; String Table을 눌러 새로운 String Table을 만들어주자&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;2027&quot; data-origin-height=&quot;167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bg0m33/btsIGxaww01/8dp07PkRgnTVtOVmR3c7n0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bg0m33/btsIGxaww01/8dp07PkRgnTVtOVmR3c7n0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bg0m33/btsIGxaww01/8dp07PkRgnTVtOVmR3c7n0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbg0m33%2FbtsIGxaww01%2F8dp07PkRgnTVtOVmR3c7n0%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;2027&quot; height=&quot;167&quot; data-origin-width=&quot;2027&quot; data-origin-height=&quot;167&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;2026&quot; data-origin-height=&quot;849&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNLAXd/btsIGYr585x/EoGjdATkqK8ceYKsCCpGrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNLAXd/btsIGYr585x/EoGjdATkqK8ceYKsCCpGrk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNLAXd/btsIGYr585x/EoGjdATkqK8ceYKsCCpGrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNLAXd%2FbtsIGYr585x%2FEoGjdATkqK8ceYKsCCpGrk%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;2026&quot; height=&quot;849&quot; data-origin-width=&quot;2026&quot; data-origin-height=&quot;849&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 Key / Value 값을 만들어주자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 Namespace는 우리가 만든 StringTable의 이름임을 기억하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(본인은 ST_TestString이라는 스트링 테이블 파일을 만들었으므로, ST_TestString이 Namespace가 된다. 이는 위에서 따로 지정해줄 수도 있다.)&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;1074&quot; data-origin-height=&quot;137&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rG1uI/btsIHJVgFN4/zgOoB4eigObvkmJukR9dWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rG1uI/btsIHJVgFN4/zgOoB4eigObvkmJukR9dWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rG1uI/btsIHJVgFN4/zgOoB4eigObvkmJukR9dWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrG1uI%2FbtsIHJVgFN4%2FzgOoB4eigObvkmJukR9dWK%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;1074&quot; height=&quot;137&quot; data-origin-width=&quot;1074&quot; data-origin-height=&quot;137&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 Localization Dashboard를 키고 Gather from Packcages 에서 내가 만든 스트링 테이블의 위치 WildCards를 추가해주고 Gather Text를 실행해주자.&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;1549&quot; data-origin-height=&quot;91&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/co16lS/btsIGXteTqj/lhlgWo9BGljDLHteGw0O8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/co16lS/btsIGXteTqj/lhlgWo9BGljDLHteGw0O8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/co16lS/btsIGXteTqj/lhlgWo9BGljDLHteGw0O8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fco16lS%2FbtsIGXteTqj%2FlhlgWo9BGljDLHteGw0O8K%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;1549&quot; height=&quot;91&quot; data-origin-width=&quot;1549&quot; data-origin-height=&quot;91&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진행하면 Word Count가 증가한 것을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해 알 수 있는 점은, 우리가 새로운 (Key, Value)를 지정하면 그것은 엔진의 Default Language와 같다는 것을 알 수있다.&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;아무튼, 또 Korean의 .po를 수정해주고, Translation Edit로 해당 값을 열면&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;1812&quot; data-origin-height=&quot;154&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpKFxp/btsIHHwnXgW/2VEbKgfkRfOIM1j0X3RKQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpKFxp/btsIHHwnXgW/2VEbKgfkRfOIM1j0X3RKQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpKFxp/btsIHHwnXgW/2VEbKgfkRfOIM1j0X3RKQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpKFxp%2FbtsIHHwnXgW%2F2VEbKgfkRfOIM1j0X3RKQ1%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;1812&quot; height=&quot;154&quot; data-origin-width=&quot;1812&quot; data-origin-height=&quot;154&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;이제 Count words를 해주고 Compile text를 해주자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1365&quot; data-origin-height=&quot;179&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcluve/btsIHGK6j9A/c71Ks4DQJKJkgY2ZxH5VOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcluve/btsIHGK6j9A/c71Ks4DQJKJkgY2ZxH5VOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcluve/btsIHGK6j9A/c71Ks4DQJKJkgY2ZxH5VOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbcluve%2FbtsIHGK6j9A%2Fc71Ks4DQJKJkgY2ZxH5VOK%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;1365&quot; height=&quot;179&quot; data-origin-width=&quot;1365&quot; data-origin-height=&quot;179&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;613&quot; data-origin-height=&quot;57&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMfvtk/btsIIkAGGlI/KKGciNn6LIkxDYz3XXwcX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMfvtk/btsIIkAGGlI/KKGciNn6LIkxDYz3XXwcX1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMfvtk/btsIIkAGGlI/KKGciNn6LIkxDYz3XXwcX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMfvtk%2FbtsIIkAGGlI%2FKKGciNn6LIkxDYz3XXwcX1%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;613&quot; height=&quot;57&quot; data-origin-width=&quot;613&quot; data-origin-height=&quot;57&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;이를 공용적으로 사용하기 위해서는 TextManager 같은것을 하나 만들어놓고 그고세엇 StringTable 들을 다 긁어온 다음&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;h4 data-ke-size=&quot;size20&quot;&gt;4. FText의 구현&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 FText를 어떻게 사용하는지 알 수 있게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 실제로 언리얼 엔진에서 FText는 어떻게 구현되어 있을까?&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;이를 위해 엔진 코드에서 TextLocalizationManager.h 를 열어보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 TMap에 대한 코드를 찾으면 다음과 같이 typedef가 되어 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1721555405727&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/** Manages the currently loaded or registered text localizations. */
typedef TMap&amp;lt;FTextId, FDisplayStringEntry&amp;gt; FDisplayStringLookupTable;
    
FDisplayStringLookupTable DisplayStringLookupTable;&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;DisplayStringLookupTable에 우리가 사용하는 Key, Value를 저장하여 사용한다는 것을 알 수 있다.&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;b&gt;&quot;아니 우리는 Key Value 뿐만 아니라 Namespace도 지정했는데?&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 TMap&amp;lt;FTextId, FDisplayStringEntry&amp;gt; 에서 FTextId를 보면 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FTextId의 생성과 변수는 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1721555519335&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FTextId(const FTextKey&amp;amp; InNamespace, const FTextKey&amp;amp; InKey)
	: Namespace(InNamespace)
	, Key(InKey)
{
}

/** Namespace component of this text identity */
FTextKey Namespace;

/** Key component of this text identity */
FTextKey Key;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해 FTextId는 Namespace와 Key로 이루어졌다는 것을 알 수 있다.&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;TextLocalizationManager는 Singleton으로 작성되어 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1721555703062&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FTextLocalizationManager::GetDisplayString(const FTextKey&amp;amp; Namespace, const FTextKey&amp;amp; Key, const FString* const SourceString)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 우리가 실제로 FText를 정의하고 사용할 때, GetDisplayString함수로 넘어오게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1721556107138&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	FDisplayStringEntry* LiveEntry = DisplayStringLookupTable.Find(TextId);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 DisplayStringLooupTable에 데이터가 있으면 바로 Find로 찾아서 꺼내올 수 있게 된다.&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;FName 도 동일한 방법으로 정의 되는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 배울 때 FString에 비해 FName과 FText가 가볍다고 한 이유가 바로 이렇게 Key값으로 저장해두고 바로 찾을 수 있기 때문이다.&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;이제 실제로 FText를 정의하게 되면 어떻게 찾는지 플로우를 대략적으로 코드로만 설명하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1721556201951&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FText testText = NSLOCTEXT(&quot;A&quot;, &quot;B&quot;, &quot;C&quot;);

APlayerController* controller = Cast&amp;lt;APlayerController&amp;gt;(GetController());
controller-&amp;gt;GetHUD()-&amp;gt;DrawText(testText.ToString(), FColor::White, 500, 400);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 testText를 실제로 사용하게 될 때,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FText 객체가 들고있는 TextData-&amp;gt;TextHistory를 통해서 Text를 새로 업데이트 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1721556321273&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void FTextHistory_Base::UpdateDisplayString()
{
	check(!TextId.IsEmpty()); // CanUpdateDisplayString should prevent UpdateDisplayString being called
	LocalizedString = FTextLocalizationManager::Get().GetDisplayString(TextId.GetNamespace(), TextId.GetKey(), &amp;amp;SourceString);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 FTextHistory는 내부에서 FTextLocalizationManager의 GetDisplayString 함수를 호출한다.&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;FText에 대한 사용법과 구현에 대해서 간략하게 설명했습니다.&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;</description>
      <category>UnrealEngine/Impl</category>
      <category>UnrealEngine</category>
      <author>엄준식사생팬</author>
      <guid isPermaLink="true">https://openmynotepad.tistory.com/133</guid>
      <comments>https://openmynotepad.tistory.com/133#entry133comment</comments>
      <pubDate>Sun, 21 Jul 2024 19:06:29 +0900</pubDate>
    </item>
    <item>
      <title>[Unreal Engine 5] Gameplay Ability System - 2</title>
      <link>https://openmynotepad.tistory.com/132</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;233&quot; data-origin-height=&quot;257&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cESA0Y/btsFPqLT3ja/WuChwec6UARFKcebogUl2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cESA0Y/btsFPqLT3ja/WuChwec6UARFKcebogUl2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cESA0Y/btsFPqLT3ja/WuChwec6UARFKcebogUl2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcESA0Y%2FbtsFPqLT3ja%2FWuChwec6UARFKcebogUl2k%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;233&quot; height=&quot;257&quot; data-origin-width=&quot;233&quot; data-origin-height=&quot;257&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GameAbilitySystem의 가장 중요한 부분중 하나는 AbilitySystemComponent 다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 Component는 Actor에 추가할 수 있으며 AbilitySystem, Granding Abilities, Activating Abilities, Handling Notifications,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GameplayEffect applied 등 많은 것을 처리한다.&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;즉, 해당 캐릭터(Actor)가 GameplayAbilitySystem에 추가되길 원한다면, AbilitySystemComponent는 꼭 추가해야 한다.&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;211&quot; data-origin-height=&quot;231&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgaeDl/btsFODZfGP2/YKOU16zSTXRCB8nY5NVGlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgaeDl/btsFODZfGP2/YKOU16zSTXRCB8nY5NVGlk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgaeDl/btsFODZfGP2/YKOU16zSTXRCB8nY5NVGlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgaeDl%2FbtsFODZfGP2%2FYKOU16zSTXRCB8nY5NVGlk%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;211&quot; height=&quot;231&quot; data-origin-width=&quot;211&quot; data-origin-height=&quot;231&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 전 시간에 설명했듯이, 우리는 힘, 지능, 민첩과 같은 능력치를 Attribute라고 하기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 Attribute를 모아놓은 것을 AttributeSet이라고 한다.&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;이제 우리는 AbilitySystemComponent를 추가하여 Gameplay Ability System에 대해 알아볼 것이다.&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;AbilitySystemComponent는 꼭 Character가 가지고있지 않아도 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;468&quot; data-origin-height=&quot;361&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JPo5C/btsFRulZ32U/jLugW5SiFnz4l00Cevzv21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JPo5C/btsFRulZ32U/jLugW5SiFnz4l00Cevzv21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JPo5C/btsFRulZ32U/jLugW5SiFnz4l00Cevzv21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJPo5C%2FbtsFRulZ32U%2FjLugW5SiFnz4l00Cevzv21%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;468&quot; height=&quot;361&quot; data-origin-width=&quot;468&quot; data-origin-height=&quot;361&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;우리가 어떠한 Actor에 AbilitySystemComponent와 AttributeSet을 추가했다고 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이 Actor가 어떠한 영향에 의해 ( HP가 0이 되었다거나, 특정 로직으로 강제로 삭제해야 한다거나.. ) 파괴된다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AbilitySystemComponent와 AttributeSet도 당연히 파괴되어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 다시 Actor를 만들어 낸다면, AbilitySystemComponent와 AttributeSet이 재 생성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 '다시시작' (부활) 이 가능한 게임에서는 재사용이 가능할 수 있는 객체를 파괴하고 있다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;410&quot; data-origin-height=&quot;239&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s6OPA/btsFQgoLNUW/lhVEEvXmpgDZcIkESLKS90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s6OPA/btsFQgoLNUW/lhVEEvXmpgDZcIkESLKS90/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s6OPA/btsFQgoLNUW/lhVEEvXmpgDZcIkESLKS90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs6OPA%2FbtsFQgoLNUW%2FlhVEEvXmpgDZcIkESLKS90%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;239&quot; data-origin-width=&quot;410&quot; data-origin-height=&quot;239&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 Actor대신 어떠한 객체에 AbilitySystemComponent를 넣고, 해당 객체가 관리할 수 있다고 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우에는 Actor가 파괴되더라도, AbilitySystemComponent와 AttributeSet을 재사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리의 Actor의 힘이 10이였다고 해보자, 그 상태로 다시 시작을 한다고 하여서 힘이 10에서 변할 필요가 있을까?&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;468&quot; data-origin-height=&quot;327&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uKm8r/btsFSZsj9hi/NA7B80lOKiAk2pc5nV7Ny0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uKm8r/btsFSZsj9hi/NA7B80lOKiAk2pc5nV7Ny0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uKm8r/btsFSZsj9hi/NA7B80lOKiAk2pc5nV7Ny0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuKm8r%2FbtsFSZsj9hi%2FNA7B80lOKiAk2pc5nV7Ny0%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;468&quot; height=&quot;327&quot; data-origin-width=&quot;468&quot; data-origin-height=&quot;327&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파괴되더라도 Actor를 새로 생성하고, 우리가 관리하던 객체에 연결해주기만 하면 된다.&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;958&quot; data-origin-height=&quot;339&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnu3Ue/btsFOZVkpKg/5CoI896hLYLKjLeeXGHYFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnu3Ue/btsFOZVkpKg/5CoI896hLYLKjLeeXGHYFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnu3Ue/btsFOZVkpKg/5CoI896hLYLKjLeeXGHYFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbnu3Ue%2FbtsFOZVkpKg%2F5CoI896hLYLKjLeeXGHYFk%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;958&quot; height=&quot;339&quot; data-origin-width=&quot;958&quot; data-origin-height=&quot;339&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문서를 작성하면서, 우리의 캐릭터는 PlayerState에서 AbilitySystemComponent를 가지게 할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI는 동일하게 캐릭터가 AbilitySystemComponent를 가지게 된다.&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;460&quot; data-origin-height=&quot;58&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FVlxi/btsFRzHFOtu/5G2lbAquitLhnlK6HO7PI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FVlxi/btsFRzHFOtu/5G2lbAquitLhnlK6HO7PI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FVlxi/btsFRzHFOtu/5G2lbAquitLhnlK6HO7PI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFVlxi%2FbtsFRzHFOtu%2F5G2lbAquitLhnlK6HO7PI0%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;460&quot; height=&quot;58&quot; data-origin-width=&quot;460&quot; data-origin-height=&quot;58&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 PlayerState를 만들어 AbilitySystemComponent를 선언해준다.&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;736&quot; data-origin-height=&quot;56&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUvMZC/btsFQUeqO6C/X5pgpGpKyW4oSwIuqVkZ1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUvMZC/btsFQUeqO6C/X5pgpGpKyW4oSwIuqVkZ1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUvMZC/btsFQUeqO6C/X5pgpGpKyW4oSwIuqVkZ1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUvMZC%2FbtsFQUeqO6C%2FX5pgpGpKyW4oSwIuqVkZ1k%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;736&quot; height=&quot;56&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;56&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 PlayerState의 생성자에서 AbilitySystemComponent를 만들어준다.&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;여기서 궁금할건 SetIsReplicated와 SetReplicationMode이다.&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;이는 Replicate (복제) 에 대해서 조금 알아야 한다.&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;310&quot; data-origin-height=&quot;105&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYyvUO/btsFQy3Hbgi/IBxTvHvxsDVaUnfGkHBw61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYyvUO/btsFQy3Hbgi/IBxTvHvxsDVaUnfGkHBw61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYyvUO/btsFQy3Hbgi/IBxTvHvxsDVaUnfGkHBw61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYyvUO%2FbtsFQy3Hbgi%2FIBxTvHvxsDVaUnfGkHBw61%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;310&quot; height=&quot;105&quot; data-origin-width=&quot;310&quot; data-origin-height=&quot;105&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 멀티플레이어 게임에서, 어떠한 변수를 선언하고 해당 변수를 Replicated 변수로 선언했다고 하자.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;983&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mnUl7/btsFQufUZKO/boCp9RJ1bjQGuUkMxnWetK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mnUl7/btsFQufUZKO/boCp9RJ1bjQGuUkMxnWetK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mnUl7/btsFQufUZKO/boCp9RJ1bjQGuUkMxnWetK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmnUl7%2FbtsFQufUZKO%2FboCp9RJ1bjQGuUkMxnWetK%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;983&quot; height=&quot;352&quot; data-origin-width=&quot;983&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버는 모든 클라이언트들에게 변경된 해당 변수 값을 알려주고, 그 값으로 업데이트 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 행위를 복제(Replicate)라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러면, 멀티플레이어 개발을 해보신 분들은 어떠한 의구심을 품을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;? : 그렇다면 Replicate 선언된 변수가 클라이언트 중 하나에서 변경된다면, 그 값은 서버에 알려주나요? (혹은 변경 되어야 한다라고 알려주나요?) : (즉, Replicate가 양방향으로 작동하나요?)&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;복제는 단방향으로만 작동한다. 변수가 Replicate로 표시되면 서버는 해당 변경 사항을 알지 못하기 때문에 클라이언트에서는 해당 값을 변경해서는 안된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신 RPC (Remote Procedure call)로 처리합니다. 물론 이에 대해선 나중에 작성하겠습니다.&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;그럼 SetIsReplicated에 대해 알 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SetIsReplicated 함수는 해당 컴포넌트를 복제시킬것이냐 라는 것입니다.&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;ReplicationMode는 다음과 같이 요약할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;825&quot; data-origin-height=&quot;384&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceeEOo/btsFScFlZQ2/6E4UGOs9Ozd6nsiLtda2rk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceeEOo/btsFScFlZQ2/6E4UGOs9Ozd6nsiLtda2rk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceeEOo/btsFScFlZQ2/6E4UGOs9Ozd6nsiLtda2rk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FceeEOo%2FbtsFScFlZQ2%2F6E4UGOs9Ozd6nsiLtda2rk%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;825&quot; height=&quot;384&quot; data-origin-width=&quot;825&quot; data-origin-height=&quot;384&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;p data-ke-size=&quot;size16&quot;&gt;ReplicationMode::Full은 GameplayEffect가 모든 클라이언트에 복제됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ReplicationMode::Mixed는 GameplayEffect가 소유하고 있는 클라이언트에서만 복제됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Gameplay Cues와 Gameplay Tags는 모든 클라이언트에 복제됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ReplicationMode::Minimal은 GameplayEffect가 복제되지 않습니다. 그리고 Gameplay Cues와 Gameplay Tags는 모든 클라이언트에 복제됩니다.&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;위에서 설명했듯 우리가 아직 알지못하는 GameplayEffect, Gameplay Cues, Gameplay Tags가 나왔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 추후에 알아보도록 하며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Mixed는 플레이어에, Minimal은 AI에 적합하므로 해당 문서에서는 이와 같이 작성할 것입니다.&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;이제 위에서, 우리는 Actor에 AbilitySystemComponent가 붙어있어야 GameplayAbilitySystem에 참여할 수 있다고 했습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;421&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vDnMQ/btsFP2dewTK/pbD40UqOJEhXQWPCmtE11K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vDnMQ/btsFP2dewTK/pbD40UqOJEhXQWPCmtE11K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vDnMQ/btsFP2dewTK/pbD40UqOJEhXQWPCmtE11K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvDnMQ%2FbtsFP2dewTK%2FpbD40UqOJEhXQWPCmtE11K%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;600&quot; height=&quot;421&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;421&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AbilitySystem은 Owner Actor와 Avatar Actor를 설정할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Owner Actor는 해당 Component를 가지고 있는 Actor 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Avatar Actor는 해당 Component를 적용받고 화면에 보여질 Actor 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI (적군)은 Owner Actor와 Avatar Actor가 해당 Actor가 될 것입니다.&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;383&quot; data-origin-height=&quot;318&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dbuNUL/btsFR9u7l8B/S3unU2aTiof7dMlCLuh1d0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dbuNUL/btsFR9u7l8B/S3unU2aTiof7dMlCLuh1d0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dbuNUL/btsFR9u7l8B/S3unU2aTiof7dMlCLuh1d0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdbuNUL%2FbtsFR9u7l8B%2FS3unU2aTiof7dMlCLuh1d0%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;383&quot; height=&quot;318&quot; data-origin-width=&quot;383&quot; data-origin-height=&quot;318&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리의 캐릭터는 PlayerState가 AbilitySystemComponent를 가지기로 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러므로 Owner Actor는 PlayerState이며 Avatar Actor는 Actor 입니다.&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;869&quot; data-origin-height=&quot;40&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBiQKS/btsFQbAWoNQ/45hcWpF08moXI34d7XHf6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBiQKS/btsFQbAWoNQ/45hcWpF08moXI34d7XHf6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBiQKS/btsFQbAWoNQ/45hcWpF08moXI34d7XHf6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBiQKS%2FbtsFQbAWoNQ%2F45hcWpF08moXI34d7XHf6K%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;869&quot; height=&quot;40&quot; data-origin-width=&quot;869&quot; data-origin-height=&quot;40&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 OwnerActor와 AvatarActor를 설정해주어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 설정은 InitAbilityActorInfo 함수로 설정합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 문제는, 해당 함수를 언제 어디서 호출해야 하는가 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알아야 할 점은 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;InitAbilityActorInfo는 Possession이 끝난 후에 수행되어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(즉, Controller가 Pawn에 Set된 후에 수행되어야 합니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몇 가지 타이밍이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Actor가 AbilitySystemComponent를 가지고 있는 경우&lt;/p&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;237&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNRSye/btsFPGByETO/07ILA2VtkWdKJadhhslbl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNRSye/btsFPGByETO/07ILA2VtkWdKJadhhslbl1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNRSye/btsFPGByETO/07ILA2VtkWdKJadhhslbl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNRSye%2FbtsFPGByETO%2F07ILA2VtkWdKJadhhslbl1%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;237&quot; data-origin-width=&quot;366&quot; data-origin-height=&quot;237&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Server는 PossessedBy가 호출되면 InitAbilityActorInfo를 호출하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Client는 AcknowledgePossession이 호출되면 InitAbilityActorInfo를 호출하면 됩니다.&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;2. PlayerState가 AbilitySystemComponent를 가지고 있는 경우&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;326&quot; data-origin-height=&quot;203&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cT6on0/btsFSYUvqkq/n2DXAjp0v7rkNLIndLGdq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cT6on0/btsFSYUvqkq/n2DXAjp0v7rkNLIndLGdq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cT6on0/btsFSYUvqkq/n2DXAjp0v7rkNLIndLGdq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcT6on0%2FbtsFSYUvqkq%2Fn2DXAjp0v7rkNLIndLGdq1%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;326&quot; height=&quot;203&quot; data-origin-width=&quot;326&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;Server는 PossessedBy가 호출되면 InitAbilityActorInfo를 호출하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Client는 AcknowledgePossession을 사용할 수 없습니다. 왜냐면 우리의 AbilitySystemComponent는 PlayerState에 있기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신 OnRep_PlayerState를 사용합니다. 해당 함수는 PlayerState가 복제되었을때 오는 콜백 함수입니다.&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;3. AI 캐릭터&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;270&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kwS3z/btsFQRWf8op/INQvVy1JG4DhXjUaB5jFck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kwS3z/btsFQRWf8op/INQvVy1JG4DhXjUaB5jFck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kwS3z/btsFQRWf8op/INQvVy1JG4DhXjUaB5jFck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkwS3z%2FbtsFQRWf8op%2FINQvVy1JG4DhXjUaB5jFck%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;270&quot; height=&quot;270&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;270&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 캐릭터는 간단합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AbilitySystemComponent를 Actor가 가지고 있고 Controller가 Pawn에 Set되어야 한다는 제약도 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BeginPlay에서 해주면 됩니다.&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;이제 InitAbilityActorInfo를 해봅시다.&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;445&quot; data-origin-height=&quot;73&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/br8NEM/btsFPr48hA9/o2kP8kaizG6zmAhtXZFM71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/br8NEM/btsFPr48hA9/o2kP8kaizG6zmAhtXZFM71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/br8NEM/btsFPr48hA9/o2kP8kaizG6zmAhtXZFM71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbr8NEM%2FbtsFPr48hA9%2Fo2kP8kaizG6zmAhtXZFM71%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;445&quot; height=&quot;73&quot; data-origin-width=&quot;445&quot; data-origin-height=&quot;73&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Enemy는 BeginPlay에서 하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Owner와 Avatar는 Actor 자기 자신이므로 this로 등록합니다.&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;692&quot; data-origin-height=&quot;120&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/efx82U/btsFRddFLA4/eC7ijNuPBXc4umy6OZzO2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/efx82U/btsFRddFLA4/eC7ijNuPBXc4umy6OZzO2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/efx82U/btsFRddFLA4/eC7ijNuPBXc4umy6OZzO2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fefx82U%2FbtsFRddFLA4%2FeC7ijNuPBXc4umy6OZzO2K%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;692&quot; height=&quot;120&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;120&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PlayerState 상태에서는, 두 곳 (PossessedBy, OnRep_PlayerState) 에서 처리한다고 했습니다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;711&quot; data-origin-height=&quot;111&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JRjNU/btsFS2ih9cg/EUcq7TmcTEspMm5k9cShL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JRjNU/btsFS2ih9cg/EUcq7TmcTEspMm5k9cShL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JRjNU/btsFS2ih9cg/EUcq7TmcTEspMm5k9cShL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJRjNU%2FbtsFS2ih9cg%2FEUcq7TmcTEspMm5k9cShL0%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;711&quot; height=&quot;111&quot; data-origin-width=&quot;711&quot; data-origin-height=&quot;111&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;이 것으로 AbilitySystemComponent가 등록이 완료되었습니다.&lt;/p&gt;</description>
      <category>UnrealEngine/기능</category>
      <category>UnrealEngine</category>
      <author>엄준식사생팬</author>
      <guid isPermaLink="true">https://openmynotepad.tistory.com/132</guid>
      <comments>https://openmynotepad.tistory.com/132#entry132comment</comments>
      <pubDate>Sun, 17 Mar 2024 21:57:11 +0900</pubDate>
    </item>
    <item>
      <title>[Unreal Engine 5] Gameplay Ability System - 1</title>
      <link>https://openmynotepad.tistory.com/131</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Gameplay Ability System의 정보글이 적어 작성하는 포스트&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 개요&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Gameplay Ability System의 내용은 언리얼 엔진 문서에도 잘 나와있다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;b&gt;게임플레이 어빌리티 시스템(Gameplay Ability System)&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;은 RPG나 MOBA 타이틀에서 볼 수 있는 어빌리티 및 어트리뷰트 유형을 구축하기 위한 고도로 유연한 프레임워크입니다. 게임 내 캐릭터가 사용할 액션이나 패시브 어빌리티, 이러한 액션의 결과로 다양한 어트리뷰트를 높이거나 낮추는 상태 이펙트를 만들 수 있고, '재사용 대기 시간' 타이머나 자원 비용을 구현하여 액션의 사용 빈도를 조절하거나, 어빌리티의 레벨과 레벨에 따른 이펙트를 변경하거나, 파티클 및 사운드 이펙트를 활성화하는 등의 작업이 가능합니다. 게임플레이 어빌리티 시스템을 사용하면 점프처럼 단순한 것부터 최신 RPG나 MOBA 타이틀 내 인기 캐릭터의 기술 모음처럼 복잡한 것까지 다양한 인게임 어빌리티를 설계 및 구현하고 효과적으로 연결할 수 있습니다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;p data-ke-size=&quot;size16&quot;&gt;Gameplay Ability System은 게임 내 능력을 설계, 구현 하기 쉽게 도와주고 네트워크 게임에서 효율적으로 작동할 수 있게 도와준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;듣기만 하면 꽤 좋아 보이긴 하는데, 약간 모호하기도 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 무엇인지에 대해 조금 이야기 해보도록 하겠다.&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;우리가 RPG 게임을 하나 만든다고 생각해보자&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;RPG 또는 롤플레잉 게임은 일반적으로 다양한 요소를 포함하는&lt;b&gt; '상당히'&lt;/b&gt; 큰 게임이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;307&quot; data-origin-height=&quot;176&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bILz9L/btsFOY2POaF/AOdouhWtQd1klSn70CiAA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bILz9L/btsFOY2POaF/AOdouhWtQd1klSn70CiAA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bILz9L/btsFOY2POaF/AOdouhWtQd1klSn70CiAA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbILz9L%2FbtsFOY2POaF%2FAOdouhWtQd1klSn70CiAA0%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;307&quot; height=&quot;176&quot; data-origin-width=&quot;307&quot; data-origin-height=&quot;176&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;RPG 게임에서는 힘, 지능, 민첩, 체력, 마나와 같은 능력치가 있을 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 들은 게임 플레이에 중요한 방식으로 영향을 미치는 것들이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이를 일반적으로 &lt;b&gt;'Attribute'&lt;/b&gt; 라고 한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;우리가 어떠한 Attribute에 변화를 가하면, 다른 Attribute들이 영향을 받을 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;또한 Attribute는 다른 여려 요인의 영향을 받을 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;힘(Str)을 찍으면 캐릭터의 물리 공격력(Damage)이 올라간다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt; A의 물리 공격력(Damage)으로 B를 공격하면, Armor, CriticalChance 같은 Attribute들에 영향을 받아 최종 데미지가 계산된다. &lt;/b&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;372&quot; data-origin-height=&quot;161&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bu5akr/btsFOWEn7BB/46SlgVHkQEu3cTxVpKGlJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bu5akr/btsFOWEn7BB/46SlgVHkQEu3cTxVpKGlJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bu5akr/btsFOWEn7BB/46SlgVHkQEu3cTxVpKGlJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbu5akr%2FbtsFOWEn7BB%2F46SlgVHkQEu3cTxVpKGlJ0%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;161&quot; data-origin-width=&quot;372&quot; data-origin-height=&quot;161&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 Damage라는 Attribute로 어떠한 캐릭터를 공격했을때, 이 공격 이라는 행위는 Ability로 인해 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RPG에서 어떠한 캐릭터를 공격하여, 그 캐릭터가 죽었다면 우리는 EXP (경험치) 라는 것을 얻는다.&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;또한 우리의 캐릭터는 Buff/DeBuff 같은 것들을 받을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포션을 마시면 체력/마나가 증가하거나, 불 지형에 닿으면 '발화' 같은 디버프에 걸려 체력이 점차 감소한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 이러한 효과들은 캐릭터의 Attribute 값을 변경하는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 Attribute 값을 변경하는 것을 &lt;b&gt;'Effects'&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;248&quot; data-origin-height=&quot;223&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxvnNe/btsFP2Rld3j/nqmnnLSK5Lt6d3BTkmsRIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxvnNe/btsFP2Rld3j/nqmnnLSK5Lt6d3BTkmsRIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxvnNe/btsFP2Rld3j/nqmnnLSK5Lt6d3BTkmsRIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxvnNe%2FbtsFP2Rld3j%2FnqmnnLSK5Lt6d3BTkmsRIk%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;248&quot; height=&quot;223&quot; data-origin-width=&quot;248&quot; data-origin-height=&quot;223&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;/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;이는 우리가 몬스터의 Attribute에 Effect를 적용시킨것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 해당 Effect가 게임 내에서 적절하게 작동하는지 '시각적', '청각적' 으로 확인할 수 있어야 하는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 &lt;b&gt;GameplayCues&lt;/b&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;이 내용들은 RPG에만 쓰이는 것 뿐만아니라, 잘 생각해보면 여러 장르의 게임에서 많이 사용되고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 게임들은 HP/MP같은 Attribute들을 사용하고, 다른 캐릭터에게 Effect를 적용시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요점은, 게임이 다양한 처리를 맡게 됨으로써 많은 효과들로 인해 복잡해질 수 있다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게임이 복잡해질수록, 오브젝트간의 관계는 더 많아진다는 것이고&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;Gameplay Ability System은 프레임워크를 제공하여 매우 복잡한 게임을 개발하기 쉽게 만들어준다.&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;Gameplay Ability System은 네트워크와 관련된 정보들이 많이 물려있는데, 이에 대한 내용들도 간단하게 나마 작성할 예정이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네트워크를 몰라도 알 수 있도록 작성할 예정이며 개요는 이렇게 마치겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 위에 설명한 내용 말고도 GameplayAbility, Ability Task, Gameplay Tag등이 있다. 이 내용은 앞으로 추가되는 문서에서 다룰 예정이다.&lt;/p&gt;</description>
      <category>UnrealEngine/기능</category>
      <category>UnrealEngine</category>
      <author>엄준식사생팬</author>
      <guid isPermaLink="true">https://openmynotepad.tistory.com/131</guid>
      <comments>https://openmynotepad.tistory.com/131#entry131comment</comments>
      <pubDate>Fri, 15 Mar 2024 22:28:28 +0900</pubDate>
    </item>
    <item>
      <title>[Unreal Editor] 4. Custom Tab</title>
      <link>https://openmynotepad.tistory.com/130</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;606&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqAmGs/btsDzyxzjeX/UHbrl4COCMdAaKDKAcbel0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqAmGs/btsDzyxzjeX/UHbrl4COCMdAaKDKAcbel0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqAmGs/btsDzyxzjeX/UHbrl4COCMdAaKDKAcbel0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqAmGs%2FbtsDzyxzjeX%2FUHbrl4COCMdAaKDKAcbel0%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;1006&quot; height=&quot;606&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;606&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;b&gt;Slate&lt;/b&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;Slate&lt;/b&gt;에 대해 알아야합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Slate&lt;/b&gt;는 이 곳에 설명해 두었습니다. &lt;i&gt;(추후 추가 예정 )&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 언리얼 엔진 에디터를 커스터마이징 해야 하기 때문에, 엔진이 시작과 동시에 기능이 붙어야 한다는 것을 알아둬야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔진이 시작됨과 동시에, 즉 &lt;b&gt;StartupModule&lt;/b&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;FGlobalTabmanager&lt;/b&gt;를 통해서 요청합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1031&quot; data-origin-height=&quot;126&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3h0Tw/btsDyCmGMlk/Jm5wMKrVqGGT5KkaUJfsEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3h0Tw/btsDyCmGMlk/Jm5wMKrVqGGT5KkaUJfsEk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3h0Tw/btsDyCmGMlk/Jm5wMKrVqGGT5KkaUJfsEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3h0Tw%2FbtsDyCmGMlk%2FJm5wMKrVqGGT5KkaUJfsEk%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;1031&quot; height=&quot;126&quot; data-origin-width=&quot;1031&quot; data-origin-height=&quot;126&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;FOnSpawnTab&lt;/b&gt; 객체를 확인해보면, &lt;b&gt;Delegate&lt;/b&gt;임을 알 수 있습니다. 이에 맞춰서 함수를 하나 만들어 바인딩 해주어야 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;669&quot; data-origin-height=&quot;19&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqPz6T/btsDs3lrOBd/t3pExA06xMvezDp8J9j090/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqPz6T/btsDs3lrOBd/t3pExA06xMvezDp8J9j090/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqPz6T/btsDs3lrOBd/t3pExA06xMvezDp8J9j090/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqPz6T%2FbtsDs3lrOBd%2Ft3pExA06xMvezDp8J9j090%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;669&quot; height=&quot;19&quot; data-origin-width=&quot;669&quot; data-origin-height=&quot;19&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;566&quot; data-origin-height=&quot;37&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KiyJh/btsDsYq1G2x/KNdFkBwU5eQkKXok6qmsX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KiyJh/btsDsYq1G2x/KNdFkBwU5eQkKXok6qmsX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KiyJh/btsDsYq1G2x/KNdFkBwU5eQkKXok6qmsX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKiyJh%2FbtsDsYq1G2x%2FKNdFkBwU5eQkKXok6qmsX0%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;566&quot; height=&quot;37&quot; data-origin-width=&quot;566&quot; data-origin-height=&quot;37&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 탭 생성이 끝났으니, 탭이 눌러졌을 때 어떠한 창이 떠야 하는지를 알려주어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 작성합니다.&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;705&quot; data-origin-height=&quot;84&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bp1yLn/btsDuSYbKyT/J64qcJGUvaPZN1TxHa2XA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bp1yLn/btsDuSYbKyT/J64qcJGUvaPZN1TxHa2XA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bp1yLn/btsDuSYbKyT/J64qcJGUvaPZN1TxHa2XA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbp1yLn%2FbtsDuSYbKyT%2FJ64qcJGUvaPZN1TxHa2XA0%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;705&quot; height=&quot;84&quot; data-origin-width=&quot;705&quot; data-origin-height=&quot;84&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;SNew&lt;/b&gt; 매크로와 &lt;b&gt;ETabRole&lt;/b&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;SNew&lt;/b&gt;는 괄호안에 들어가는 새로운 &lt;b&gt;Slate&lt;/b&gt; 객체를 만들겠다는 뜻입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Slate&lt;/b&gt; 객체는 &lt;b&gt;SNew&lt;/b&gt; 또는 &lt;b&gt;SAssignNew&lt;/b&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;ETabRole&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;MajorTab&lt;/b&gt; : 탭의 최상위 레벨이며 모드 패널이나 월드 아웃라이너 같은 에디터UI의 최상위 섹션입니다. MatorTab에는 여러 개의 PanelTab이 포함될 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PanelTab&lt;/b&gt; : 디테일 패널이나 콘텐츠 브라우저 같은 콘텐츠 패널이 포함된 탭입니다. PanelTab은 MajorTab, PanelTab, NomadTab이 포함될 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;NomadTab&lt;/b&gt; : MajorTab / PanelTab 에 맞지 않는 콘텐츠를 보관하는데 사용하는 독립적인 탭입니다. 에셋이나 다른 유형의 콘텐츠에 대한 에디터를 보유하는데 사용할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DocumentTab&lt;/b&gt; : Material이나 Blueprint같은 특정 에셋이나 리소스에 대한 문서를 표시하는데 사용되는 PanelTab 유형입니다. 일반적으로 에셋 / 리소스 당 단일 인스턴스를 가지며 에디터 UI에서 붙이거나 (도킹하거나) 뗄 수 있습니다.&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;/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;493&quot; data-origin-height=&quot;74&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bku8fl/btsDwETaH8G/a5kJKmzhinrTQuPrOKJLP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bku8fl/btsDwETaH8G/a5kJKmzhinrTQuPrOKJLP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bku8fl/btsDwETaH8G/a5kJKmzhinrTQuPrOKJLP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbku8fl%2FbtsDwETaH8G%2Fa5kJKmzhinrTQuPrOKJLP0%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;493&quot; height=&quot;74&quot; data-origin-width=&quot;493&quot; data-origin-height=&quot;74&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;이를 통해 우리가 만든 새로운 NomadTab이 생성되게 됩니다.&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;380&quot; data-origin-height=&quot;463&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dld5V8/btsDxj2gyWI/oW33iPpWfhlLStLIULvkHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dld5V8/btsDxj2gyWI/oW33iPpWfhlLStLIULvkHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dld5V8/btsDxj2gyWI/oW33iPpWfhlLStLIULvkHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdld5V8%2FbtsDxj2gyWI%2FoW33iPpWfhlLStLIULvkHK%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;380&quot; height=&quot;463&quot; data-origin-width=&quot;380&quot; data-origin-height=&quot;463&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>UnrealEngine/Editor</category>
      <category>UnrealEditor</category>
      <author>엄준식사생팬</author>
      <guid isPermaLink="true">https://openmynotepad.tistory.com/130</guid>
      <comments>https://openmynotepad.tistory.com/130#entry130comment</comments>
      <pubDate>Tue, 16 Jan 2024 15:53:02 +0900</pubDate>
    </item>
    <item>
      <title>[Unreal Editor] 3. EditorAssetLibrary, EditorUtilityLibrary</title>
      <link>https://openmynotepad.tistory.com/129</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 에디터의 어떠한 에셋에 대해서 '특정 작업'을 하려면 &lt;b&gt;EditorAssetLibrary&lt;/b&gt;와 &lt;b&gt;EditorUtilityLibrary&lt;/b&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;pre id=&quot;code_1704771107339&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;UEditorUtilityLibrary::GetSelectedAssets();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 사용하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해, 사용이 되지 않는 에셋에 대해서 삭제도 진행할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1704771193561&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void UQuickAssetAction::RemoveUnusedAssets()
{
	TArray&amp;lt;FAssetData&amp;gt; SelectedAssetsData = UEditorUtilityLibrary::GetSelectedAssetData();
 	TArray&amp;lt;FAssetData&amp;gt; UnusedAssetsData;

	//FixUpRedirectors();

	for (const FAssetData&amp;amp; SelectedAsset : SelectedAssetsData)
	{
		TArray&amp;lt;FString&amp;gt; AssetReferencers = UEditorAssetLibrary::FindPackageReferencersForAsset(SelectedAsset.ObjectPath.ToString());

		if (AssetReferencers.Num() == 0)
		{
			UnusedAssetsData.Add(SelectedAsset);
		}
	}

	if (UnusedAssetsData.Num() == 0)
	{
		ShowMessageDialog(EAppMsgType::Ok, TEXT(&quot;No unused asset found among selected assets&quot;), false);
		return;
	}

	const int32 NumOfAssetsDeleted = ObjectTools::DeleteAssets(UnusedAssetsData);

	if (NumOfAssetsDeleted == 0) return;

	ShowNotifyInfo(TEXT(&quot;Succesfully deleted &quot;) + FString::FromInt(NumOfAssetsDeleted) + TEXT(&quot; unused Assets&quot;));
}&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;이를 사용하면 Level에 배치되지 않았거나 reference가 없는 '클릭된' 모든 오브젝트를 삭제한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 삭제하기에는 알림 기능이 없으므로, Editor의 힘을 빌려 ObjectTool에서 특정 알림을 낼 수 있다.&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;273&quot; data-origin-height=&quot;214&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b11rEQ/btsC53GcNM0/3L9XZiOwTjEAWMjTZcw5g1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b11rEQ/btsC53GcNM0/3L9XZiOwTjEAWMjTZcw5g1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b11rEQ/btsC53GcNM0/3L9XZiOwTjEAWMjTZcw5g1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb11rEQ%2FbtsC53GcNM0%2F3L9XZiOwTjEAWMjTZcw5g1%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;273&quot; height=&quot;214&quot; data-origin-width=&quot;273&quot; data-origin-height=&quot;214&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;606&quot; data-origin-height=&quot;740&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/md1Tm/btsC55xgR1U/CmrJzxY2dX3tG4MOBbSf10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/md1Tm/btsC55xgR1U/CmrJzxY2dX3tG4MOBbSf10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/md1Tm/btsC55xgR1U/CmrJzxY2dX3tG4MOBbSf10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmd1Tm%2FbtsC55xgR1U%2FCmrJzxY2dX3tG4MOBbSf10%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;606&quot; height=&quot;740&quot; data-origin-width=&quot;606&quot; data-origin-height=&quot;740&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;</description>
      <category>UnrealEngine/Editor</category>
      <category>UnrealEditor</category>
      <author>엄준식사생팬</author>
      <guid isPermaLink="true">https://openmynotepad.tistory.com/129</guid>
      <comments>https://openmynotepad.tistory.com/129#entry129comment</comments>
      <pubDate>Tue, 9 Jan 2024 12:35:26 +0900</pubDate>
    </item>
    <item>
      <title>[Unreal Editor] 2. Asset Action Utility</title>
      <link>https://openmynotepad.tistory.com/128</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 언리얼 에디터에서 특정 에셋이나 액터들에 어떠한 '로직'을 행할 때 유용한 &lt;b&gt;ScriptedAction&lt;/b&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;이를 위해 언리얼 엔진에서는 다양한 Built-in Class를 제공 하고 있습니다.&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;AssetActionUtility : 에셋들에 대한 액션&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ActorActionUtility : 액터들에 대한 액션&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번엔 테스트를 위해 &lt;b&gt;TestFunc&lt;/b&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;Add C++ Class&lt;/b&gt;를 하여 &lt;b&gt;AssetActionUtility&lt;/b&gt;를 만들어줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;931&quot; data-origin-height=&quot;246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Dm5Nd/btsCzR6uCat/zO8TOS5DZjRkLLjy5OIws0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Dm5Nd/btsCzR6uCat/zO8TOS5DZjRkLLjy5OIws0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Dm5Nd/btsCzR6uCat/zO8TOS5DZjRkLLjy5OIws0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDm5Nd%2FbtsCzR6uCat%2FzO8TOS5DZjRkLLjy5OIws0%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;931&quot; height=&quot;246&quot; data-origin-width=&quot;931&quot; data-origin-height=&quot;246&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 우리가 만든 플러그인에 만들어야 하므로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;PluginName(Editor)&lt;/b&gt; 로 변경하여 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Class Type&lt;/b&gt;은 .h와 .cpp를 분리할 것 이므로 &lt;b&gt;Public&lt;/b&gt;으로 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;946&quot; data-origin-height=&quot;580&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HIn46/btsCyoYlD1Q/KppL7MhJAdKEdtM2KEYk41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HIn46/btsCyoYlD1Q/KppL7MhJAdKEdtM2KEYk41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HIn46/btsCyoYlD1Q/KppL7MhJAdKEdtM2KEYk41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHIn46%2FbtsCyoYlD1Q%2FKppL7MhJAdKEdtM2KEYk41%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;946&quot; height=&quot;580&quot; data-origin-width=&quot;946&quot; data-origin-height=&quot;580&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;p data-ke-size=&quot;size16&quot;&gt;이로써 첫 &lt;b&gt;AssetActionUtility&lt;/b&gt;가 만들어 졌습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 만들고 나면, &lt;b&gt;AssetActionUtility.h&lt;/b&gt; 에서 컴파일 에러가 발생할 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;493&quot; data-origin-height=&quot;242&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxNibK/btsCyLZ2iex/i2FYBNlPE7Y7ehaZjm1WHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxNibK/btsCyLZ2iex/i2FYBNlPE7Y7ehaZjm1WHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxNibK/btsCyLZ2iex/i2FYBNlPE7Y7ehaZjm1WHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxNibK%2FbtsCyLZ2iex%2Fi2FYBNlPE7Y7ehaZjm1WHK%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;493&quot; height=&quot;242&quot; data-origin-width=&quot;493&quot; data-origin-height=&quot;242&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;AssetActionUtility&lt;/b&gt;를 사용할 것이라고 &lt;b&gt;Build.cs&lt;/b&gt;에게 알려야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;IDE&lt;/b&gt;에서 &lt;b&gt;AssetActionUtility&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;315&quot; data-origin-height=&quot;267&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOqifR/btsCzR6uGHV/Pp86qUp3oXmQVvCj6Mh6Kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOqifR/btsCzR6uGHV/Pp86qUp3oXmQVvCj6Mh6Kk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOqifR/btsCzR6uGHV/Pp86qUp3oXmQVvCj6Mh6Kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOqifR%2FbtsCzR6uGHV%2FPp86qUp3oXmQVvCj6Mh6Kk%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;315&quot; height=&quot;267&quot; data-origin-width=&quot;315&quot; data-origin-height=&quot;267&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;Blutility&lt;/b&gt;는 모듈 이름이며, 우리가 만든 모듈이 이 &lt;b&gt;Blutility&lt;/b&gt;를 사용한다고 알려주어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 만든 플러그인의 &lt;b&gt;Build.cs&lt;/b&gt;를 확인합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;475&quot; data-origin-height=&quot;106&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFoS5A/btsCJkM6I7Q/44Us8halIFpWWLLDo9eML1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFoS5A/btsCJkM6I7Q/44Us8halIFpWWLLDo9eML1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFoS5A/btsCJkM6I7Q/44Us8halIFpWWLLDo9eML1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFoS5A%2FbtsCJkM6I7Q%2F44Us8halIFpWWLLDo9eML1%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;475&quot; height=&quot;106&quot; data-origin-width=&quot;475&quot; data-origin-height=&quot;106&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;623&quot; data-origin-height=&quot;403&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bS8F7b/btsCF80xvLD/GdtJEkA0KNesaA09kmuGMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bS8F7b/btsCF80xvLD/GdtJEkA0KNesaA09kmuGMK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bS8F7b/btsCF80xvLD/GdtJEkA0KNesaA09kmuGMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbS8F7b%2FbtsCF80xvLD%2FGdtJEkA0KNesaA09kmuGMK%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;623&quot; height=&quot;403&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;403&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;다음과 같이 dependency에 &lt;b&gt;&quot;Blutility&quot;&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;604&quot; data-origin-height=&quot;129&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c36H0t/btsCG35UQYN/igEVKgdoMk6nwpOkiYChRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c36H0t/btsCG35UQYN/igEVKgdoMk6nwpOkiYChRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c36H0t/btsCG35UQYN/igEVKgdoMk6nwpOkiYChRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc36H0t%2FbtsCG35UQYN%2FigEVKgdoMk6nwpOkiYChRK%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;604&quot; height=&quot;129&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;129&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;Blutility&lt;/b&gt;에는 &lt;b&gt;Private&lt;/b&gt;한 폴더와 모듈이 있습니다. 이 또한 포함해주어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 경로 설정을 통해 포함할 수 있는데, cs를 사용해 &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;408&quot; data-origin-height=&quot;374&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bI6D29/btsCy4kQmqk/BLlQ6XRpNrRUpQLLtRy8Rk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bI6D29/btsCy4kQmqk/BLlQ6XRpNrRUpQLLtRy8Rk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bI6D29/btsCy4kQmqk/BLlQ6XRpNrRUpQLLtRy8Rk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbI6D29%2FbtsCy4kQmqk%2FBLlQ6XRpNrRUpQLLtRy8Rk%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;408&quot; height=&quot;374&quot; data-origin-width=&quot;408&quot; data-origin-height=&quot;374&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;801&quot; data-origin-height=&quot;442&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/czCIO9/btsCyLltYlA/kPGJOaedtDlZgHJ2FwKUuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/czCIO9/btsCyLltYlA/kPGJOaedtDlZgHJ2FwKUuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czCIO9/btsCyLltYlA/kPGJOaedtDlZgHJ2FwKUuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FczCIO9%2FbtsCyLltYlA%2FkPGJOaedtDlZgHJ2FwKUuk%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;801&quot; height=&quot;442&quot; data-origin-width=&quot;801&quot; data-origin-height=&quot;442&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;이제 UE5를 종료하고, IDE에서 컴파일 해보면 정상적으로 컴파일이 되는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 우리가 만든 버튼이 눌려지면, Test 라는 문자열을 화면에 출력하도록 만들겠습니다.&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;AssetAction.h&lt;/b&gt; 로 돌아가 다음과 같이 테스트 함수를 작성합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;519&quot; data-origin-height=&quot;169&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUyD5c/btsCF7N6cck/mvdhWXdc7fVdGhdquIUDBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUyD5c/btsCF7N6cck/mvdhWXdc7fVdGhdquIUDBk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUyD5c/btsCF7N6cck/mvdhWXdc7fVdGhdquIUDBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUyD5c%2FbtsCF7N6cck%2FmvdhWXdc7fVdGhdquIUDBk%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;519&quot; height=&quot;169&quot; data-origin-width=&quot;519&quot; data-origin-height=&quot;169&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;567&quot; data-origin-height=&quot;116&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u5izU/btsCyoKO1PC/XgkuFoFlZjNcWLa7GYUwL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u5izU/btsCyoKO1PC/XgkuFoFlZjNcWLa7GYUwL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u5izU/btsCyoKO1PC/XgkuFoFlZjNcWLa7GYUwL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu5izU%2FbtsCyoKO1PC%2FXgkuFoFlZjNcWLa7GYUwL1%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;567&quot; height=&quot;116&quot; data-origin-width=&quot;567&quot; data-origin-height=&quot;116&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;이제 우리가 임의의 Actor를 만들고, 우클릭하여 &lt;b&gt;'Scripted Asset Actions'&lt;/b&gt; 에서 &lt;b&gt;TestFunc&lt;/b&gt;를 클릭하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화면에 &quot;Test&quot;라는 문자가 나타나게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;522&quot; data-origin-height=&quot;603&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/R2S2m/btsCyJVugZY/qfz6ZgQgtrOgZNKIA27KK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/R2S2m/btsCyJVugZY/qfz6ZgQgtrOgZNKIA27KK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/R2S2m/btsCyJVugZY/qfz6ZgQgtrOgZNKIA27KK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FR2S2m%2FbtsCyJVugZY%2Fqfz6ZgQgtrOgZNKIA27KK1%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;522&quot; height=&quot;603&quot; data-origin-width=&quot;522&quot; data-origin-height=&quot;603&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;추가로 만약, 여기까지 정상적으로 진행했는데 Scripted AssetActions 나오지 않는다면,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Editor Utility Blueprint에서 우리가 만든 AssetAction을 부모로 한 새로운 블루프린트를 만들어주면 나타납니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;437&quot; data-origin-height=&quot;234&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cpF5r8/btsCzTQO6n9/NKJiwhh0U4N1MDKhJxRMpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cpF5r8/btsCzTQO6n9/NKJiwhh0U4N1MDKhJxRMpk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cpF5r8/btsCzTQO6n9/NKJiwhh0U4N1MDKhJxRMpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcpF5r8%2FbtsCzTQO6n9%2FNKJiwhh0U4N1MDKhJxRMpk%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;437&quot; height=&quot;234&quot; data-origin-width=&quot;437&quot; data-origin-height=&quot;234&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;626&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tuWcd/btsCy6bSsMr/fOB6itSzbtA1IS7DAHH5T0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tuWcd/btsCy6bSsMr/fOB6itSzbtA1IS7DAHH5T0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tuWcd/btsCy6bSsMr/fOB6itSzbtA1IS7DAHH5T0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtuWcd%2FbtsCy6bSsMr%2FfOB6itSzbtA1IS7DAHH5T0%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;626&quot; height=&quot;360&quot; data-origin-width=&quot;626&quot; data-origin-height=&quot;360&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>UnrealEngine/Editor</category>
      <category>UnrealEditor</category>
      <author>엄준식사생팬</author>
      <guid isPermaLink="true">https://openmynotepad.tistory.com/128</guid>
      <comments>https://openmynotepad.tistory.com/128#entry128comment</comments>
      <pubDate>Tue, 26 Dec 2023 09:06:51 +0900</pubDate>
    </item>
    <item>
      <title>[Unreal Editor] 1. Plugins</title>
      <link>https://openmynotepad.tistory.com/127</link>
      <description>&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;p data-ke-size=&quot;size16&quot;&gt;그리고 Editor를 확장하려면 자체 모듈과 Resource Dropdown을 만들어야 합니다.&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;Custom Editor 문서에서는 간단하게 주요 사항만 작성합니다.&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;모듈은 자체적으로 '빌드 평가 파일' 이 필요합니다. 이는 [ModuleName].Build.cs 로 시작합니다.우리가 어떠한 프로젝트를 만들때도 이것이 만들어지는것을 볼 수 있습니다.&lt;br /&gt;즉, 프로젝트도 하나의 모듈입니다.&lt;/li&gt;
&lt;li&gt;모든 모듈은 빌드 액세스 파일에 추가하여, 프로젝트에 포함할 수 있습니다.&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;언리얼 에디터에서 Edit &amp;gt; Plugins를 클릭합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;482&quot; data-origin-height=&quot;317&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZqXge/btsBVHjdPa1/DbTfz275RYHnxuYK5YanXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZqXge/btsBVHjdPa1/DbTfz275RYHnxuYK5YanXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZqXge/btsBVHjdPa1/DbTfz275RYHnxuYK5YanXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZqXge%2FbtsBVHjdPa1%2FDbTfz275RYHnxuYK5YanXk%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;482&quot; height=&quot;317&quot; data-origin-width=&quot;482&quot; data-origin-height=&quot;317&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 곳에서 많은 플러그인들을 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Add를 클릭합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1670&quot; data-origin-height=&quot;1087&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFFqkm/btsBT1a4tmw/lQQvThyWVkUeQHdJ8LIR4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFFqkm/btsBT1a4tmw/lQQvThyWVkUeQHdJ8LIR4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFFqkm/btsBT1a4tmw/lQQvThyWVkUeQHdJ8LIR4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFFqkm%2FbtsBT1a4tmw%2FlQQvThyWVkUeQHdJ8LIR4k%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;1670&quot; height=&quot;1087&quot; data-origin-width=&quot;1670&quot; data-origin-height=&quot;1087&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;Blank를 클릭하고, 플러그인 이름을 작성합니다.&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;1670&quot; data-origin-height=&quot;1087&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dh4YxF/btsBUJIlXn7/GtYY8f9QVCtLw8ntLStbK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dh4YxF/btsBUJIlXn7/GtYY8f9QVCtLw8ntLStbK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dh4YxF/btsBUJIlXn7/GtYY8f9QVCtLw8ntLStbK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdh4YxF%2FbtsBUJIlXn7%2FGtYY8f9QVCtLw8ntLStbK0%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;1670&quot; height=&quot;1087&quot; data-origin-width=&quot;1670&quot; data-origin-height=&quot;1087&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;p data-ke-size=&quot;size16&quot;&gt;플러그인 생성이 완료되면, 프로젝트 내의 Plugins 폴더에서 내가 만든 플러그인을 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 [ModuleName].uplugin을 더블클릭합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;484&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OCTFN/btsBT0jv3m9/XKaOkrQTGlyeWSzKo19vqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OCTFN/btsBT0jv3m9/XKaOkrQTGlyeWSzKo19vqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OCTFN/btsBT0jv3m9/XKaOkrQTGlyeWSzKo19vqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOCTFN%2FbtsBT0jv3m9%2FXKaOkrQTGlyeWSzKo19vqk%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;484&quot; height=&quot;483&quot; data-origin-width=&quot;484&quot; data-origin-height=&quot;483&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;p data-ke-size=&quot;size16&quot;&gt;우리가 만들 플러그인에 대한 정보가 작성되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 중, 유심히 봐야 할 것은 'Type'과 'LoadingPhase' 입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;259&quot; data-origin-height=&quot;388&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6IZX3/btsBUc48LiN/tSK3NOFly9RkOXpVzFDZQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6IZX3/btsBUc48LiN/tSK3NOFly9RkOXpVzFDZQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6IZX3/btsBUc48LiN/tSK3NOFly9RkOXpVzFDZQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6IZX3%2FbtsBUc48LiN%2FtSK3NOFly9RkOXpVzFDZQK%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;259&quot; height=&quot;388&quot; data-origin-width=&quot;259&quot; data-origin-height=&quot;388&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;Type은 해당 플러그인이 '게임 코드'에 영향을 주는 지, 에디터에 영향을 주는지에 대해 작성합니다.&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;이 곳에서 LoadingPhase에 대한 설명을 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://openmynotepad.tistory.com/114&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://openmynotepad.tistory.com/114&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1702504622369&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;Unreal Engine Game Framework : main 함수부터 BeginPlay까지&quot; data-og-description=&quot;UnrealEngine의 초보자들이 GameFramework(GameMode, GameState, PlayerController, Pawn, PlayerState와 같은 클래스)를 제대로 이해하고 다루고 싶어 할 것이다. 익숙해지기 가장 좋은 방법 중 하나는 언리얼 엔진의 소&quot; data-og-host=&quot;openmynotepad.tistory.com&quot; data-og-source-url=&quot;https://openmynotepad.tistory.com/114&quot; data-og-url=&quot;https://openmynotepad.tistory.com/114&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/TD8JU/hyUL4lKEIk/kVlNkKXGbHUA5xW04bMMKK/img.png?width=545&amp;amp;height=260&amp;amp;face=0_0_545_260,https://scrap.kakaocdn.net/dn/MlL4U/hyULRzWT7O/4yhnDqKDN1Y53TFTjrLFu1/img.png?width=545&amp;amp;height=260&amp;amp;face=0_0_545_260,https://scrap.kakaocdn.net/dn/bLoI2E/hyULSTasa0/k0WubPiFoz4QiMQUUuuk0k/img.png?width=1024&amp;amp;height=799&amp;amp;face=0_0_1024_799&quot;&gt;&lt;a href=&quot;https://openmynotepad.tistory.com/114&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://openmynotepad.tistory.com/114&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/TD8JU/hyUL4lKEIk/kVlNkKXGbHUA5xW04bMMKK/img.png?width=545&amp;amp;height=260&amp;amp;face=0_0_545_260,https://scrap.kakaocdn.net/dn/MlL4U/hyULRzWT7O/4yhnDqKDN1Y53TFTjrLFu1/img.png?width=545&amp;amp;height=260&amp;amp;face=0_0_545_260,https://scrap.kakaocdn.net/dn/bLoI2E/hyULSTasa0/k0WubPiFoz4QiMQUUuuk0k/img.png?width=1024&amp;amp;height=799&amp;amp;face=0_0_1024_799');&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;Unreal Engine Game Framework : main 함수부터 BeginPlay까지&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;UnrealEngine의 초보자들이 GameFramework(GameMode, GameState, PlayerController, Pawn, PlayerState와 같은 클래스)를 제대로 이해하고 다루고 싶어 할 것이다. 익숙해지기 가장 좋은 방법 중 하나는 언리얼 엔진의 소&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;openmynotepad.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;Type을 'Editor' 로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LoadingPhase를 'PreDefault'로 작성합니다.&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;244&quot; data-origin-height=&quot;119&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/db5ep8/btsBY0PCkWw/T9GOPa8pk8TwKcbhLwABJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/db5ep8/btsBY0PCkWw/T9GOPa8pk8TwKcbhLwABJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/db5ep8/btsBY0PCkWw/T9GOPa8pk8TwKcbhLwABJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdb5ep8%2FbtsBY0PCkWw%2FT9GOPa8pk8TwKcbhLwABJ1%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;244&quot; height=&quot;119&quot; data-origin-width=&quot;244&quot; data-origin-height=&quot;119&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;이제 첫 Blank 플러그인 만들기가 완료 되었습니다.&lt;/p&gt;</description>
      <category>UnrealEngine/Editor</category>
      <category>UnrealEditor</category>
      <author>엄준식사생팬</author>
      <guid isPermaLink="true">https://openmynotepad.tistory.com/127</guid>
      <comments>https://openmynotepad.tistory.com/127#entry127comment</comments>
      <pubDate>Thu, 14 Dec 2023 06:59:49 +0900</pubDate>
    </item>
    <item>
      <title>NewObject와 SpawnActor</title>
      <link>https://openmynotepad.tistory.com/126</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;NewObject는 엔진이 초기화 된 이후, 런타임에서 오브젝트 생성을 위해 일반적으로 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 SpawnActor도 이와 동일한데, 무엇이 다를까?&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;결론적으로 말하자면, SpawnActor에서 Actor를 생성할 때도 NewObject를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AActor도 결국엔 UObject에서 파생된것이기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1359&quot; data-origin-height=&quot;55&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cF9BZo/btsv7VhcQQm/3zsjKAkKCM4jkVkKHeuryK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cF9BZo/btsv7VhcQQm/3zsjKAkKCM4jkVkKHeuryK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cF9BZo/btsv7VhcQQm/3zsjKAkKCM4jkVkKHeuryK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcF9BZo%2Fbtsv7VhcQQm%2F3zsjKAkKCM4jkVkKHeuryK%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;860&quot; height=&quot;35&quot; data-origin-width=&quot;1359&quot; data-origin-height=&quot;55&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 몇 가지 추가 작업을 더 거치게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 NewObject의 Outer는 당연히 ULevel이 된다.&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에 Actor 목록 배열과 GC를 위한 목록 배열을 가지고 있는데 이곳에 넣어둔다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;314&quot; data-origin-height=&quot;44&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tS9xN/btswbFLel0Z/5D9eKiZDcKjedWp5tgXeD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tS9xN/btswbFLel0Z/5D9eKiZDcKjedWp5tgXeD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tS9xN/btswbFLel0Z/5D9eKiZDcKjedWp5tgXeD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtS9xN%2FbtswbFLel0Z%2F5D9eKiZDcKjedWp5tgXeD0%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;314&quot; height=&quot;44&quot; data-origin-width=&quot;314&quot; data-origin-height=&quot;44&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;또한 해당 Actor가 가지고있는 WorldTransform을 설정한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1157&quot; data-origin-height=&quot;367&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTwQwx/btswPVZ3ZkO/QgNQTOCOphlGFg1cy1cgm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTwQwx/btswPVZ3ZkO/QgNQTOCOphlGFg1cy1cgm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTwQwx/btswPVZ3ZkO/QgNQTOCOphlGFg1cy1cgm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTwQwx%2FbtswPVZ3ZkO%2FQgNQTOCOphlGFg1cy1cgm0%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;1157&quot; height=&quot;367&quot; data-origin-width=&quot;1157&quot; data-origin-height=&quot;367&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;661&quot; data-origin-height=&quot;409&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lDL99/btsv7VO4wpc/CkvzIdHWg4R3CGwkqgj2RK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lDL99/btsv7VO4wpc/CkvzIdHWg4R3CGwkqgj2RK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lDL99/btsv7VO4wpc/CkvzIdHWg4R3CGwkqgj2RK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlDL99%2Fbtsv7VO4wpc%2FCkvzIdHWg4R3CGwkqgj2RK%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;661&quot; height=&quot;409&quot; data-origin-width=&quot;661&quot; data-origin-height=&quot;409&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;즉, 해당 작업을 개인적으로 할 수 있다면 AActor를 NewObject로 만들어도 상관은 없다.&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;근데 코드를 봐서 알겠지만, 그게 더 큰 처리가 될테니 그냥 SpawnActor 쓰자&lt;/p&gt;</description>
      <category>UnrealEngine/Impl</category>
      <category>UnrealEngine</category>
      <author>엄준식사생팬</author>
      <guid isPermaLink="true">https://openmynotepad.tistory.com/126</guid>
      <comments>https://openmynotepad.tistory.com/126#entry126comment</comments>
      <pubDate>Tue, 3 Oct 2023 19:34:02 +0900</pubDate>
    </item>
  </channel>
</rss>