<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>23m-rft68.log</title>
        <link>https://velog.io/</link>
        <description>.</description>
        <lastBuildDate>Mon, 16 Mar 2026 01:59:36 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>23m-rft68.log</title>
            <url>https://velog.velcdn.com/images/23m-rft68/profile/566f59b2-1e89-44ec-a28f-37ffecbf95d7/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. 23m-rft68.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/23m-rft68" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[TIL-260316] AR]]></title>
            <link>https://velog.io/@23m-rft68/TIL-260316-AR</link>
            <guid>https://velog.io/@23m-rft68/TIL-260316-AR</guid>
            <pubDate>Mon, 16 Mar 2026 01:59:36 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-배운-내용">오늘 배운 내용</h1>
<h2 id="ar">AR</h2>
<hr>
<blockquote>
<h3 id="araugmented-reality">AR(Augmented Reality)</h3>
</blockquote>
<ul>
<li>현실 세계 위에 디지털 컨텐츠를 겹쳐 보여주는 기술</li>
<li>카메라로 촬영한 사진 위에 가상의 오브젝트를 합성하는 기술</li>
</ul>
<table>
<thead>
<tr>
<th align="center">구분</th>
<th align="center">AR</th>
<th align="center">VR</th>
</tr>
</thead>
<tbody><tr>
<td align="center">현실</td>
<td align="center">보임</td>
<td align="center">안보임</td>
</tr>
<tr>
<td align="center">컨텐츠</td>
<td align="center">현실위에 합성</td>
<td align="center">가상 세계</td>
</tr>
<tr>
<td align="center">대표기기</td>
<td align="center">스마트폰, AR글래스</td>
<td align="center">VR 헤드셋</td>
</tr>
</tbody></table>
<hr>
<h3 id="ar-core-ar-kit">AR Core/ AR Kit</h3>
<ul>
<li>유니티에서 AR 기능을 활용할 수 있도록 지원하는 패키지</li>
</ul>
<h4 id="ar-core">AR Core</h4>
<ul>
<li>안드로이드 / ios 호환</li>
<li>AR Kit 비해서는 &#39;상대적으로&#39; 성능이 떨어짐.</li>
</ul>
<h4 id="ar-kit">AR Kit</h4>
<ul>
<li>ios 전용</li>
<li>바디트래킹</li>
</ul>
<hr>
<h3 id="ar-foundation">AR Foundation</h3>
<ul>
<li>Unity와 AR 패키지 간의 다리 역할(어댑터 역할)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL-260225] Astar]]></title>
            <link>https://velog.io/@23m-rft68/TIL-260225-Astar</link>
            <guid>https://velog.io/@23m-rft68/TIL-260225-Astar</guid>
            <pubDate>Wed, 25 Feb 2026 06:50:40 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-배운-내용">오늘 배운 내용</h1>
<h2 id="--astar-알고리즘">- AStar 알고리즘</h2>
<hr>
<h3 id="q-ai-어디-위에서-길을-찾을까">Q. AI 어디 위에서 길을 찾을까?</h3>
<ul>
<li><code>그래프</code> 위에서 움직인다</li>
</ul>
<h3 id="node-설계">Node 설계</h3>
<h4 id="q-노드node하나가-가지고-있을-정보는">Q. 노드(Node)하나가 가지고 있을 정보는?</h4>
<ul>
<li><code>walkable</code>: 지나갈 수 있는지 없는지 판별 - <strong>bool</strong></li>
<li><code>position</code>: 좌표 - <strong>Vector2Int</strong></li>
<li><code>gCost</code>: 시작점부터 현재 위치까지  - <strong>int</strong></li>
<li><code>hCost (A*)</code>: 현재 위치에서 목표까지  - <strong>int</strong></li>
<li><code>FCost</code>: gCost + hCost  - <strong>int</strong></li>
<li><code>parent</code> - <strong>Node</strong>
<img src="https://velog.velcdn.com/images/23m-rft68/post/8bfae2e3-4249-46f8-9b5f-7b4436f474b2/image.png" alt=""></li>
</ul>
<ul>
<li><strong>Node를 알면, Grid는 Node들의 집합체임을 알 수 있음</strong></li>
</ul>
<hr>
<h4 id="q-node-하나로-길찾기-가능한가">Q. Node 하나로 길찾기 가능한가?</h4>
<ul>
<li>불가능. 노드들 간 연결이(정보가) 필요함 (이웃 노드)</li>
</ul>
<h4 id="q-현재-노드-어디-방향으로-갈-수-있는가">Q. 현재 노드 어디 방향으로 갈 수 있는가?</h4>
<ul>
<li>상/하/좌/우</li>
<li>상/하/좌/우/우상/좌상/우하/좌하</li>
</ul>
<hr>
<blockquote>
<h3 id="다익스트라dijkstra">다익스트라(Dijkstra)</h3>
</blockquote>
<ol>
<li>시작점</li>
<li>주변 확장</li>
<li>거리 기록</li>
</ol>
<h3 id="q-node가-퍼져-나가려면-코드에-있어야-될-데이터는">Q. Node가 퍼져 나가려면 코드에 있어야 될 데이터는?</h3>
<ul>
<li>OpenList - List</li>
<li>Closed - HashSet</li>
</ul>
<p><strong>List</strong>의 성격</p>
<ul>
<li>순회 가능</li>
<li>인덱스 접근이 용이</li>
</ul>
<p><strong>Closed</strong> 왜 <strong>HashSet</strong>일까?</p>
<ul>
<li>빠른 검사를 위함 -&gt; O(1)</li>
<li>중복 처리 방지</li>
</ul>
<h3 id="q-step-함수에서-무슨-일이-일어나야-될까">Q. Step 함수에서 무슨 일이 일어나야 될까?</h3>
<p>Step()</p>
<ol>
<li><strong>OpenList</strong> 에서 어떤 걸 꺼내야할까?</li>
<li><strong>꺼낸 노드</strong> 어디로 가는가?</li>
<li><strong>이웃 노드</strong> 어떻게 처리하는가?</li>
<li>이동 비용은 어떻게 계산하는가?</li>
</ol>
<hr>
<h3 id="다익스트라-정리">다익스트라 정리</h3>
<ul>
<li><code>gCost</code>만 사용</li>
<li>전부 탐색</li>
</ul>
<p>[문제점]</p>
<ul>
<li>목표를 찾는 방식 -&gt; 비효율적 -&gt; 그래서 나온 게 <code>휴리스틱(hCost)</code>을 포함한 <code>A* 알고리즘</code></li>
</ul>
<p>[다익스트라 vs A* 차이]</p>
<ul>
<li><p>다익스트라</p>
<ul>
<li>시작점(S) 기준으로 퍼져 나감 -&gt; 전부 탐색</li>
</ul>
</li>
<li><p>A*</p>
<ul>
<li>목표(T) 방향으로 퍼짐 -&gt; 필요 영역 우선적 탐색</li>
</ul>
</li>
</ul>
<hr>
<blockquote>
<h3 id="a">A*</h3>
</blockquote>
<p><img src="https://velog.velcdn.com/images/23m-rft68/post/0bc4a057-6369-4c3b-a5f0-ef45f6d98b5f/image.png" alt=""></p>
<ul>
<li><strong>gCost</strong>: 시작점 노드와 현재 노드 사이의 거리</li>
<li><strong>hCost</strong>: 현재 노드와 타겟 노드 사이의 거리</li>
<li><strong>FCost</strong>: 타겟 노드까지 얼마나 걸리는지에 대한 예상값</li>
</ul>
<h3 id="hcost">hCost</h3>
<p>[예시]</p>
<pre><code class="language-c#">S ... T</code></pre>
<p>S = (0, 0)
T = (4, 0)</p>
<p>현재 노드 좌표 (1, 0) -&gt; 타겟까지 우측 3칸
-&gt; <code>hCost</code>: 목표까지 몇 칸 남았는지를 계산한 숫자</p>
<h3 id="q-왜-맨해튼-거리인가">Q. 왜 맨해튼 거리인가?</h3>
<p>현재 위치 (1, 2)
타겟 위치 (4, 5)</p>
<pre><code class="language-C">|4 - 1| + |5 - 2| = 3 + 3 = 6</code></pre>
<p>-&gt; <code>hCost</code> = 6</p>
<p>A Node - 남은거리 (3)
B Node - 남은거리 (7)</p>
<p>A Node와 B Node는 <code>gCost</code>가 같다.</p>
<hr>
<h3 id="parent---경로-역추적">Parent - 경로 역추적</h3>
<ul>
<li>&quot;Parent 노드에 오기 직전 노드&quot;</li>
</ul>
<pre><code class="language-csharp">S -&gt; a -&gt; b -&gt; c -&gt; T</code></pre>
<pre><code class="language-Csharp">T.parent = c
c.parent = b
b.parent = a
a.parent = S</code></pre>
<p>-&gt; 거꾸로 올라감
<code>isPath = true</code> 순회했다고 표시를 남김</p>
<hr>
<pre><code class="language-csharp">int newCost = currentNode.gCost + 1;

// 더 좋은 길을 찾았거나 || 이웃 노드를 처음 발견했거나

if (newCost &lt; neighbour.gCost || !_openList.Contains(neighbour))
{
    // 비용 갱신
    neighbour.gCost = newCost;
    neighbour.hCost = GetHeuristic(currentNode, _targetNode);
    // 부모(이전) 노드를 기록
    neighbour.parent = currentNode;

    if(!_openList.Contains(neighbour))
    // 리스트에 탐색 후보를 넣는다
        _openList.Add(neighbour);
}</code></pre>
<p>-&gt; <strong>다익스트라 + 휴리스틱 = <code>A*</code></strong></p>
<hr>
<blockquote>
<h3 id="정리">정리</h3>
</blockquote>
<pre><code class="language-Csharp">// #01
Node - 가지고 있는 정보가 무엇이고, 의미하는바가 무엇인가?
    1) walkable
    2) position
    3) gCost
        // A* 용
        3-1) hCost
        3-2) FCost
    4) parent
    5) isPath

// #02
Node 데이터를 처리할 자료구조는 무엇이고, 왜 필요한가?
- OpenList
- ClosedSet

// #03
- 다익스트라 
    - gCost로만 판단
    - StartNode

- A* 
    - FCost로 판단 || FCost 같다면 hCost로 판단
    - StartNode, TargetNode</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL-260224] Behaviour Tree]]></title>
            <link>https://velog.io/@23m-rft68/TIL-260224-Behaviour-Tree</link>
            <guid>https://velog.io/@23m-rft68/TIL-260224-Behaviour-Tree</guid>
            <pubDate>Tue, 24 Feb 2026 09:07:56 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-배운-내용">오늘 배운 내용</h1>
<h2 id="--behaviour-tree">- Behaviour Tree</h2>
<hr>
<h3 id="흐름도">흐름도</h3>
<p><strong>FSM 복습 (한계점) -&gt; State 복습 (한계점) -&gt; 코드 기반 BT (한계점) -&gt; BT Graph - Unity 6</strong></p>
<ul>
<li>Player</li>
<li>Enemy -&gt; 일정거리 안에 있으면 Player 추적 / 공격 범위 안에 있으면 공격</li>
</ul>
<h2 id="enemy-ai가-어떻게-player를-추적하고-동작하게-할끼"><strong>Enemy AI가 어떻게 Player를 추적하고 동작하게 할끼?</strong></h2>
<blockquote>
<h3 id="fsm">FSM</h3>
</blockquote>
<p>[기본구조]</p>
<pre><code class="language-csharp">switch(currentState)
{
    case State.Idle:
        // 동작
        break;
    case State.Move:
        // 동작
        break;
    ...
}</code></pre>
<p>[ex]</p>
<ul>
<li><code>상태(State)</code>가 3개일때는?
근데 만약에 <code>상태(State)</code>가 10개 이상이라면?</li>
</ul>
<p>-&gt; <code>상태(State)</code>수가 늘수록 코드 복잡도 폭증</p>
<hr>
<blockquote>
<h3 id="state-pattern-복습">State Pattern 복습</h3>
</blockquote>
<p>[구조]</p>
<ul>
<li>Istate.cs (interface)<ul>
<li>IdleState</li>
<li>MoveState</li>
<li>JumpState
...</li>
</ul>
</li>
<li>StateMachine.cs</li>
</ul>
<h4 id="상태state-구성">상태(State) 구성</h4>
<ul>
<li>Idle</li>
<li>Move</li>
<li>Jump</li>
</ul>
<p>+<code>상태(State)</code></p>
<ul>
<li>Attack</li>
<li>Dash</li>
<li>Air 관련 (Jump 비슷한 State)</li>
<li>Crouch</li>
</ul>
<p><strong>&quot;전이(Transition) 연결&quot;</strong></p>
<p><code>상태(State)</code>가 많아질수록</p>
<ul>
<li>비슷한 <strong>상태(State)</strong> 간, <strong>조건 중복</strong>이 많이됨</li>
<li><code>상태(State)</code> 들간 결합도가 커질 수 있음</li>
</ul>
<hr>
<blockquote>
<h3 id="behaviour-tree-bt">Behaviour Tree (BT)</h3>
</blockquote>
<ul>
<li>루트 노드 -&gt; 자식 노드를 순서대로 조건부 판단</li>
</ul>
<h3 id="q-state-pattern과-차이">Q. State Pattern과 차이?</h3>
<ul>
<li><code>상태(State)</code>는 선택된 현재 상태(State)만 실행 -&gt; 그 상태(State)가 가진 조건부 판별만함</li>
<li><code>BT</code>는 조건을 매 프레임 단위로 루트 노드에서부터 판단</li>
</ul>
<h4 id="bt의-구조">BT의 구조</h4>
<ul>
<li><strong>Node</strong>들로 이뤄져 있다<pre><code class="language-csharp">public enum NodeState { Success, Failure, Running }
</code></pre>
</li>
</ul>
<p>public abstract class Node
{                          // Update();
    public abstract NodeState Evalute();
}</p>
<pre><code>- Evaluate() 실행 결과를 반환

### 다룰 Node
- Selector (OR)
- Sequence (AND)
- Leaf (Condition/ Acition)

---
### Node 종류

1. Composite Node

- 자식 노드들의 실행 흐름을 제어한다
    - `시퀀스(Sequence)` - **AND구조**
        - 순서대로 실행
        - 하나라도 실패하면 즉시 **Failure** 반환
        - 모두 성공하면 **Success** 반환

    - `셀렉터(Selector)` - **OR구조**
        - 자식 중 하나라도 성공하면 **Success** 반환
        - 모두 실패하면 **Failure** 반환

2. Leaf Mode

- **트리의 가장 하위 노드**로 자식을 가지지 않는다
- **조건을 판단(`Condition`)** 하거나 **실제 행동(`Action`)을 수행**

---
### (유니티 실습)BT 구조
- Enemy가 Player 추적 및 공격 구현중
```csharp
           [Root]
              |
          [Selector] - OR구조
           /       \
      [Attack]    [Chase] - Sequence (And 구조)
                     |           
                [IsNearTarget] - Condition(Leaf)
                    |               
                [MoveToTarget]  - Action(Leaf) </code></pre><h3 id="selector-or-구조">Selector (OR 구조)</h3>
<ul>
<li><code>AttackAction</code>: 공격이 가능한가? -&gt; 가능하다면 공격 (Success / Failure)<ul>
<li><strong>Failure</strong>: Chase(추적) 함? (Success / Failure)<ul>
<li><strong>Success</strong>: Target 추적중</li>
<li><strong>Failure</strong>: IdleState </li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h3 id="추가-bt-구조-짤-때">(+추가) BT 구조 짤 때</h3>
<ol>
<li>동작할 흐름 모식도로 그려보기</li>
<li>노드를 이해하기(Composite, Leaf Node)</li>
<li>코드 짜기</li>
</ol>
<h3 id="한계점">한계점</h3>
<ul>
<li>코드 복잡해짐</li>
<li>구조 파악 어려움</li>
<li>디자이너(기획자) 수정 불편 (못함...)</li>
</ul>
<hr>
<h3 id="정리">정리</h3>
<table>
<thead>
<tr>
<th align="center"></th>
<th align="center">정의</th>
<th align="center">한계점</th>
</tr>
</thead>
<tbody><tr>
<td align="center">FSM</td>
<td align="center">상태를 분기</td>
<td align="center">코드가 복잡해짐</td>
</tr>
<tr>
<td align="center">State Pattern</td>
<td align="center">상태 책임 분리</td>
<td align="center">전이 폭증 현상</td>
</tr>
<tr>
<td align="center">Behaviour Tree</td>
<td align="center">상태 조건 판별 트리 구조</td>
<td align="center">구조 파악 어려움, 협업 활용 못함</td>
</tr>
<tr>
<td align="center">BT Graph</td>
<td align="center">코드 기반 BT 시각화</td>
<td align="center">영어를 잘해야함</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL-260223] State Pattern]]></title>
            <link>https://velog.io/@23m-rft68/TIL-260223-State-Pattern</link>
            <guid>https://velog.io/@23m-rft68/TIL-260223-State-Pattern</guid>
            <pubDate>Mon, 23 Feb 2026 07:44:18 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-배운-내용">오늘 배운 내용</h1>
<h2 id="--state-pattern과-플랫포머-구현">- State Pattern과 플랫포머 구현</h2>
<hr>
<blockquote>
<h3 id="state-pattern">State Pattern</h3>
</blockquote>
<h3 id="--문제-코드">- 문제 코드</h3>
<pre><code class="language-csharp">public enum StateList
{
   Idle, Move, Jump, Attack
}

public class PlayerState : MonoBehaviour
{
   private int _direction;
   [SerializeField] private StateList CurrentState; 

   private void Update() 
   {
     // 키 입력 에 따른 각 상태 변화

   }

   private void Idle()
   {
     // 기능 로직
     // 애니메이션 변화 로직
     // 예외처리 등
   }

   private void Move()
   {
     // 기능 로직
     // 애니메이션 변화 로직
     // 예외처리 등
   }

   private void Jump()
   {
     // 기능 로직
     // 애니메이션 변화 로직
     // 예외처리 등
   }

   private void Attack()
   {
     // 기능 로직
     // 애니메이션 변화 로직
     // 예외처리 등
   }
}</code></pre>
<ul>
<li><code>상태(State)</code>가 늘어나면, 조건 분기수(if) 기하급수적으로 늘어남.</li>
</ul>
<hr>
<h2 id="꼭-기억해야할-점">꼭 기억해야할 점</h2>
<p>-&gt; 게임 기능이 늘어나면 조건문을 늘리는 게 아니라 <strong>상태(State)</strong>를 늘린다</p>
<h3 id="q-상태state란">Q. 상태(State)란?</h3>
<p>-&gt; 어떤 객체가 <strong>특정 상황에서 어떻게 행동해야 하는지를 결정하는 행동 규칙</strong></p>
<hr>
<h3 id="코드-문제점">코드 문제점</h3>
<pre><code class="language-csharp">void Update()
{
    HandleInput();
    ApplyGravity();
    CheckGround();

    if (_state == PlayerState.Idle)
    {
        ...
    }
    else if (_state == PlayerState.Move)
    {
        ...
    }
    else if (_state == PlayerState.Jump)
    {
        ...
        if (CanDoubleJump()) ...
        if (InputDash()) ...
        if (InputAttack()) ...
        if (IsHit()) ...
    }
    else if (_state == PlayerState.AirAttack)
    {
        ...
        if (ComboWindowOpen()) ...
        if (IsHit()) ...
        if (IsGrounded()) ...
    }
    else if (_state == PlayerState.Hit)
    {
        ...
        if (RecoverTimeOver()) ...
    }
    else if (_state == PlayerState.Die)
    {
        ...
    }
    // 계속 증가
}</code></pre>
<ul>
<li><code>상태(State)</code>가 서로를 안다. (엮여있다)</li>
<li><strong>책임</strong>이 <code>Player</code>한테 몰리는 현상이 일어난다.</li>
<li>수정 시 리스크 폭발</li>
</ul>
<hr>
<blockquote>
<h3 id="state-pattern-구조">State Pattern 구조</h3>
</blockquote>
<table>
<thead>
<tr>
<th align="center">요소</th>
<th align="center">책임</th>
<th align="center">하면 안되는 것</th>
</tr>
</thead>
<tbody><tr>
<td align="center">Player</td>
<td align="center">상태 실행</td>
<td align="center">상태 로직 직접 구현</td>
</tr>
<tr>
<td align="center">StateMachine</td>
<td align="center">상태 교체</td>
<td align="center">입력처리</td>
</tr>
<tr>
<td align="center">ConcreteState</td>
<td align="center">자기 상태 행동 전달</td>
<td align="center">다른 상태 내부 접근</td>
</tr>
<tr>
<td align="center"><img src="https://velog.velcdn.com/images/23m-rft68/post/5a4398dc-1627-462b-ba66-25bf117b972d/image.png" alt=""></td>
<td align="center"></td>
<td align="center"></td>
</tr>
</tbody></table>
<p>[동작 흐름]</p>
<pre><code class="language-note">User Input -&gt; Player -&gt; StateMachine -&gt; State.Update()
입력 -&gt; 코드 FSM -&gt; 물리 -&gt; Animator</code></pre>
<ul>
<li><strong>게임</strong>은 <code>코드 FSM</code> 위에서 동작 <code>Animator</code>는 그 위에 얹힌 표현 계층</li>
</ul>
<p>[전환 흐름]</p>
<pre><code>CurrentState?.Exit()
↓
NewState.Enter()</code></pre><hr>
<h3 id="unity에서-상태패턴을-가지는-임의의-객체player">Unity에서 상태패턴을 가지는 임의의 객체(Player)</h3>
<h3 id="playercontrollercs-예시">PlayerController.cs 예시</h3>
<pre><code class="language-csharp">using UnityEngine;

// 입력 처리 / 물리 판정 / 애니메이션 결정
public class PlayerController : MonoBehaviour
{
    Rigidbody2D _rb;
    Animator _animator;

    StateMachine _stateMachine;

    // Player가 사용할 State들
    IdleState Idle;
    MoveState Move;
    JumpState Jump;

    void Start()
    {
        _stateMachine = new StateMachine();
        Idle = new IdleState(this);
        Move = new MoveState(this);
        Jump = new JumpState(this);

        _stateMachine.ChangeState(Idle);
    }

    void Update()
    {
        _stateMachine.Update();
    }

    public void ChangeState(IState state)
    {
        _stateMachine.ChangeState(state);
    }
}</code></pre>
<hr>
<blockquote>
<h3 id="정리">정리</h3>
</blockquote>
<p>[Player가 모든 상태를 관리하는 코드 문제점]</p>
<ul>
<li>상태 수 X 전환 조건 수 = Update 복잡도 폭증</li>
<li><blockquote>
<p><code>상태(State)</code>가 늘어날수록 Player가 모든 상태 관련 것들을 알아야함</p>
</blockquote>
</li>
</ul>
<p>[상태(State) 역할]</p>
<ul>
<li><code>상태(게임 로직 + 애니메이션)</code> 모두 Player 안에서 처리</li>
</ul>
<p>[상태(State) 분리로 일어난 이점]</p>
<ul>
<li>Update 함수 코드 구현이 없어진 것이 아니라, 책임이 상태(State) 객체로 이동한 것</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL-260220] 2D]]></title>
            <link>https://velog.io/@23m-rft68/TIL-260220</link>
            <guid>https://velog.io/@23m-rft68/TIL-260220</guid>
            <pubDate>Fri, 20 Feb 2026 07:34:33 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-배운-내용">오늘 배운 내용</h1>
<h2 id="--2d">- 2D</h2>
<hr>
<blockquote>
<h3 id="3d-환경과-차이점">3D 환경과 차이점?</h3>
</blockquote>
<p>Depth Test -&gt; 기본적으로 해당 단계를 비활성화/생략</p>
<p>-&gt; 2D 랜더링은 <code>Sorting Layer / Order in Layer</code> </p>
<hr>
<blockquote>
<h3 id="유니티-2d-컴포넌트">유니티 2D 컴포넌트</h3>
</blockquote>
<ul>
<li><p>Collider 2D</p>
<ul>
<li>Circle</li>
<li>Box</li>
<li>Capsule</li>
<li>Edge</li>
<li>Polygon</li>
<li>Composite(⭐)</li>
</ul>
</li>
<li><p>Rigidbody 2D</p>
</li>
<li><p>Sprite Renderer</p>
</li>
</ul>
<p>[+추가]</p>
<ul>
<li>Physics Material 2D</li>
<li>Sorting Layer 설정하는 법</li>
<li>2D Physics 설정 (Project Settings)</li>
</ul>
<h3 id="유니티-2d를-제작-전-사고-방식">유니티 2D를 제작 전 사고 방식</h3>
<ul>
<li>Sprite 그림(연출)</li>
<li>Collider 감지</li>
<li><blockquote>
<p>결국 게임 규칙을 따름</p>
</blockquote>
</li>
</ul>
<hr>
<h3 id="edge-collider-2d">Edge Collider 2D</h3>
<ul>
<li>선 하나 시작 -&gt; 원하는 콜라이더를 직접 지정 가능</li>
</ul>
<h3 id="polygon-collider-2d">Polygon Collider 2D</h3>
<ul>
<li><strong>복잡한 모양</strong> 자동 생성</li>
<li>성능이 상대적으로 무거움</li>
</ul>
<h3 id="composite-collider-2d">Composite Collider 2D</h3>
<ul>
<li>하위 객체 콜라이더를 하나로 관리해주는 친구</li>
</ul>
<hr>
<blockquote>
<h3 id="tilemap">Tilemap</h3>
</blockquote>
<h3 id="step-1-tilemap---rectangluar-생성">Step 1. Tilemap - Rectangluar 생성</h3>
<ul>
<li>2D Object -&gt; Tilemap -&gt; Rectangular</li>
</ul>
<hr>
<h3 id="step-2-create-new-palette">Step 2. Create New Palette</h3>
<ul>
<li>&#39;Resources/Palette/Test palette&#39; 생성</li>
</ul>
<hr>
<h3 id="step-3-tiles-드래그-드롭">Step 3. Tiles 드래그 드롭</h3>
<ul>
<li>&#39;Resources/Tile/Tiles 등록&#39;</li>
</ul>
<hr>
<h3 id="step-4-종류">Step 4. 종류</h3>
<h4 id="4-1-brushb">4-1. Brush(B)</h4>
<ul>
<li>&quot;개별 Tile에 칠하기 가능&quot;</li>
</ul>
<h4 id="4-2-flood-fill-with-active-brushg">4-2. Flood fill with active brush(G)</h4>
<ul>
<li>&quot;Tile 한 번에 채우기 가능&quot;</li>
</ul>
<h4 id="4-3-transform-조정">4-3. Transform 조정</h4>
<ul>
<li>&quot;다음 Tile 회전해서 칠하기 가능&quot;</li>
</ul>
<h4 id="4-4-tile-transform-변경-가능">4-4. Tile Transform 변경 가능</h4>
<h4 id="4-5-gameobject-brush-옵션">4-5. GameObject Brush 옵션</h4>
<ul>
<li>&quot;애니메이션 들어간 캐릭터를 넣어서 Brush로 쭉 그려보기&quot;</li>
</ul>
<h4 id="4-6-group-brush-옵션">4-6. Group Brush 옵션</h4>
<ul>
<li>&quot;스포이드로 짜서 원하는 Tile 만들고 Grid에 찍어보기&quot;</li>
</ul>
<h4 id="4-7-random-brush">4-7. Random Brush</h4>
<ul>
<li>&quot;랜덤으로 칠해질 Tile을 등록하고 Grid에 찍어보기&quot;</li>
</ul>
<h4 id="4-8-rule-tile-⭐">4-8. Rule Tile (⭐)</h4>
<ul>
<li>&quot;매번 매끄러운 타일을 만들기 위해서 일일이 Brush 하기 번거롭고, 자동으로 타일을 매끄럽게 매핑해주면 좋을것같음&quot;</li>
</ul>
<hr>
<blockquote>
<h3 id="sprite-animation">Sprite Animation</h3>
</blockquote>
<ul>
<li>이미지를 시간 순서로 변화시키는/바꾸는 것</li>
</ul>
<h3 id="sprite-sheet">Sprite Sheet</h3>
<ul>
<li>여러 개의 Sprite 이미지를 &quot;한 장의 이미지&quot;에 모아둔 것</li>
</ul>
<h4 id="q-사용하는-이유">Q. 사용하는 이유?</h4>
<ul>
<li>관리가 편하다</li>
<li>메모리 효율이 좋다 (GPU 바인딩 감소)</li>
</ul>
<h4 id="unity에서-사용법">Unity에서 사용법</h4>
<ol>
<li><code>Texture Type</code> -&gt; Sprite (2D and UI)</li>
<li><code>Sprite Mode</code> -&gt; Multiple</li>
<li><code>Sprite Editor</code> -&gt; Slice (Grid by Cell Size)</li>
<li>Apply</li>
</ol>
<ul>
<li>위 과정을 거치면
Sprite Sheet가 &quot;개별 Sprite들&quot;로 분리된다.</li>
</ul>
<hr>
<blockquote>
<h3 id="sprite-mode--multiple">Sprite Mode = Multiple</h3>
</blockquote>
<ul>
<li><p>이미지 하나 = 여러 Sprite</p>
<h4 id="pixels-per-unit-ppu">Pixels Per Unit (PPU)</h4>
<p><img src="https://velog.velcdn.com/images/23m-rft68/post/72952f88-6662-46e1-89f6-066cd13d8058/image.png" alt=""></p>
</li>
<li><p>&quot;PPU는 픽셀을 월드 단위로 환전하는 기준&quot; &quot;1유닛 = 몇 픽셀인가?&quot;</p>
</li>
</ul>
<pre><code class="language-csharp">64px = 1 Unity Unit</code></pre>
<ul>
<li>PPU 64</li>
<li>이미지 64px
  -&gt; 월드에서 1유닛</li>
</ul>
<p>[예시]</p>
<ul>
<li>이미지 크기: 96px</li>
<li>PPU: 64</li>
</ul>
<p>계산:</p>
<pre><code class="language-csharp">96 / 64 = 1.5 Unit</code></pre>
<p>즉, 씬에서 높이 1.5 유닛으로 보임</p>
<h4 id="q-중요한-이유">Q. 중요한 이유</h4>
<ul>
<li>&quot;카메라 기준이 Unity Unit이기 때문에&quot;</li>
</ul>
<p>ex)</p>
<pre><code class="language-csharp">orthographicSize = 5;</code></pre>
<p>-&gt; 카메라 중점 기준, 위로 5 유닛</p>
<hr>
<h3 id="mesh-type-설명-중요⭐">Mesh Type 설명 (중요⭐)</h3>
<ol>
<li>Full Rect</li>
</ol>
<ul>
<li>&quot;사각형 메쉬 전체 사용&quot;</li>
</ul>
<p>[장점]</p>
<ul>
<li>안정적</li>
<li>타일맵, 캐릭터에 안전</li>
</ul>
<p>[단점]</p>
<ul>
<li>투명 영역도 포함</li>
</ul>
<ol start="2">
<li>Tight</li>
</ol>
<ul>
<li>&quot;투명 영역 제외하고 메쉬 생성&quot;</li>
</ul>
<p>[장점]</p>
<ul>
<li>오버로드 감소</li>
</ul>
<p>[단점]</p>
<ul>
<li>경계가 불규칙</li>
<li>타일 경계 어긋날 수 있음</li>
<li>픽셀 아트 흔들림 발생 가능</li>
</ul>
<p>[실무 추천]</p>
<table>
<thead>
<tr>
<th align="center">용도</th>
<th align="center">추천</th>
</tr>
</thead>
<tbody><tr>
<td align="center">캐릭터</td>
<td align="center">Full Rect</td>
</tr>
<tr>
<td align="center">타일맵</td>
<td align="center">Full Rect</td>
</tr>
<tr>
<td align="center">파티클</td>
<td align="center">Tight 가능</td>
</tr>
</tbody></table>
<hr>
<h3 id="wrap-mode">Wrap Mode</h3>
<ol>
<li>Repeat</li>
</ol>
<ul>
<li>텍스처 반복</li>
<li>타일처럼 무한 반복 가능</li>
</ul>
<ol start="2">
<li>Clamp</li>
</ol>
<ul>
<li>끝 픽셀 유지</li>
<li>대부분 2D 게임 기본값</li>
</ul>
<p>Q. 언제 Repeat?</p>
<ul>
<li>배경 패턴</li>
<li>무한 스크롤</li>
</ul>
<hr>
<h3 id="filter-mode-매우-중요⭐">Filter Mode (매우 중요⭐)</h3>
<ol>
<li>Point (no filter)</li>
</ol>
<ul>
<li>픽셀 그대로 표현</li>
<li>픽셀 아트 필수</li>
</ul>
<ol start="2">
<li>Bilinear</li>
</ol>
<ul>
<li>부드럽게 보간</li>
</ul>
<ol start="3">
<li>Trilinear</li>
</ol>
<ul>
<li>3D에서 사용</li>
<li>2D에서는 거의 안 씀
&quot;픽셀 게임이면 무조건 Point&quot;</li>
</ul>
<hr>
<h3 id="추가-sprite-atlas란">(+추가) Sprite Atlas란?</h3>
<ul>
<li>여러 Sprite를 하나의 큰 텍스처로 묶어서 성능을 올리는 시스템
<img src="https://velog.velcdn.com/images/23m-rft68/post/ef632581-4b66-4b45-afdb-1ae62dcc01a3/image.png" alt=""></li>
</ul>
<h4 id="q-왜-쓰는가">Q. 왜 쓰는가?</h4>
<ul>
<li><code>GPU</code>는 <strong>같은 텍스처를 쓰는 오브젝트를 한 번에 그릴 수 있다.</strong> 텍스처가 다르면 -&gt; Draw Call 증가 -&gt; 성능 하락</li>
</ul>
<h4 id="q-언제-쓰는가">Q. 언제 쓰는가?</h4>
<ul>
<li>모바일</li>
<li>UI 많을 때</li>
<li>캐릭터 수 많을 때</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL-260219] CSV / JSON / Scriptable Object]]></title>
            <link>https://velog.io/@23m-rft68/TIL-260219-CSV-JSON-Scriptable-Object</link>
            <guid>https://velog.io/@23m-rft68/TIL-260219-CSV-JSON-Scriptable-Object</guid>
            <pubDate>Thu, 19 Feb 2026 07:44:17 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-배운-내용">오늘 배운 내용</h1>
<hr>
<h2 id="--csv">- CSV</h2>
<h2 id="--json">- JSON</h2>
<h2 id="--scriptable-object">- Scriptable Object</h2>
<hr>
<blockquote>
<h3 id="데이터-관리저장을-이해하기-위해서-알아야-할-선수지식">데이터 관리(저장)을 이해하기 위해서 알아야 할 선수지식</h3>
</blockquote>
<h4 id="직렬화">직렬화</h4>
<p><code>객체 -&gt; 파일</code>로 바꾸는 것</p>
<p>[목적]</p>
<ul>
<li>HDD/SDD 저장하기 위해서</li>
<li>네트워크로 전송하기 위해서</li>
<li>유니티 인스텍터 창에 데이터 노출하기 위해</li>
</ul>
<h4 id="역직렬화">역직렬화</h4>
<p><code>파일 -&gt; 객체</code>로 복원하는 것</p>
<hr>
<blockquote>
<h3 id="데이터-저장방식">데이터 저장방식</h3>
</blockquote>
<h4 id="1-playerprefs">1. PlayerPrefs</h4>
<ul>
<li>빠르게 사용 가능</li>
<li>저장 공간에 제약</li>
<li>보안 취약</li>
</ul>
<h4 id="2-csv">2. CSV</h4>
<ul>
<li>협업 효율 -&gt; 엑셀로 편하게 수치를 기입하고 수정</li>
<li>표로 구성되어 있어서, 복잡한 구조에는 치명적</li>
</ul>
<h4 id="3-json">3. JSON</h4>
<ul>
<li>리스트, 딕셔너리 같은 복잡한 자료구조를 파일 하나로 묶을 수 있음</li>
</ul>
<h4 id="4-scriptableobject">4. ScriptableObject</h4>
<ul>
<li>유니티 에디터로 지원되는 기능</li>
<li>정적 데이터 저장 시 유용</li>
</ul>
<hr>
<blockquote>
<h3 id="playerprefs">PlayerPrefs</h3>
</blockquote>
<h3 id="사용처">사용처</h3>
<ul>
<li><p>게임 설정 -&gt; 인게임에 크게 영향을 받지 않는 곳에 활용됨</p>
</li>
<li><p>사용 가능한곳</p>
<ul>
<li>설정창</li>
<li>튜토리얼 완료 여부</li>
</ul>
</li>
<li><p>사용 불가능한곳</p>
<ul>
<li>중요한 정보들 -&gt; 변동성이 심한 데이터</li>
</ul>
</li>
</ul>
<hr>
<h3 id="사용법">사용법</h3>
<pre><code>PlayerPrefs.SetFloat(&quot;키&quot;, value)
PlayerPrefs.SetInt(&quot;키&quot;, value)
PlayerPrefs.SetString(&quot;키&quot;, value)

PlayerPrefs.GetFloat(&quot;키&quot;, value)
PlayerPrefs.GetInt(&quot;키&quot;, value)
PlayerPrefs.GetString(&quot;키&quot;, value)</code></pre><hr>
<p>유니티 PlayerPrefs 저장 장소</p>
<p><img src="https://velog.velcdn.com/images/23m-rft68/post/bb714e79-691c-4bfa-aab8-3a46b9a6b7e9/image.png" alt=""></p>
<hr>
<blockquote>
<h3 id="csv">CSV</h3>
</blockquote>
<ul>
<li><mark>C</mark>omma <mark>S</mark>eparated <mark>V</mark>alues<pre><code class="language-csv">ID,HP,ATK
1,100,10
2,200,20</code></pre>
</li>
<li><blockquote>
<p>엑셀 -&gt; 텍스트로 저장</p>
</blockquote>
</li>
</ul>
<h3 id="csv-사용하는-이유">CSV 사용하는 이유</h3>
<p>&quot;몬스터 스탯 -&gt; 필드 변수 다 선언&quot;</p>
<p>[문제]</p>
<ul>
<li>기획자 접근 불가</li>
<li>하드 코딩</li>
<li>데이터 변경 용이X -&gt; 나만 알아본다</li>
</ul>
<p>[CSV 이점]</p>
<ul>
<li>코드(게임 로직) &lt;-&gt; 데이터 분리 -&gt; <code>기획자</code>가 데이터 값 수정 용이</li>
<li>버전 관리 &amp; 협업 용이</li>
</ul>
<p>[CSV 단점]</p>
<ul>
<li>계층적 구조</li>
</ul>
<pre><code class="language-text">Weapon
 ㄴ Sword
     ㄴ RareSword</code></pre>
<pre><code class="language-csv">Weapon,Sword,RareSword</code></pre>
<ul>
<li>중첩 데이터<pre><code class="language-text">Monster
ㄴ Skills
   ㄴ Fire
   ㄴ Ice</code></pre>
<pre><code class="language-csv">ID,Skill1,Skill2 ...
1,Fire,Ice
2,</code></pre>
</li>
</ul>
<p>[CSV 한계]</p>
<ul>
<li>타입 정보 없음 (int, float, bool)</li>
<li>구조적 표현이 불가</li>
<li>런타임 수정 불편</li>
</ul>
<hr>
<blockquote>
<h3 id="json">JSON</h3>
</blockquote>
<ul>
<li>객체 -&gt; 텍스트로 바꿔 외부와 교환하는 방법</li>
</ul>
<h3 id="실무-가지는-문제들">실무 가지는 문제들</h3>
<p>1) 하드코딩된 필드 변수</p>
<pre><code class="language-csharp">int level = 5;</code></pre>
<p>2) 메모리 휘발</p>
<ul>
<li>Unity 객체는 메모리</li>
<li>게임 종료 시, 데이터 삭제</li>
</ul>
<p>3) 서버 데이터</p>
<pre><code class="language-json">{
    &quot;gold&quot;: 500,
    &quot;items&quot;: [&quot;sword&quot;, &quot;potion&quot;]
}</code></pre>
<p>-&gt; 문자열 -&gt; 객체 보완해줘야함</p>
<hr>
<pre><code class="language-csharp">public class Player : MonoBehaviour
{
    public int _level;
    public int _gold;

    public string _path; 

    public void Save()
    {
        string json = JsonUtility.ToJson(this);
        File.WriteAllText(_path, json);
    }
}</code></pre>
<p>-&gt; Player.cs 게임 로직 담당</p>
<p>[위 코드의 문제점]</p>
<ul>
<li>JSON = 데이터를 직접적으로 만짐</li>
</ul>
<p>[역할 분리]</p>
<h4 id="1playercs">1.Player.cs</h4>
<pre><code class="language-csharp">public class Player : MonoBehaviour
{
    public int _level;
    public int _gold;
}</code></pre>
<p>-&gt; 게임 플레이만 담당</p>
<h4 id="2-jsonhandlercs">2. JsonHandler.cs</h4>
<pre><code class="language-csharp">public static class JsonHandler
{
    // 파일 변환
    public static string ToJson(Data data)
    {
        return JsonUtility.ToJson(data)
    }

    // 파일 저장
    public static void Save(string path, string json)
    {
        File.WriteAlltext(path, json)
    }
}</code></pre>
<hr>
<blockquote>
<h3 id="유니티에서-제공하는-json-2가지">유니티에서 제공하는 JSON 2가지</h3>
</blockquote>
<h3 id="1-jsonutility">1) JsonUtility</h3>
<p>[특징]</p>
<ul>
<li>Unity 기본 제공</li>
<li>빠르다</li>
<li>제한 많음</li>
</ul>
<p>[장점]</p>
<ul>
<li>간단한 구조 적합</li>
<li>세이브/설정에 충분히 활용 가능</li>
</ul>
<p>[한계점]</p>
<ul>
<li>Dictionary 미지원</li>
<li>프로퍼티(Property) 미지원</li>
<li>상속 제한</li>
</ul>
<hr>
<h3 id="2-newtonsoft-json">2) Newtonsoft JSON</h3>
<p>Package Manager git URL 설치:</p>
<blockquote>
<p>com.unity.nuget.newtonsoft-json</p>
</blockquote>
<ul>
<li><code>JsonUtility</code>는 Unity 저장 규칙 따름 (Inspector에 뜨나/안뜨나)</li>
<li><code>Newtonsoft JSON</code> Unity 규칙 무관 -&gt; C# 객체를 직접 JSON 바꿈</li>
</ul>
<h3 id="q-무조건-newtonsoft-json을-쓰면-되지-않을까">Q. 무조건 Newtonsoft JSON을 쓰면 되지 않을까?</h3>
<ul>
<li>기획자와 협업? -&gt; 데이터 수치를 기획자가 만질 일이 많다 -&gt; <code>CSV</code></li>
<li>서버 통신/ 복잡한 데이터 -&gt; <code>Newtonsoft JSON</code></li>
<li>간단한 설정/ 캐싱 -&gt; <code>JsonUtility</code></li>
</ul>
<p>[사용처]</p>
<h3 id="csv-1">CSV</h3>
<ul>
<li>아이템 정보 스탯</li>
<li>몬스터 정보</li>
<li>퀘스트 리스트</li>
</ul>
<h3 id="newtonsoft-json">Newtonsoft JSON</h3>
<p>-&gt; C# 객체가 JSON 변환해주기 때문에 JsonUtility가 제공하지 않는 것들도 제공함</p>
<ul>
<li>NPC 대사</li>
<li>유저 인벤토리</li>
</ul>
<h3 id="jsonutility">JsonUtility</h3>
<p>-&gt; Unity에서 제공하는 직렬화 객체들만 가능 = Inspector에서 보이는지 여부</p>
<ul>
<li>설정창</li>
<li>업적 </li>
</ul>
<hr>
<blockquote>
<h3 id="scriptableobject">ScriptableObject</h3>
</blockquote>
<h3 id="경량-패턴flyweight-pattern-형태-비슷">경량 패턴(Flyweight Pattern) 형태 비슷</h3>
<p><img src="https://velog.velcdn.com/images/23m-rft68/post/5092f70d-d4c3-485c-b027-ce41ee6bb00f/image.png" alt=""></p>
<pre><code class="language-csharp">public class TreeModel : MonoBehaviour
{
    Mesh _mesh;
    Texture _bark;
    Texture _leaves;
}</code></pre>
<pre><code class="language-csharp">public class Tree
{
    TreeModel _model;

    Vector3 _position;
    double _height;
    double _width;

    Color _barkTint;
    Color _leafTink;
}</code></pre>
<p><img src="https://velog.velcdn.com/images/23m-rft68/post/c8f0fb6c-d9be-4a6b-bd70-298a604eeb88/image.png" alt=""></p>
<h3 id="scriptableobject-1">ScriptableObject</h3>
<ul>
<li>초기 설정값이 되는 것들<ul>
<li>몬스터 종류</li>
<li>프리팹</li>
<li>HP/MP</li>
<li>이동 속도</li>
<li>연출 애니메이션</li>
<li>SFX 등등</li>
</ul>
</li>
</ul>
<hr>
<blockquote>
<h3 id="csv---json---scriptableobject">CSV - JSON - ScriptableObject</h3>
</blockquote>
<h4 id="csv-2">CSV</h4>
<ul>
<li>수치 테이블<ul>
<li>밸런스 기획</li>
</ul>
</li>
</ul>
<h4 id="json-1">JSON</h4>
<ul>
<li>직렬화 포맷<ul>
<li>데이터를 저장, 통신</li>
</ul>
</li>
</ul>
<h4 id="scriptableobject-2">ScriptableObject</h4>
<ul>
<li>유니티에서 제공하는 초기 데이터 설정<ul>
<li>초기 데이터 타입</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL-260218] NavMesh]]></title>
            <link>https://velog.io/@23m-rft68/TIL-260218-Nav-Mesh</link>
            <guid>https://velog.io/@23m-rft68/TIL-260218-Nav-Mesh</guid>
            <pubDate>Wed, 18 Feb 2026 07:25:49 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-배운-내용">오늘 배운 내용</h1>
<h2 id="--navmesh">- NavMesh</h2>
<hr>
<blockquote>
<h3 id="navmesh">NavMesh</h3>
</blockquote>
<ul>
<li><p>이동 로직을 코드로 짜지 않고 사용하는 시스템 내부적으로 (Graph)로 데이터화 해서 성능-안정성 우수함.
<img src="https://velog.velcdn.com/images/23m-rft68/post/d7be66ba-d7d2-4b5f-aa93-7421a42a3262/image.png" alt="">
<img src="https://velog.velcdn.com/images/23m-rft68/post/af293506-cb48-4c04-8e17-bbb12579d7bc/image.png" alt=""></p>
</li>
<li><p>NavMesh 는 Bake 시점에서 계산이 끝남.</p>
</li>
</ul>
<hr>
<blockquote>
<h3 id="bake-단계-사전-준비">Bake 단계 (사전 준비)</h3>
</blockquote>
<p>컴포넌트: NavMesh Surface -&gt; Bake 버튼 클릭!</p>
<h4 id="1--공간-판별">1.  공간 판별</h4>
<p>Unity 씬을 훑음</p>
<ul>
<li>이 표면 Walking 가능한가?</li>
<li>경사 각도 올라갈 수 있는가? [Navigation 탭 - Max Slope]</li>
<li>Agent가 지나갈 수 있는 충분한 부피/반지름 인가? [Navigation 탭 - Radius]</li>
</ul>
<h4 id="2-공간을-폴리곤면polygon으로-분해생성">2. 공간을 폴리곤/면(Polygon)으로 분해/생성</h4>
<p><img src="https://velog.velcdn.com/images/23m-rft68/post/4f2fa32a-716b-4ef9-bfe9-a6377358f54d/image.png" alt=""></p>
<ul>
<li>다각형(Polygon)으로 쪼갬</li>
<li>이동에 필요한 정보만 남김</li>
</ul>
<h4 id="3-폴리곤면polygon-간-연결">3. 폴리곤/면(Polygon) 간 연결</h4>
<ul>
<li>폴리곤/면 간 생기는 선 엣지(Edge)</li>
</ul>
<h4 id="4-area---cost-저장">4. Area - Cost 저장</h4>
<p><img src="https://velog.velcdn.com/images/23m-rft68/post/bf881939-ba8c-434b-a617-c5ccd1a8347a/image.png" alt=""></p>
<ul>
<li>이동 우선 순위를 정함</li>
</ul>
<hr>
<blockquote>
<h3 id="runtime-단계-이동-요청-시">Runtime 단계 (이동 요청 시)</h3>
</blockquote>
<pre><code class="language-csharp">agent.SetDestination(target.position);</code></pre>
<ol>
<li><strong>현재 위치</strong>가 속한 폴리곤/면 찾기 -&gt; 내 위치 찾기</li>
<li><strong>목적지</strong> 폴리곤/면 찾기</li>
<li>폴리곤 그래프(Graph)에서 최적 경로 검색 (경로 O/X ❌ -&gt;  경로 선택)<ul>
<li>A* 계열, 상대적으로 노드 수가 적음</li>
</ul>
</li>
<li>폴리곤 경로를 따라 이동 경로 생성</li>
</ol>
<h3 id="navmesh가-내부에-가지고-있는-정보">NavMesh가 내부에 가지고 있는 정보</h3>
<pre><code>[폴리곤 A] ㅡ 연결 ㅡ [폴리곤 B]
[폴리곤 B] ㅡ 연결 ㅡ [폴리곤 C]</code></pre><ul>
<li>좌표 X</li>
<li>텍스처 X</li>
<li>렌더링 정보 X</li>
</ul>
<p>-&gt; 이동 정보만 가짐 -&gt; 그래프 기반 이동이기 때문에 이미 검증된 길만 탐색함</p>
<hr>
<blockquote>
<h3 id="a-vs-navmesh">A* vs NavMesh</h3>
</blockquote>
<h3 id="a">A*</h3>
<ul>
<li>노드 생성: 런타임(Runtime)</li>
<li>그래프 구성: 직접</li>
<li>비용 계산: 항상</li>
</ul>
<h3 id="navmesh-1">NavMesh</h3>
<ul>
<li>노드 생성: Bake</li>
<li>그래프 구성: 엔진</li>
<li>비용 계산: 최소화</li>
</ul>
<hr>
<blockquote>
<h3 id="navmesh-기본-구성">NavMesh 기본 구성</h3>
</blockquote>
<h3 id="1-navmesh-surface---길-만들기">1. NavMesh Surface - 길 만들기</h3>
<p><img src="https://velog.velcdn.com/images/23m-rft68/post/f4238f91-23c3-4adf-9228-e58bbefaf5ed/image.png" alt=""></p>
<ul>
<li>걸어다닐 수 있는 공간인지 판별해주는 매니저 역할<h3 id="2-navmesh-agent">2. NavMesh Agent</h3>
<img src="https://velog.velcdn.com/images/23m-rft68/post/a8688fa6-d0c6-47f2-a1c9-7122c0bcbc3c/image.png" alt=""></li>
</ul>
<p>역할</p>
<ul>
<li>이동</li>
<li>회전</li>
<li>충돌 회피</li>
</ul>
<p>프로퍼티</p>
<ul>
<li>speed</li>
<li>angular speed</li>
<li>Stopping Distance</li>
</ul>
<p>필수함수</p>
<pre><code class="language-csharp">agent.SetDestination(target.position);</code></pre>
<p>유의사항</p>
<ul>
<li>transform.position 으로 이동  X</li>
<li>Rigidbody 동시 제어 X</li>
</ul>
<h3 id="3-navmesh-obstacle---동적-장애물">3. NavMesh Obstacle - 동적 장애물</h3>
<p><img src="https://velog.velcdn.com/images/23m-rft68/post/1d8c4c23-8263-46d7-8c3a-33f6e808be5b/image.png" alt=""></p>
<p>필수 기능</p>
<ul>
<li>Carving [ON] -&gt; 못가는 길을 만듦.</li>
</ul>
<p>유의사항</p>
<ul>
<li>많이 쓰면 성능 하락</li>
<li>많이 움직일 필요가 없는 물체 정도만 사용</li>
</ul>
<hr>
<blockquote>
<h3 id="agent-settings">Agent Settings</h3>
</blockquote>
<p><img src="https://velog.velcdn.com/images/23m-rft68/post/0d78180a-5a7a-4477-8d04-4a17d0d3e21e/image.png" alt=""></p>
<ul>
<li>Radius/Height -&gt; 캐릭터 부피/크기</li>
<li>Step Height/Max Slope -&gt; 계단-경사 허용치</li>
</ul>
<p>-&gt; Agent(AI) 몸체</p>
<hr>
<blockquote>
<h3 id="areas">Areas</h3>
</blockquote>
<p><img src="https://velog.velcdn.com/images/23m-rft68/post/e2524b58-e7e2-4436-b11a-1aef6de0bea2/image.png" alt=""></p>
<ul>
<li>0~31번까지 있음</li>
<li>Cost = 선호도 (낮을수록 우선순위)</li>
</ul>
<hr>
<blockquote>
<h3 id="navmesh-link">NavMesh Link</h3>
</blockquote>
<p><img src="https://velog.velcdn.com/images/23m-rft68/post/7a07db38-cb09-4400-a03c-9bc9c3a4e450/image.png" alt=""></p>
<ul>
<li>끊긴 길 연결<ul>
<li>점프</li>
<li>드롭(낙하)</li>
<li>사다리</li>
</ul>
</li>
</ul>
<hr>
<blockquote>
<h3 id="navmesh-modifier-volume">NavMesh Modifier Volume</h3>
</blockquote>
<p><img src="https://velog.velcdn.com/images/23m-rft68/post/937c0c00-c0d3-4c2f-b54b-e2c7a9629b1d/image.png" alt=""></p>
<h4 id="역할">역할</h4>
<ul>
<li>특정 영역의 길을 설정</li>
</ul>
<h4 id="예시">예시</h4>
<ul>
<li>늪지대</li>
<li>함정 구역</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL-260214] 빛]]></title>
            <link>https://velog.io/@23m-rft68/TIL-260214</link>
            <guid>https://velog.io/@23m-rft68/TIL-260214</guid>
            <pubDate>Sat, 14 Feb 2026 09:42:50 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-배운-내용">오늘 배운 내용</h1>
<h2 id="--빛">- 빛</h2>
<hr>
<h2 id="빛">빛</h2>
<h3 id="q-rp-어디-단계에서-일어나는가">Q. RP 어디 단계에서 일어나는가?</h3>
<p> -&gt; 픽셀/프래그먼트 쉐이더
 -&gt; <strong>GPU 연산</strong>이 일어난다? -&gt; 과부하 요소가 있다 -&gt; 최적화 할 필요가 있다</p>
<h3 id="q-unity6-는-어떤-rp-방식인가">Q. Unity6 는 어떤 RP 방식인가?</h3>
<p> -&gt; Forward + RP 방식 (Default)</p>
<hr>
<blockquote>
<h3 id="unity가-지원하는-빛-컴포넌트">Unity가 지원하는 빛 컴포넌트</h3>
</blockquote>
<h4 id="light-mode">Light Mode</h4>
<ol>
<li><p>Realtime</p>
<ul>
<li>매 프레임 객체에 빛과 그림자를 실시간으로 계산하는 친구</li>
<li>부하가 높음</li>
<li>빛 연산이 민감하게 처리되야 하는 모든 곳(횃불)</li>
<li>그림자 연산 처리도 신경써줘야한다 (특히 모바일)</li>
</ul>
</li>
<li><p>Mixed</p>
<ul>
<li><p>정적 객체 -&gt; lightmap으로 굽기</p>
</li>
<li><p>동적 객체 -&gt; Realtime으로 굽기
-&gt; 하이브리드 방식</p>
</li>
<li><p><strong>Lighting settings</strong></p>
<ul>
<li><strong>Shadowmask(표준)</strong>: 실시간 그림자 + Baked된 그림자 섞음</li>
<li><strong>Subtractive(저사양 모바일)</strong>: 가볍고 퀄리티가 낮음</li>
<li><strong>Baked Indirect(고사양)</strong></li>
</ul>
</li>
</ul>
</li>
<li><p>Baked</p>
<ul>
<li>빛의 정보를 미리 계산함 -&gt; lightmap (Texture) 형식으로 저장함</li>
<li>런타임 연산이 거의 없다</li>
<li>부하가 매우 낮음</li>
<li>변하지 않는 환경에 세팅된 물체</li>
</ul>
</li>
</ol>
<h4 id="1-directional-light">1. Directional Light</h4>
<p> -&gt; 모든 씬에서 태양광 역할 </p>
<ol start="2">
<li><p>Point Light</p>
<ul>
<li><strong>모양</strong>: 구</li>
<li><strong>특징</strong>: 전방향 발사</li>
<li><strong>사례</strong>: 횃불, 랜턴, 모닥불, 마법 효과, 반딧불</li>
</ul>
</li>
<li><p>Spot Light</p>
<ul>
<li><strong>모양</strong>: 원뿔형 조명</li>
<li><strong>특징</strong>: 원뿔형 발사</li>
<li><strong>사례</strong>: 손전등, 가로등</li>
</ul>
</li>
<li><p>Area Light</p>
<ul>
<li>이 친구만 <strong>Baked</strong> -&gt; Why? 연산 비용이 비싸서</li>
<li><strong>사례</strong>: 실내 형광등, 창문 채광</li>
</ul>
</li>
<li><p>(+)Light Probe Group</p>
<ul>
<li>동적 오브젝트에게 라이트맵(lightmap)을 입히는 기능
= Baked된 Texture를 입히는 작업</li>
</ul>
</li>
<li><p>(+)Reflection Probe  </p>
</li>
</ol>
<hr>
<blockquote>
<h3 id="lighting-setting">Lighting Setting</h3>
</blockquote>
<p> <img src="https://velog.velcdn.com/images/23m-rft68/post/abf7c539-b2e1-4159-8037-6292bf84ac4d/image.png" alt=""></p>
<ul>
<li><p>Light Settings Asset</p>
</li>
<li><p>Lightmapper</p>
<ul>
<li>Progressive GPU권장</li>
</ul>
</li>
<li><p>Lightmap Resolution</p>
<ul>
<li>모바일: 5~15 (권장)</li>
<li>PC/콘솔: 20~40</li>
</ul>
</li>
<li><p>Max Lightmap Size</p>
<ul>
<li>텍스처 해상도</li>
<li>표준 1024 (되도록 건들지 않기)</li>
</ul>
</li>
<li><p>Direct/Indirect Samples</p>
<ul>
<li>수치가 높을수록 Noise가 줆 -&gt; 근데 Baked 시간 엄청 튐(되도록 건들지 않기)</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL-260213] Character Controller]]></title>
            <link>https://velog.io/@23m-rft68/TIL-260213</link>
            <guid>https://velog.io/@23m-rft68/TIL-260213</guid>
            <pubDate>Sat, 14 Feb 2026 09:40:59 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-배운-내용">오늘 배운 내용</h1>
<h2 id="--character-controller">- Character Controller</h2>
<hr>
<blockquote>
<h3 id="character-controller-속성">Character Controller 속성</h3>
</blockquote>
<ul>
<li>Slope Limit<ul>
<li>Default: 45</li>
<li>이 수치를 넘으면 이동 상쇄</li>
</ul>
</li>
<li>Step Offset<ul>
<li>Default: 0.3</li>
<li>계단 높이, 되도록 0.3을 넘기지 않음</li>
</ul>
</li>
<li>Skin Width<ul>
<li>충돌 계산의 완충 지대</li>
<li>수치가 작으면: 벽에 낌</li>
<li>수치가 크면: 캐릭터가 공중에 뜬 것처럼 보임</li>
</ul>
</li>
<li>Min Move Distance<ul>
<li>Default: 0.001</li>
<li>지터링 방지를 위해 기본값(0.001) 유지</li>
</ul>
</li>
</ul>
<hr>
<blockquote>
<h3 id="이동-방식-3가지">이동 방식 3가지</h3>
</blockquote>
<h3 id="1-transform">1. Transform</h3>
<ul>
<li>이동X -&gt; 순간이동</li>
<li>사례: 충돌이 필요 없는 투사체<pre><code class="language-csharp">transform.position += direction * speed * Time.deltaTime();</code></pre>
<h3 id="2-rigidbody">2. Rigidbody</h3>
</li>
<li>물리 법칙의 지배</li>
<li>velocity / AddForce()<h3 id="3-character-controller">3. Character Controller</h3>
</li>
<li>단독 캐릭터 조작할 때 많이 사용</li>
</ul>
<hr>
<blockquote>
<h3 id="이동-방식-3가지-실사용-사례">이동 방식 3가지 실사용 사례</h3>
</blockquote>
<h3 id="1-transform-1">1. Transform</h3>
<ul>
<li>배경 연출</li>
<li>아이템 획득 UI (주로 UI 연출)</li>
<li>카메라 연출<h3 id="2-rigidbody-1">2. Rigidbody</h3>
</li>
<li>레이싱 게임</li>
<li>앵그리 버드</li>
<li>게팅오버잇</li>
<li>폴가이즈<h3 id="3-character-controller-1">3. Character Controller</h3>
</li>
<li>바이오하자드</li>
<li>오버워치</li>
<li>소울류</li>
<li>FPS류</li>
<li>RPG 주인공</li>
</ul>
<hr>
<h4 id="지터링jittering"><strong>지터링</strong>(Jittering)</h4>
<p> -&gt; Character Controller + Rigidbody 같이 쓸 때 나타나는 현상. 두 컴포넌트가 서로 좌표를 잡으려고함</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL-260212] Object Pool / Particle System / Audio]]></title>
            <link>https://velog.io/@23m-rft68/TIL-260212-Object-Pool-Particle-System-Audio</link>
            <guid>https://velog.io/@23m-rft68/TIL-260212-Object-Pool-Particle-System-Audio</guid>
            <pubDate>Thu, 12 Feb 2026 11:23:28 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-배울-내용">오늘 배울 내용</h1>
<h2 id="--오브젝트-풀">- 오브젝트 풀</h2>
<h2 id="--파티클-시스템">- 파티클 시스템</h2>
<h2 id="--오디오">- 오디오</h2>
<hr>
<h3 id="instantiate-함수">Instantiate 함수</h3>
<ul>
<li>객체를 <code>생성</code>해주는 함수</li>
</ul>
<h3 id="object-pooling">Object Pooling</h3>
<ul>
<li>미리 생성된 객체를 필요할 때 <code>꺼내고/넣고 쓰는 방식</code></li>
</ul>
<hr>
<blockquote>
<h3 id="1-instantiate-함수-unity-내부에서-일어나는-일">1. Instantiate 함수 Unity 내부에서 일어나는 일</h3>
</blockquote>
<p><strong>1-1. 메모리 할당 및 직렬화 해제</strong></p>
<ul>
<li>메모리 할당 -&gt; RAM위에 올리는 단계</li>
</ul>
<p><strong>1-2. 역직렬화(Deserialization)</strong></p>
<ul>
<li>Instantiate 함수 호출 시, 역직렬화 발생</li>
</ul>
<p><strong>1-3. 리플렉션 비용 발생</strong></p>
<ul>
<li>프리팹(Prefeb)을 복사(Instantiate)할 때, <code>어떤 데이터</code>와 <code>컴포넌트</code>가 붙어 있는지 일일이 확인해서 복붙 (역시 CPU가 부담)</li>
</ul>
<p><strong>1-4. 드로우콜 부담</strong></p>
<ul>
<li>Awake() {}</li>
<li>Start() {}</li>
<li>Update() {}</li>
</ul>
<p>-&gt; 위 이벤트 함수를 호출하는 스크립트가 붙은 오브젝트 -&gt; 천개 단위로 있다.</p>
<hr>
<blockquote>
<h3 id="2-오브젝트-풀링">2. 오브젝트 풀링</h3>
</blockquote>
<ul>
<li><code>생성 비용 -&gt; 활성화</code> 비용으로 치환하는 기술</li>
</ul>
<ol>
<li><p>화면에 필요한 양만큼 미리 오브젝트를 메모리에 적재해서 사용</p>
</li>
<li><p>객체 파괴(Destroy)대신 -&gt; SetActive(False)를 사용
-&gt; 메모리 할당/해제 막고 GC 발생 원천 차단</p>
</li>
<li><p>메모리 점유율을 일정하게 유지</p>
</li>
</ol>
<h3 id="추가-instantiate-함수가-오브젝트-풀보다-느린-이유">(+추가) Instantiate 함수가 오브젝트 풀보다 느린 이유</h3>
<h4 id="1-데이터-전송-hddsdd---ram---vram">1. 데이터 전송 (HDD/SDD -&gt; RAM -&gt; VRAM)</h4>
<pre><code>- 전송해야 될 데이터가 크면 클수록, CPU 부담 발생 -&gt; 게임이 &#39;렉&#39; 걸림...</code></pre><h4 id="2-쉐이더-컴파일">2. 쉐이더 컴파일</h4>
<hr>
<blockquote>
<h3 id="3-오브젝트-풀링-장점">3. 오브젝트 풀링 장점</h3>
</blockquote>
<h4 id="cpu--ram-최적화">CPU &amp; RAM 최적화</h4>
<pre><code>- `생성/삭제` 연산 횟수 최소화
-&gt; 재사용성의 장점 (오브젝트 ON/OFF)
-&gt; 매 프레임 게임 안정성 유지, GC렉 방지</code></pre><hr>
<blockquote>
<h3 id="4-오브젝트-풀---메서드">4. 오브젝트 풀 -&gt; 메서드</h3>
</blockquote>
<ul>
<li><p>메모리 단편화(Fragment)</p>
</li>
<li><p>GC 호출 최소화</p>
<ul>
<li>Destroy 함수 호출</li>
</ul>
</li>
</ul>
<hr>
<blockquote>
<h3 id="5-유니티-profiler-테스트">5. 유니티 Profiler 테스트</h3>
</blockquote>
<p>[Instantiate/Destroy]
<img src="https://velog.velcdn.com/images/23m-rft68/post/5b736d92-27ac-42df-8d79-4774f43457e2/image.png" alt=""></p>
<p>[옵젝 풀]
<img src="https://velog.velcdn.com/images/23m-rft68/post/cea56dc1-a55c-49d9-ae7d-46cb39b0aaaa/image.png" alt=""></p>
<hr>
<blockquote>
<h3 id="6-오브젝트-풀-실전-사례">6. 오브젝트 풀 실전 사례</h3>
</blockquote>
<ol>
<li><p>오디오(Audio)</p>
<ul>
<li>사용 사례: 피격음, 총 발사, 타격음</li>
</ul>
</li>
<li><p>파티클(Particle)</p>
<ul>
<li>사용 사례: 피격 이펙트, 트레일(궤적)</li>
</ul>
</li>
</ol>
<p>Q. 풀링은 언제 사용하면 안될까?</p>
<ul>
<li>씬에 객체 개수가 그렇게 많지 않다면 + 빈번하게 생성/파괴가 일어나지 않는다면</li>
</ul>
<hr>
<blockquote>
<h3 id="7-오브젝트-풀-어떤-자료구조-사용하는가">7. 오브젝트 풀 어떤 자료구조 사용하는가?</h3>
</blockquote>
<ul>
<li><strong>List</strong></li>
<li><strong>Stack</strong></li>
<li><strong>Queue</strong></li>
<li><strong>Dictionary</strong></li>
<li>HashSet</li>
<li>Array</li>
<li>LinkedList</li>
</ul>
<h4 id="7-1-list-비권장">7-1. List (비권장)</h4>
<ul>
<li>특징: 순서가 있고 인덱스 접근이 가능하다.</li>
<li>문제점: 중간 데이터를 삭제하거나 삽입할 때 뒤의 데이터를 당겨오거나 밀어내는 <code>오버헤드</code>가 발생 풀링의 목적인 &#39;최적화&#39;에 부합하지 않아서 단독으로는 잘 쓰이지 않는다.</li>
</ul>
<h4 id="7-2-stack-성능-중시---cpu-캐시-효율을-극대화하여-01ms라도-아껴야-할-때">7-2. Stack (성능 중시) - &quot;CPU 캐시 효율을 극대화하여 0.1ms라도 아껴야 할 때&quot;</h4>
<ul>
<li>특징: 후입선출(LIFO)</li>
<li>사용사례:<ul>
<li><code>대량의 탄막/탄피</code>: 방금 사용하고 반납된 &#39;따끈따끈한&#39; 객체는 메모리의 <code>캐시(Cache)</code>에 남아있을 확률이 매우 높다. 이를 즉시 재사용하면 CPU 연산 속도가 비약적으로 향상된다.</li>
<li><code>동적 확장</code>: 필요한 만큼만 조금씩 늘려가며 사용할 때, 최근 생성된 객체를 우선 사용하므로 `캐시 적중률(Cache Hit) 이 최상이다.</li>
</ul>
</li>
<li>가치: <code>퍼포먼스 최상</code>. 자원이 한정적인 모바일 환경이나 대규모 탄막 게임에서 필수이다.</li>
</ul>
<h4 id="7-3-queue★안정성-중시---예외-없는-초기화와-시스템의-균일한-동작이-중요할-때">7-3. Queue(★안정성 중시) - &quot;예외 없는 초기화와 시스템의 균일한 동작이 중요할 때&quot;</h4>
<ul>
<li>특징: 선입선출(FIFO)</li>
<li>사용 사례: <ul>
<li><code>파티클/이펙트</code>: 연출 시간이 제각각인 이펙트들을 골고루 순환시켜, 특정 객체만 과부하가 걸리는 것을 방지하고 파티클 연산의 꼬임을 막습니다.</li>
<li>`버그 탐지(QA): 100개중 1개라도 초기화(Reset) 로직이 잘못되었다면, 순환 구조상 무조건 버그가 발견된다. &quot;안걸리고 넘어가는 버그&quot;를 원천 차단한다.</li>
</ul>
</li>
<li>가치: <code>디버깅과 시스템 안정성</code>. 로직이 복잡한 대작 프로젝트나 개발 초기 단계에서 권장</li>
</ul>
<h4 id="7-4-dictionary관리의-핵심---수많은-종류의-프리팹을-하나의-매니저에서-관리할-때">7-4 Dictionary(관리의 핵심) - &quot;수많은 종류의 프리팹을 하나의 매니저에서 관리할 때&quot;</h4>
<ul>
<li>특징: 키(Key)를 통해 원하는 바구니(Value)를 즉시 찾는다.(O(1)의 속도)</li>
<li>실무 활용: <code>Enum</code>이나 <code>GameObject(Prefab)</code> 자체를 키값으로 사용하여, 어떤 물건을 빌려줄지 결정하는 <strong>&#39;거대 창고 관리 대장&#39;</strong> 역할을 한다.</li>
<li><strong>주의</strong>: 메모리를 다소 점유하므로 키값을 너무 남발하지 않도록 주의해야 한다. </li>
</ul>
<p>[실무] 자주 사용하는 구조</p>
<pre><code class="language-csharp">Dictionary&lt;키,자료구조&lt;키&gt;&gt;

Dictionary&lt;Enum,Queue&lt;GameObject&gt;&gt;
Dictionary&lt;Enum,Stack&lt;GameObject&gt;&gt;</code></pre>
<hr>
<blockquote>
<h3 id="오브젝트-풀-구조">오브젝트 풀 구조</h3>
</blockquote>
<ul>
<li>PoolManager.cs -&gt; 객체를 꺼내서 On(Get 함수) / (Release)OFF<ul>
<li>Object Script : IPoolable -&gt; 상태 초기화(OnSpawn 함수) 및 돌려주기(OnDespawn 함수)</li>
<li>Object Script : IPoolable -&gt; 상태 초기화(OnSpawn 함수) 및 돌려주기(OnDespawn 함수)</li>
<li>Object Script : IPoolable -&gt; 상태 초기화(OnSpawn 함수) 및 돌려주기(OnDespawn 함수)...</li>
</ul>
</li>
</ul>
<hr>
<h2 id="particle-system">Particle System</h2>
<blockquote>
<h3 id="협업-프로세스">협업 프로세스</h3>
</blockquote>
<ol>
<li>VFX/이펙트 아티스트 or Assets<ul>
<li>파티클 모양, 색상, 텍스처 제작</li>
</ul>
</li>
<li>클라이언트 개발자 <ul>
<li>제작된 파티클 프리팹 -&gt; 오브젝트 풀 등록 -&gt; 게임 로직에 맞춰서 호출되는 코드 작성</li>
</ul>
</li>
</ol>
<hr>
<blockquote>
<h3 id="기본-속성">기본 속성</h3>
</blockquote>
<ul>
<li>Main Module: <code>Start Lifetime</code>, <code>Start Speed</code>등 파티클의 초기 설정을 결정<ul>
<li>Simulation Space: <code>World</code> = 잔상 효과</li>
</ul>
</li>
<li>Emission: 파티클 생성 빈도를 결정<ul>
<li>단발성 피격 효과는 <code>Rate over Time</code> X <code>Bursts</code>(한꺼번에 뿜어내기) 사용</li>
</ul>
</li>
<li>Shape: 파티클이 방출되는 모양(구체, 원뿔, 박스 등)을 정의</li>
<li>Color over Lifetime: 시간이 지남에 따라 파티클의 색상이나 투명도(Alpha)를 변화<ul>
<li>ex: 연기가 서서히 투명해지는 효과</li>
</ul>
</li>
<li>Size over Lifetime: 입자가 크기를 변화를 줌(역동성)</li>
<li>Renderer: 파티클 시각적 외형을 결정</li>
</ul>
<hr>
<blockquote>
<h3 id="파티클-초기화-함수">파티클 초기화 함수</h3>
</blockquote>
<ul>
<li>파티클 OFF -&gt; 초기화X -&gt; 파티클 켜진 상태 잔상 남은 상태에서 어색하게 Play 됨<pre><code class="language-csharp">ps.Clear();
ps.Stop(ture, ParticleSystemBehaviour.StopEmittingAndClear); // Clear() 함수 포함
</code></pre>
</li>
</ul>
<p>ps.Play();</p>
<h2 id="">```</h2>
<h2 id="audio">Audio</h2>
<blockquote>
<h3 id="유니티-오디오-3요소">유니티 오디오 3요소</h3>
</blockquote>
<ol>
<li>Audio Listener (귀)</li>
<li>Audio Source (스피커)</li>
<li>Audio Clip (음원)</li>
</ol>
<hr>
<blockquote>
<h3 id="audio-clip">Audio Clip</h3>
</blockquote>
<h4 id="load-type">Load type</h4>
<ul>
<li>Deconpress on Load(★)<ul>
<li>짧은 효과음(SFX)<ul>
<li>로드 시 압축품</li>
</ul>
</li>
</ul>
</li>
<li>Compressed In Memory<ul>
<li>일반적인 소리</li>
<li>메모리에 압 올리고 -&gt; 재생시 압축 풀림</li>
</ul>
</li>
<li>Streaming<ul>
<li>배경음(BGM)<ul>
<li>메모리에 올리지 않고 씀</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="compression-format-압축-포맷">Compression Format (압축 포맷)</h4>
<ul>
<li>PCM<ul>
<li>무압축 고음질 데이터</li>
</ul>
</li>
<li>Vorbis(★)<ul>
<li>압축률이 좋음 -&gt; 실무에서 자주 사용</li>
</ul>
</li>
<li>ADPCM<ul>
<li>PCM보다 용량 작음<ul>
<li>노이즈 섞인 짧은 소리 유용</li>
</ul>
</li>
</ul>
</li>
<li>Force To Mono<ul>
<li>채널이 하나로 합쳐짐 -&gt; 용량이 절반</li>
</ul>
</li>
</ul>
<hr>
<blockquote>
<h3 id="audiosource">AudioSource</h3>
</blockquote>
<h4 id="핵심-속성">핵심 속성</h4>
<ul>
<li>Priority<ul>
<li>0~256설정 가능 -&gt; 주로 배경음은 0 설정</li>
</ul>
</li>
<li>Spatial Blend<ul>
<li><del>01 (2D3D)</del><pre><code>  - 0 (2D - BGM, UI)</code></pre><ul>
<li>1 (3D - 발소리, 효과음)</li>
</ul>
</li>
</ul>
</li>
<li>Volume &amp; Pitch<ul>
<li>Pitch: 0.9~1.1 사이로 조정할 때 사운드 풍부</li>
</ul>
</li>
<li>Play On Awake<ul>
<li>체크 시, 게임 시작과 동시에 시작<h4 id="거리-감쇄-falloff">거리 감쇄 (FallOff)</h4>
</li>
</ul>
</li>
<li>Min Distance / Max Distance: 소리 거리 설정</li>
<li>Rolloff Mode<ul>
<li>평시: Logaritmic<ul>
<li><code>거리감을 일정하게 주고싶을 때</code>: Linear</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<blockquote>
<h3 id="오디오-실행-함수">오디오 실행 함수</h3>
</blockquote>
<ul>
<li>Play()<ul>
<li>기존 소리 끊고 새로 시작</li>
<li>BGM 교체</li>
</ul>
</li>
<li>PlayOneShot()<ul>
<li>기존 소리에 <mark>&#39;중첩&#39;</mark>해서 재생</li>
<li>대부분 효과음</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL-260211] 애니메이션과 FSM]]></title>
            <link>https://velog.io/@23m-rft68/TIL-260211-%EC%95%A0%EB%8B%88%EB%A9%94%EC%9D%B4%EC%85%98%EA%B3%BC-FSM</link>
            <guid>https://velog.io/@23m-rft68/TIL-260211-%EC%95%A0%EB%8B%88%EB%A9%94%EC%9D%B4%EC%85%98%EA%B3%BC-FSM</guid>
            <pubDate>Wed, 11 Feb 2026 08:43:39 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-배운-내용">오늘 배운 내용</h1>
<hr>
<h2 id="--애니메이션과-fsm">- 애니메이션과 FSM</h2>
<hr>
<blockquote>
<h2 id="1-fsm유한-상태-머신-무엇인가">1. FSM(유한 상태 머신) 무엇인가?</h2>
</blockquote>
<ul>
<li>객체가 한 번에 하나의 상태만 가질 수 있도록 제어하는 모델.</li>
</ul>
<p>[구조]</p>
<pre><code>현재 상태(State) + 조건(Parameter) -&gt; 상태 전이(Transition)</code></pre><p>Idle &lt;-&gt; Walking &lt;-&gt; Running</p>
<hr>
<blockquote>
<h2 id="2-unity-animation-구성-요소">2. Unity Animation 구성 요소</h2>
</blockquote>
<h3 id="2-1-컴포넌트">2-1. 컴포넌트</h3>
<ul>
<li><p>Animation (Legacy)</p>
<ul>
<li>단순한 클립 재생</li>
<li>.anim 파일</li>
</ul>
</li>
<li><p>Animator (New)</p>
<ul>
<li>상태 전이가 활발한데 제어도 필요할 때</li>
<li>.controller 파일</li>
<li>Parameter 탭 수치를 조절</li>
</ul>
</li>
</ul>
<ul>
<li>Animation과 Animator가 둘 다 사용하는 것 -&gt; Animation Clip (녹화본)</li>
<li><h4 id="animation은-단순한-연출에-활용된다"><strong>Animation은 단순한 연출에 활용된다.</strong></h4>
</li>
</ul>
<hr>
<h3 id="1-skinnedmeshrenderer-컴포넌트">1. SkinnedMeshRenderer 컴포넌트</h3>
<ul>
<li>뼈의 움직임에 따라 변형되는 메쉬(Mesh) 를 화면에 그리는 컴포넌트</li>
</ul>
<h3 id="2-animator-컴포넌트">2. Animator 컴포넌트</h3>
<ul>
<li>애니메이션 설계도(Controller)를 읽어 뼈(Bone)을 실제로 움직이는 엔진</li>
</ul>
<h3 id="3-animator-controller">3. Animator Controller</h3>
<ul>
<li>애니메이션의 흐름도를 볼 수 있다</li>
</ul>
<h3 id="3-1-state-노드">3-1. State (노드)</h3>
<ul>
<li>캐릭터가 취할 수 있는 각각의 행동 단위
<img src="https://velog.velcdn.com/images/23m-rft68/post/95e33aa4-122e-48f5-92a1-315c7889387b/image.png" alt=""></li>
</ul>
<h3 id="3-2-transition-상태-전이-표시-화살표">3-2. Transition (상태 전이 표시, 화살표)</h3>
<ul>
<li>상태(State)&lt;-&gt;상태(State) 를 잇는 통로
<img src="https://velog.velcdn.com/images/23m-rft68/post/5899ade3-6194-4e48-aad9-be633f3d885f/image.png" alt=""></li>
</ul>
<p><img src="https://velog.velcdn.com/images/23m-rft68/post/8d98039d-05b2-4858-a2c5-f4dc0ee17863/image.png" alt=""></p>
<h3 id="3-3-parameter">3-3. Parameter</h3>
<ul>
<li>코드에서 애니메이터로 보내는 데이터</li>
</ul>
<h3 id="conditions">Conditions</h3>
<ul>
<li>Transition이 일어나기 위한 조건문(Float, Int, Bool, Trigger)<ul>
<li>Float: 이동 속도처럼 <code>부드러운 변화</code></li>
<li>Int: 무기 스왑이 필요한 것들</li>
<li>Bool: 상태 체크</li>
<li>Trigger: Attack처럼 단발성 이벤트 </li>
</ul>
</li>
</ul>
<ul>
<li><strong>개발자는 위 4가지 Parameter들로 스크립트로 제어하여 State(노드)간 Transition(상태 전이)를 제어한다.</strong></li>
</ul>
<hr>
<blockquote>
<h2 id="3-추가-속성-기능">3. 추가 속성 기능</h2>
</blockquote>
<ul>
<li>Loop Time<ul>
<li>동작 반복 여부 결정</li>
</ul>
</li>
<li>Animation Type<ul>
<li>인간형이라면 반드시 Humanoid로 설정해야 다른 캐릭터의 애니메이션을 재사용 가능</li>
</ul>
</li>
<li>Avator (Configure)<ul>
<li>유니티가 캐릭터의 관절(머리, 팔, 다리)을 올바르게 인식하도록 지도를 매핑하는 단계</li>
</ul>
</li>
<li>Any State<ul>
<li>현재 어떤 상태에 있든 즉시 특정 액션(공격, 피격)으로 이동하는 <mark>만능 통로</mark></li>
</ul>
</li>
<li>Has Exit Time<ul>
<li>체크하면 현재 애니메이션이 끝날 때까지 기다렸다가 이동하고, 해제하면 즉시 이동한다.</li>
</ul>
</li>
<li>Can Transition To Self<ul>
<li>공격 중에 다시 공격 신호를 받았을 때 처음부터 다시 재생할지 결정</li>
<li>Any State 활용 시 무한 루프 방지를 위해 반드시 해제</li>
</ul>
</li>
<li>Transition Duration<ul>
<li>두 동작이 섞이는 순간</li>
<li>반응 속도를 높이려면 이 값을 0.1 정도로 줄이기(보통 0.1~0.25가 적당)</li>
</ul>
</li>
<li>Transition Priority<ul>
<li>멈춤(Idle)과 걷기(Walking) 조건이 동시에 만족될 때, 어떤 화살표를 먼저 검사할지 결정하는 리스트 순서</li>
</ul>
</li>
</ul>
<hr>
<blockquote>
<h3 id="1-blend-tree">1. Blend Tree</h3>
</blockquote>
<ul>
<li>한 노드 안에 여러 클릭을 넣고 수치에 따라 실시간으로 적용시킴 (블렌딩)</li>
</ul>
<h3 id="parameter">Parameter</h3>
<ul>
<li>1D Blend Type: 주로 이동(속도)과 같은 카테고리로 제어할 때 사용<ul>
<li>Threshold (임계값): float형 수치로 조절해서 두 동작 사이 전환 가능</li>
</ul>
</li>
<li>2D Simple Directional (2D 단순 방향)<ul>
<li>상하좌우(위, 아래, 왼쪽, 오른쪽)와 같은 방향성 애니메이션</li>
<li>사용 사례: 4방향 혹은 8방향 걷기/달리기</li>
</ul>
</li>
<li>2D Freeform Directional (2D 자유 형식 방향)<ul>
<li>방향은 같지만 속도(걷기/달리기)가 다른 애니메이션을 혼합할 때 유용</li>
<li>사용 사례: 같은 방향으로의 걷기/달리기 속도 차이가 있는 경우</li>
</ul>
</li>
</ul>
<hr>
<blockquote>
<h3 id="2-avatar-mask">2. Avatar Mask</h3>
</blockquote>
<ul>
<li>애니메이션이 영향을 미칠 &#39;부위&#39; 를 선택하는 필터
<img src="https://velog.velcdn.com/images/23m-rft68/post/5a74c9d8-c34b-40a2-8316-387b443243ae/image.png" alt=""></li>
</ul>
<h3 id="2-1-실사용-예시">2-1. 실사용 예시</h3>
<p>[Base Layer: Idle, Move(Walk, Run)]
<img src="https://velog.velcdn.com/images/23m-rft68/post/7ee115d8-5856-465b-8c7b-6d014049cfd0/image.png" alt=""></p>
<p>[Shiled Layer: 다리 부분을 제외 -&gt; 방패막기와 방패밀치기 Animation]
<img src="blob:https://velog.io/9530737e-12e8-4f7b-89c2-07b775216765" alt=""></p>
<p>[Avator Mask: Base Layer 기반 -&gt; Upper Layer Override/Additive]
<img src="https://velog.velcdn.com/images/23m-rft68/post/ff405fd2-28f4-4a87-8ed0-aaf7009086c7/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL-260210] UGUI, MVC / MVP]]></title>
            <link>https://velog.io/@23m-rft68/TIL-260210-UGUI-MVC-MVP</link>
            <guid>https://velog.io/@23m-rft68/TIL-260210-UGUI-MVC-MVP</guid>
            <pubDate>Tue, 10 Feb 2026 09:09:35 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-배운-내용">오늘 배운 내용</h1>
<h2 id="--ugui">- UGUI</h2>
<h2 id="--mvc--mvp">- MVC / MVP</h2>
<hr>
<blockquote>
<h3 id="image--rawimage">Image &amp; RawImage</h3>
</blockquote>
<h3 id="image">Image</h3>
<p>Image Type (4가지)</p>
<ul>
<li>Simple: 이미지를 있는 그대로 출력(배경, 아이콘)</li>
<li>Sliced: 테두리는 유지하고 중심만 늘리는 방식(버튼)</li>
<li>Tiled: 이미지 (Center) 타일 형태로 반복.
-&gt; 이미지 늘릴때</li>
<li>Filled: 이미지 일부를 노출(체력바, 스킬 쿨타임)    <ul>
<li>Fill Amount(0~1)<ul>
<li>Radial 모드</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="imagesprite-vs-raw-imagetexture">Image(Sprite) VS Raw Image(Texture)</h4>
<p>Image</p>
<ul>
<li>버튼</li>
<li>배경</li>
<li>체력바</li>
<li>아이템</li>
<li>아이콘</li>
</ul>
<p>단점: Sprite 변환 과정이 필요(자원 소모가 상대적으로 있음)</p>
<p>Raw Image</p>
<ul>
<li>CCTV 화면</li>
<li>저격총 Scope</li>
<li>영상</li>
<li>미니맵</li>
</ul>
<p>단점: 각 텍스처당 Draw Call 발생</p>
<hr>
<blockquote>
<h3 id="slider">Slider</h3>
</blockquote>
<ul>
<li>Value 값 (0~1)</li>
</ul>
<h3 id="사용-사례">사용 사례</h3>
<p>[환경 설정]
<img src="https://velog.velcdn.com/images/23m-rft68/post/616e8591-810e-4b8e-8bbf-49fbb7711371/image.png" alt="">
[체력바 - 플레이어, 적, 보스 등등]
<img src="https://velog.velcdn.com/images/23m-rft68/post/c5df428c-e02d-4120-8024-02368963c1e1/image.png" alt="">
[과열기능 - 게임적 허용]</p>
<hr>
<blockquote>
<h3 id="scroll-view">Scroll View</h3>
</blockquote>
<ul>
<li>Content: 실제 아이템들이 담기는 도화지</li>
<li>Movement Type<ul>
<li>Elastic<ul>
<li>Clamped</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<blockquote>
<h3 id="textmeshpro-tmp">TextMeshPro (TMP)</h3>
</blockquote>
<h3 id="q--왜-text-대신-tmp를-사용하는가">Q . 왜 Text 대신 TMP를 사용하는가?</h3>
<ul>
<li>&quot;랜더링 방식에서 최적화가 일어났기 때문에&quot; 
(Unity6에서 기본적으로 사용중)</li>
</ul>
<hr>
<blockquote>
<h3 id="mvc--mvp">MVC / MVP</h3>
</blockquote>
<ul>
<li>게임 로직은 건들지 않고 UI만 갈아 끼우는 설계</li>
</ul>
<hr>
<h3 id="1-왜-ui와-로직을-분리해야-하나">1. 왜 UI와 로직을 분리해야 하나?</h3>
<pre><code class="language-csharp">using TMPro;
using UnityEngine;

public class Enemy : MonoBehaviour
{
    public int hp = 100;
    public TextMeshProUGUI hp Text; // UI와 강한 결합

    public void OnDamage(int damage)
    {
        hp -= damage;

        // 로직 스크립트 안에서 UI를 건든다 -&gt; UI와 강한 결합
        hpText.text = &quot;HP:&quot; + hp.ToString();

        if(hp &lt;= 0)
        {
            Debug.Log(&quot;Enemy 죽음...&quot;);
        }
    }
}</code></pre>
<ul>
<li>유지보수 지옥<ul>
<li>프로젝트 커질 시 추적 불가 (어딨는지 못 찾음)</li>
</ul>
</li>
</ul>
<hr>
<h3 id="2-mvc-vs-mvp">2. MVC vs MVP</h3>
<p><img src="https://velog.velcdn.com/images/23m-rft68/post/1d0e72a7-5aeb-4baf-9287-76c1b83db511/image.png" alt=""></p>
<ol>
<li><p>MVC</p>
<ul>
<li>사용자 입력이 Controller로 전달.</li>
<li>의존성: View가 Model을 직접 참조.</li>
</ul>
</li>
<li><p>MVP</p>
<ul>
<li>사용자의 입력이 View를 통해 들어와서 Presenter로 전달.</li>
<li>의존성: View와 Model 사이에 참조가 전혀 없음(의존 안함)</li>
</ul>
</li>
</ol>
<hr>
<h3 id="3-1-mvc-model---view---controller-예시">3-1. MVC (Model - view - Controller) 예시</h3>
<p>[Model - 데이터 관리]</p>
<pre><code class="language-csharp">public class PlayerModel_MVC
{
    public int hp = 100;
}</code></pre>
<p>[View - 화면에 출력 - Model 직접 참조중]</p>
<pre><code class="language-csharp">using UnityEngine;
using UnityEngine.UI;

public class PlayerView_MVC : MonoBehaviour
{
    public PlayerModel_MVC playerModel;
    public Slider hpSlider;

    public void UpdateView()
    {
        hpSlider.value = playerModel.hp / 100f;
    }
}</code></pre>
<p>[Controller - 입력 처리 및 Model(데이터) 수정]</p>
<pre><code class="language-csharp">using UnityEngine;

public class PlayerController_MVC : MonoBehaviour
{
    PlayerModel_MVC playerModel = new PlayerModel_MVC();
    public PlayerView_MVC playerView;

    public void OnDamage(int damage)
    {
        playerModel.hp -= damage; // Model(데이터) 수정
        playerView.UpdateView(); // View(UI - Slider) 갱신
    }
}</code></pre>
<hr>
<h3 id="3-2-같은-코드로-mvp-패턴-구현">3-2. 같은 코드로 MVP 패턴 구현</h3>
<p>[Model 파트 MVC와 동일]</p>
<p>[View - 오로지 그려주기만 한다]</p>
<pre><code class="language-csharp">using UnityEngine;
using UnityEngine.UI;

public class PlayerView_MVP : MonoBehaviour
{
    [serializeField] Slider slider;

    public void SetFillAmount(float ratio)
    {
        slider.value = ratio;
    }
}

// Model을 직접 참조하고 있지 않다.
// 데이터 가공도 하지 않는다.
// 오로지 그려주기만 한다.</code></pre>
<p>[Presenter - Model(데이터)와 View(화면) 중재]</p>
<pre><code class="language-csharp">using UnityEngine;

public class PlayerPresenter_MVP : MonoBehaviour
{
    PlayerModel_MVC model = new PlayerModel_MVC();
    [SerializeField] PlayerView_MVP playerview; // 조립할 대상

    public void TakeDamage(int damage)
    {
        model.hp -= damage;

        float ratio = model.hp / 100f;
        playerView.SetFillAmount(ratio)
    }
}</code></pre>
<hr>
<h3 id="4-mvp-패턴">4. MVP 패턴</h3>
<h4 id="역할">역할</h4>
<ul>
<li>Model<ul>
<li>데이터 관리(값만 가짐, 순수 C#)</li>
<li>MonoBehaviour 상속받지 않음</li>
</ul>
</li>
<li>View<ul>
<li>그리기만 하는 녀석 -&gt; UI 컴포넌트 수정/갱신</li>
<li>MonoBehaviour 상속받음</li>
</ul>
</li>
<li>Presenter<ul>
<li>Model(데이터)의 변화를 감지해서 View(화면)에 전달/명령내리는 대상</li>
</ul>
</li>
</ul>
<h4 id="사고방식">사고방식</h4>
<ul>
<li>Model: 어떤 데이터를 관리하지? (선언된 데이터)</li>
<li>View: 화면에 뭘 그리지?</li>
<li>Presenter: Model(데이터) 업데이트와 그려줄 View(화면)를 누가 중재/관리하나?</li>
</ul>
<hr>
<h3 id="5-실전-예제">5. 실전 예제</h3>
<p>1) Basic - 단일 연동 (1:1)
[model]</p>
<pre><code class="language-csharp">public class StatModel
{
    public float hp = 100f;
    public float maxHP = 100f;
    public float GetHpRatio() =&gt; hp / maxHP;
}</code></pre>
<p>[View]</p>
<pre><code class="language-csharp">using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class SliderBarView : MonoBehaviour
{
    public Slider slider;
    public void SetValue(float ratio) =&gt; slider.value = ratio;
}

public class TextPercentView : MonoBehaviour
{
    public TMP_Text hpText;
    public void SetProgress(float ratio)
    {
        hpText.text = $&quot;HP; {ratio * 100}%&quot;;
    }
}</code></pre>
<p>[presenter]</p>
<pre><code class="language-csharp">using UnityEngine;

public class StastPresenter : MonoBehaviour
{
    StatModel model = new StatModel();
    [SerializeField] SliderBarView viewA;
    [SerializeField] TextPercentView viewB;

    public void OnDamage(float damage)
    {
        model.hp -= damage;
        viewA.SetValue(model.GetHpRatio());
        viewB.SetProgress(model.GetHpRatio());
    }
}</code></pre>
<p>2) Advanced - 다중 연동 (1:N)
[Model]</p>
<pre><code class="language-csharp">public class ScoreModel
{
    int score;

    public event System.Action&lt;int&gt; OnScoreChanged; // 전광판

    public void AddScore(int amount)
    {
        score += amount;
        OnScoreChanged?.Invoke(score);
    }
}</code></pre>
<p>[Presenter]</p>
<pre><code class="language-csharp">using UnityEngine;

public class ScorePresenter : MonoBehaviour
{
    [SerializeField] ScoreView scoreView;
    [SerializeField] TargetView targetView;
    [SerializeField] RankingView rankingView;
    [SerializeField] AchievementPopupView popupView;

    ScoreModel model = new ScoreModel();

    void OnEnable()
    {
        model.OnScoreChanged += scoreView.UpdateScoreText;
        model.OnScoreChanged += targetView.UpdateTargetText;
        model.OnScoreChanged += CheckAchievement;  // Q. 왜 View쪽이 아닌 여기에 구현할까?  
    }

    void OnDisable()
    {
        // 구독 해지 안해준다면??  
    }

    void CheckAchievement(int score)
    {
        if(score &gt;= 100) popupView.Show(&quot;팝업 떳습니다&quot;);
    }
}</code></pre>
<h3 id="6-안전한-구독-onenable--ondisable">6. 안전한 구독: OnEnable / OnDisable</h3>
<ul>
<li>OnEnable (구독 시작)</li>
<li>OnDisable (구독 해제) -&gt; 메모리 누수/죽은 참조 호출 방지가 핵심</li>
</ul>
<p>📢중요 ) 밥먹듯이 습관적으로 해주기</p>
<hr>
<h3 id="7-정리">7. 정리</h3>
<ul>
<li>MVC: 프로젝트가 커지면, View와 Model이 꼬이는(참조가 많이 일어나는)스파게티의 위험이 있다.</li>
<li>MVP: Presenter가 Model과 View를 중재해서 깔끔하게 관리 -&gt; 대규모 프로젝트로 가도 문제가 발생할 확률이 적다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL-260209] LayerMask / Render Texture / UI 이해와 최적화]]></title>
            <link>https://velog.io/@23m-rft68/TIL-260209-LayerMask-Render-Texture-UI-%EC%9D%B4%ED%95%B4%EC%99%80-%EC%B5%9C%EC%A0%81%ED%99%94</link>
            <guid>https://velog.io/@23m-rft68/TIL-260209-LayerMask-Render-Texture-UI-%EC%9D%B4%ED%95%B4%EC%99%80-%EC%B5%9C%EC%A0%81%ED%99%94</guid>
            <pubDate>Mon, 09 Feb 2026 10:23:21 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-배운-내용">오늘 배운 내용</h1>
<h2 id="--layer-mask">- Layer Mask</h2>
<h2 id="--render-texture">- Render Texture</h2>
<h2 id="--ui-이해와-최적화">- UI 이해와 최적화</h2>
<hr>
<blockquote>
<h3 id="layermask">LayerMask</h3>
</blockquote>
<ul>
<li>레이어 마스크는 태그와 비슷하게 오브젝트들을 분류하여 관리할 수 있다.</li>
</ul>
<hr>
<h3 id="--layermask-함수-종류">- LayerMask 함수 종류</h3>
<ol>
<li>LayerMask.GetMask
레이어 이름으로 묶음을 생성하는 함수 Enemy 가 8번 레이어(Layer)<pre><code class="language-csharp">LayerMask.GetMask(&quot;Enemy&quot;, &quot;Obstacle&quot;)
// Enemy 가 8번 레이어(Layer)라면?
// 1 &lt;&lt; 8 (값 256)</code></pre>
</li>
<li>LayerMask.NameToLayer 레이어의 인덱스(int)를 반환<pre><code class="language-csharp">LayerMask.NameToLayer(&quot;Enemy&quot;);
// int 반환값 = 8</code></pre>
</li>
<li>LayerMask.LayerToName 레이어의 이름(string)을 반환<pre><code class="language-csharp">LayerMask.LayerToName(8);</code></pre>
</li>
<li>LayerMask.Value 비트마스크 값을 나타냄. 주로 비트 연산 수행<pre><code class="language-csharp">int bitMask = enemyLayer.value | obstacleLayer.value; (OR 연산)</code></pre>
</li>
</ol>
<hr>
<h3 id="--비트-연산의-원리">- 비트 연산의 원리</h3>
<ul>
<li>1 &lt;&lt; n: n번 레이어의 스위치를 켠다(ON)</li>
<li>| (OR): 필터에 레이어를 추가한다.</li>
<li>&amp; (AND): 이 오브젝트가 포함되어 있다 (필터 역할)</li>
<li><strong>~ (NOT)</strong>: 지정한 레이어 제외한 나머지 다 선택<pre><code class="language-csharp">layerMask = 7;
// 이진수 111 -&gt; 0,1,2</code></pre>
layerMask = 7;<pre><code class="language-csharp">0000 0000 0000 0000 0000 0000 0000 0000 0111</code></pre>
layerMask = 1 &lt;&lt; 7;<pre><code class="language-csharp">0000 0000 0000 0000 0000 0000 0000 1000 0000</code></pre>
</li>
</ul>
<hr>
<h3 id="--특정-레이어-포함-여부-체크-and">- 특정 레이어 포함 여부 체크(&amp; AND)</h3>
<pre><code class="language-csharp">public static class Extensions
{
    public static bool Contains(this LayerMask mask, int Layer)
    {
        return (mask.value &amp; (1 &lt;&lt; layer)) != 0;
    }

    public static bool Contains(this LayerMask mask, Gameobject obj)
    {
        return (mask.value &amp; (1 &lt;&lt; obj.layer)) != 0;
    }
}
if (mask.Contains(obj, layer)) {}</code></pre>
<p>시나리오 A. Monster/NPC를 때렸을 때, 공격 가능 여부 체크</p>
<pre><code class="language-csharp">(this LayerMask mask, GameObject obj)
if(mask.Contains(Enemy 마스크, 몬스터/NPC obj)) {//공격하기}</code></pre>
<pre><code>Enemy는 8번 레이어</code></pre><p>mask 0000 0000 0000 0000 0000 0000 0001 0000 0000</p>
<p>1&lt;&lt; NPC 0000 0000 0000 0000 0000 0000 0000 1000 0000 &amp;
0000 0000 0000 0000 0000 0000 0000 0000 0000 false (공격 무시)</p>
<hr>
<p>~ (NOT) 연산자</p>
<pre><code class="language-csharp">~(1 &lt;&lt; PlayerLayer)
// UI 레이어까지 포함</code></pre>
<hr>
<h4 id="q--왜-비트마스크-방식을-사용할까">Q . 왜 비트마스크 방식을 사용할까?</h4>
<pre><code class="language-csharp">if(target == &quot;&quot; || target == &quot;&quot; || target == &quot;&quot; || .....)

if(mask.Contains(target, layer)) {}</code></pre>
<hr>
<blockquote>
<h3 id="render-texture">Render Texture</h3>
</blockquote>
<ul>
<li>카메라를 이용하여 화면에 이미지 영역을 지정해 이미지에 만들어진 카메라 뷰를 볼 수 있는 방법이다.</li>
</ul>
<hr>
<h3 id="--활용-방법">- 활용 방법</h3>
<ul>
<li>CCTV </li>
<li>저격총 Scope</li>
<li>미니맵등 활용</li>
</ul>
<hr>
<h3 id="--흐름-도식화">- 흐름 도식화</h3>
<pre><code class="language-csharp">[Sub Camera] (촬영)
    ↓ Target Texture 설정
[Render Texture] (저장소/필름)
    ↓ 에셋 참조
[Material / UI -&gt; RawImage] (출력/액자)</code></pre>
<hr>
<blockquote>
<h3 id="ui-이해-최적화">UI 이해 최적화</h3>
</blockquote>
<h3 id="1-ui의-기본-좌표-recttransform">1. UI의 기본 좌표: RectTransform</h3>
<ul>
<li>Anchor: 부모 해상도가 변할 때, 부모기준으로 상대위치를 결정</li>
<li>Pivot: 내가 회전하거나 커진 때, 어디를 기준으로 움직일 것인가 (자기 기준)</li>
</ul>
<hr>
<h3 id="2-canvas-ui-처리-최소-단위">2. Canvas UI 처리 최소 단위</h3>
<p>2-1. Canvas Render Mode</p>
<ul>
<li>Screen Space-Overlay 카메라와 상관없이 화면 가장 위 레이어에 그림</li>
<li>Screen Space-Camera 특정 카메라 앞에 일정한 거리에 배치. </li>
<li><blockquote>
<p>연출용 UI, 파티클이 섞인 UI</p>
</blockquote>
</li>
<li>World Space 씬 내 3D 오브젝트처럼 활용하는 UI </li>
<li><blockquote>
<p>오브젝트 체력, 데미지 등등
2-2. Canvas Scaler</p>
</blockquote>
</li>
<li>Constant pixel Size 해상도가 바뀌어도 UI가 사용하는 픽셀 수를 그대로 유지</li>
<li>Scale With Screen Size -&gt; 모바일 게임 표준</li>
<li>Constant Physical Size 화면 해상도와 상관없이 cm/inch 크기를 유지하려고함.</li>
</ul>
<hr>
<h3 id="주의-컴포넌트">주의 컴포넌트</h3>
<ol>
<li>Layout Group</li>
<li>Text 대안 -&gt; Text Mesh Pro 사용하는 이유?</li>
</ol>
<h2 id="--ui가-변화하는-상황에-text에-비해서-최적화-되어-있다"> -&gt; UI가 변화하는 상황에 Text에 비해서 최적화 되어 있다.</h2>
<h3 id="profiler-에서-ui-최적화-잡는법">Profiler 에서 UI 최적화 잡는법</h3>
<ul>
<li>Layout(파란색) -&gt; UI 위치/크기 계산하는 시간</li>
<li>Render(노란색) -&gt; 실제 메쉬 생성 시간</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL-260206] 시네머신]]></title>
            <link>https://velog.io/@23m-rft68/TIL-260206-%EC%8B%9C%EB%84%A4%EB%A8%B8%EC%8B%A0</link>
            <guid>https://velog.io/@23m-rft68/TIL-260206-%EC%8B%9C%EB%84%A4%EB%A8%B8%EC%8B%A0</guid>
            <pubDate>Fri, 06 Feb 2026 06:33:52 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-배운-내용">오늘 배운 내용</h1>
<h2 id="--시네머신">- 시네머신</h2>
<hr>
<blockquote>
<h3 id="시네머신">시네머신</h3>
</blockquote>
<ul>
<li>카메라 선택과 전환을 자동화한 기능이다.</li>
</ul>
<hr>
<blockquote>
<h3 id="시네머신의-이점">시네머신의 이점</h3>
</blockquote>
<ol>
<li>상황별 연출을 코드 없이 구현 가능</li>
<li>플레이어 이동이나 상태 변화에따라 카메라에 자연스럽게 적용 가능</li>
</ol>
<hr>
<blockquote>
<h3 id="카메라-추적-코드">카메라 추적 코드</h3>
</blockquote>
<pre><code class="language-csharp">void LateUpdate()
{
    Camera.main.transform.position = player.position + offset;

    Camera.main.transform.LookAt(player)
}</code></pre>
<h3 id="q-왜-이-방식을-잘-사용하지-않을까">Q. 왜 이 방식을 잘 사용하지 않을까?</h3>
<ol>
<li>하드코딩 로직</li>
<li>예외 처리 지옥</li>
<li>상태 전환 불가능</li>
</ol>
<hr>
<blockquote>
<h3 id="q-시네머신을-배우는-이유">Q. 시네머신을 배우는 이유</h3>
</blockquote>
<ul>
<li>카메라에 어떤 규칙을 부여해서 활용하는 시스템/기능이다.</li>
<li>그렇지않으면 코드로 다 짜야한다.</li>
</ul>
<ol>
<li>카메라 로직의 분리</li>
<li>수학적 지식이 크게 요구되지않음</li>
<li>카메라 상태 관리 가능</li>
</ol>
<hr>
<blockquote>
<h3 id="시네머신-구성">시네머신 구성</h3>
</blockquote>
<ol>
<li>Brain (브레인)</li>
<li>Virtual (브이캠, VC)</li>
</ol>
<hr>
<blockquote>
<h3 id="1-cinemachine-brain-감독">1. Cinemachine Brain (감독)</h3>
</blockquote>
<ul>
<li><p>어떤 가상 카메라(Virtual Camera)를 이용할지 결정.</p>
</li>
<li><p>블렌딩(전환 효과) 방식을 결정함.</p>
</li>
<li><p>실제 카메라는 Brain만 보고, Brain은 가상 카메라(Virtual Camera, 브이캠) 중 하나를 고름.</p>
</li>
</ul>
<hr>
<blockquote>
<h3 id="2-virtual-camera">2. Virtual Camera</h3>
</blockquote>
<ul>
<li>VC, 브이캠이라고도 불림</li>
<li>누구를 따라갈것인가?(Follow)</li>
<li>어디를 볼것인가?(Look At)</li>
<li>어느 거리/ 각도 / 부드러움 규칙을 설정</li>
</ul>
<p>[계층구조]</p>
<pre><code class="language-csharp">Main Camera (실제 카메라)
 ㄴ Cinemachine Brain (결정 및 전환)
     ㄴ Virtual Camera A (상태 1: 평상시) 
     ㄴ Virtual Camera B (상태 2: 조준 시)
     ㄴ Virtual Camera C (상태 3: 이벤트 컷신)</code></pre>
<h3 id="브이캠-속성">브이캠 속성</h3>
<h4 id="follow--lookat대상-설정">Follow &amp; LookAt(대상 설정)</h4>
<ul>
<li>Follow : 어떤 대상의 몸체(Body)를 매칭</li>
<li>LookAt : 기획에 따라 다르지만 따로 빈 게임 오브젝트로 빼서 설정함</li>
</ul>
<h4 id="브이캠-속성-핵심">브이캠 속성 핵심</h4>
<ul>
<li>Damping: 이동을 부드럽게</li>
<li>Dead/Soft Zone: 회전 안정성</li>
<li>Priority: 브이캠 간 전환을 제어</li>
</ul>
<hr>
<blockquote>
<h3 id="3-blend-list-camera">3. Blend List Camera</h3>
</blockquote>
<ul>
<li>사례<ul>
<li>인트로 연출</li>
<li>컷신 시작</li>
<li>보스 등장</li>
</ul>
</li>
<li>특징<ul>
<li>여러 브이캠을 리스트로 묶음</li>
<li><mark>연출용 카메라</mark></li>
</ul>
</li>
</ul>
<hr>
<blockquote>
<h3 id="4-clear-shot-camera-시야-확보-전문가">4. Clear shot Camera (시야 확보 전문가)</h3>
</blockquote>
<ul>
<li>사례<ul>
<li>실내 던전</li>
<li>좁은 복도</li>
<li>장애물(기둥, 벽) 많은 환경</li>
<li><mark>시야 확보 전문가</mark></li>
</ul>
</li>
</ul>
<hr>
<blockquote>
<h3 id="5-dolly-camera">5. Dolly Camera</h3>
</blockquote>
<ul>
<li>사례<ul>
<li>특정 구간 연출</li>
<li>추적할 때</li>
</ul>
</li>
<li>구성 &amp; 특징<ul>
<li>Dolly Track (경로)</li>
<li>Dolly Camera (트랙 따라 이동)</li>
<li><code>연출용 카메라</code> -&gt; <code>정서적인 몰입감</code>과 <code>시각적 역동성</code>에 특화된 카메라</li>
</ul>
</li>
</ul>
<hr>
<blockquote>
<h3 id="6-free-look-camera3인칭-조작의-표준">6. Free Look Camera(3인칭 조작의 표준)</h3>
</blockquote>
<ul>
<li>사례<ul>
<li>TPS</li>
<li>오픈 월드</li>
<li>액션 게임</li>
</ul>
</li>
<li>특징 <ul>
<li>3인칭(TPS)조작 카메라의 표준</li>
<li>사용자 주도 하에 회전 가능/제어</li>
<li>자동 보간, 구도 유지 -&gt; 구현하려면 수학적 지식 요구함</li>
</ul>
</li>
</ul>
<hr>
<blockquote>
<h3 id="7-target-group">7. Target Group</h3>
</blockquote>
<ul>
<li>사례<ul>
<li>보스 + 플레이어</li>
<li>파티 플레이</li>
</ul>
</li>
<li>특징<ul>
<li>여러 Target을 하나의 그룹으로 묶음</li>
<li>거리, 비율 자동 조절</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL-260205] URP]]></title>
            <link>https://velog.io/@23m-rft68/TIL-260205-URP</link>
            <guid>https://velog.io/@23m-rft68/TIL-260205-URP</guid>
            <pubDate>Thu, 05 Feb 2026 07:55:24 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-배운-내용">오늘 배운 내용</h1>
<h2 id="--urp">- URP</h2>
<hr>
<blockquote>
<h3 id="urpuniversal-unity-pipeline">URP(Universal Unity Pipeline)</h3>
</blockquote>
<ul>
<li>게임이 화면에 그려지는 과정 (CPU -&gt; GPU -&gt; 화면)</li>
</ul>
<hr>
<h2 id="1-정리">1) 정리</h2>
<blockquote>
<h3 id="cpu--이-3d-모델들을-이-카메라-시점에서-그려줘명령-데이터-전달">CPU : 이 3D 모델들을 이 카메라 시점에서 그려줘(명령, 데이터 전달)</h3>
<h3 id="gpu--알겠어">GPU : 알겠어.</h3>
</blockquote>
<ol>
<li>3D를 2D로 변환(Vertex)하고,</li>
<li>픽셀로 쪼개서(Raterization),</li>
<li>색을 채워서(Pixel/Fragment)</li>
<li>화면에 보여줄게</li>
</ol>
<h2 id="2-gpu관점에서-rp를-처리하는-최소-단위">2) GPU관점에서 RP를 처리하는 최소 단위</h2>
<h3 id="2-1-vertex점">2-1) Vertex(점)</h3>
<ul>
<li>3D 공간상의 <code>한 점</code>을 의미한다. 좌표(x,y,z)로 구성</li>
</ul>
<h3 id="2-2-polygon면-다각형">2-2) Polygon(면, 다각형)</h3>
<ul>
<li>Vertex(점)들이 모여 만들어지는 최소의 면 단위</li>
</ul>
<h3 id="2-3-mesh모델">2-3) Mesh(모델)</h3>
<h4 id="mesh란">Mesh란?</h4>
<ul>
<li>면(Polygon)들의 집합</li>
</ul>
<blockquote>
<h3 id="흐름">흐름</h3>
</blockquote>
<h2 id="점vertex---면polygon---메쉬mesh">점(Vertex) -&gt; 면(Polygon) -&gt; 메쉬(Mesh)</h2>
<ul>
<li><p>GPU가 점의 위치를 우선적으로 계산</p>
</li>
<li><p>그점들을 이어서 Polygon이라는 면을 만들어서 모델을 이루고,</p>
</li>
<li><p>최종적으로 Pixel에 색을 채워 넣는다.</p>
</li>
</ul>
<blockquote>
<h3 id="정리">정리</h3>
</blockquote>
<ul>
<li>Mesh Filter: 어떤 모양(Mesh)을 쓸 것인가?</li>
<li>Mesh Renderer: 그 모양을 화면에 &#39;그리는&#39; 담당자. (Material 참조)</li>
<li>Material: 어떤 <code>색</code>과 <code>질감</code></li>
</ul>
<h3 id="3-1-1-uv-mapping">3-1-1 UV Mapping</h3>
<ul>
<li>3D 표면의 위치(점/면)와 2D 텍스처의 위치(UV 좌표)를 연결하는 과정
2D 이미지를 3D 물체 표면에 정확히 붙이는 방법</li>
</ul>
<h3 id="3-1-2-auto-mapping-tools">3-1-2 Auto Mapping Tools</h3>
<ul>
<li>블랜더(blender)</li>
<li>맥스(3max)</li>
<li>마야(Maya)</li>
</ul>
<h3 id="3-2-material">3-2 Material</h3>
<ul>
<li>게임 화면에 보이는 <code>질감</code>을 담당한다</li>
<li>색상, 질감, 빛, 투명도 등 정보를 포함한다.</li>
</ul>
<h3 id="3-3-shader">3-3 Shader</h3>
<ul>
<li>Meterial이 가진 Texture 혹은 색상 정보를 조합해서 화면에 최종적으로 질감을 입히는 역할</li>
<li>Shader(틀/설계도): 어떤 데이터를 담을 <code>빈 칸(속성)</code>을 가진다.</li>
</ul>
<hr>
<blockquote>
<h2 id="그래픽-처리-순서-게임-엔진">그래픽 처리 순서 (게임 엔진)</h2>
</blockquote>
<h2 id="4가지-거시적">4가지 (거시적)</h2>
<ol>
<li>CPU 명령 (Draw-Call)<ul>
<li>CPU가 무엇을 그릴지 정해서 명령을 내리면,</li>
</ul>
</li>
<li>Vertex Shader<ul>
<li>GPU가 그 물체의 `점(Vertex)을 화면 위치에 맞게 옮김</li>
</ul>
</li>
<li>Rasterizer<ul>
<li>모니터 눈금에 맞춰 <code>픽셀</code>로 쪼겜</li>
</ul>
</li>
<li>Pixel/Fragment Shader<ul>
<li>마지막으로 그 칸들에 색을 채운다.</li>
</ul>
</li>
</ol>
<h2 id="8가지-미시적">8가지 (미시적)</h2>
<h4 id="13단계">1~3단계</h4>
<ol>
<li><p>CPU &amp; Draw-Call</p>
<ul>
<li>CPU -&gt; GPU 그려라! 라고 명령하는 단계</li>
<li>메쉬(Mesh), 메테리얼(Material)</li>
</ul>
</li>
<li><p>Vertex Shader (정점 연산)</p>
<ul>
<li>3D 공간에 있는 어떤 메쉬/모델을 2D화면에 위치 시키는 것</li>
</ul>
</li>
<li><p>Culling</p>
<ul>
<li>불필요한 영역을 계산에서 지워버린다.<h4 id="3가지">3가지</h4>
[Default로 제공]</li>
<li><code>프로스텀 컬링(CPU)</code> : 카메라 시야 아예 밖에 있는가? (시야 밖 통째로 버림)</li>
<li><code>백페이스 컬링(GPU)</code> : 물체 면의 방향이 카메라 반대편(뒷면)을 보고있는가? (뒷면 버림)</li>
</ul>
<p>[직접 설정]</p>
<ul>
<li><code>오클루전 컬링(CPU/GPU)</code> : 앞에 있는 물체에 완전히 가려졌는가?(가려진 부분 버림)</li>
</ul>
</li>
</ol>
<h4 id="45단계-비주얼-담당--색-칠하기">4~5단계 (비주얼 담당 = 색 칠하기)</h4>
<ol start="4">
<li><p>Rasterizer</p>
<ul>
<li>출력될 <code>픽셀 조각</code>들로 쪼개는 과정</li>
<li>이 <code>계단 현상(Aliasing)</code>이 발생</li>
<li>추후에 <code>Anti-Aliasing</code> 개념까지 들어감.</li>
</ul>
</li>
<li><p>Pixel/Fragment Shader (색상과 질감)</p>
<ul>
<li>실제 색을 입히는 단계</li>
<li>Texture하고 그림자 영역이 여기서 처리됨</li>
</ul>
<h4 id="67단계">6~7단계</h4>
</li>
<li><p>Depth Test(Z-Test)</p>
<ul>
<li>그려지는 우선순위 = 오브젝트의 앞뒤 판별</li>
<li><code>Z-Buffer(깊이 지도)</code><ul>
<li>새로 그릴 픽셀이 기록된 값보다 뒤에 있으면 계산을 취소한다.</li>
</ul>
</li>
</ul>
</li>
<li><p>Blending</p>
<ul>
<li>배경하고 어떻게 섞일것인가?</li>
<li>앞뒤 판별이 끝난 후, 배경색+현재 픽셀 합성</li>
</ul>
</li>
</ol>
<ul>
<li><p>불투명</p>
</li>
<li><p>반투명</p>
<h4 id="q-불투명-객체끼리-겹쳐있다면">Q. 불투명 객체끼리 겹쳐있다면?</h4>
<ul>
<li>Front-to-Back</li>
<li>Z-Write ON</li>
</ul>
<h4 id="q-불투명과-투명-객체끼리-겹쳤다면">Q. 불투명과 투명 객체끼리 겹쳤다면?</h4>
<ul>
<li>Back-to-Front</li>
<li>Z-Write OFF</li>
</ul>
<p>8단계</p>
</li>
</ul>
<ol start="8">
<li><p>Post-Processing</p>
<ul>
<li><code>Bloom</code></li>
<li><code>Color Gradient</code></li>
<li><code>Anti-Aliasing</code></li>
</ul>
</li>
</ol>
<hr>
<blockquote>
<h2 id="rp를-이해하기위한-소스-개념-이해하기">RP를 이해하기위한 소스 개념 이해하기</h2>
</blockquote>
<h3 id="rp-일련과정-이해를-위한-소스">RP 일련과정 이해를 위한 소스</h3>
<ul>
<li><p>Vertex(점)</p>
</li>
<li><p>Polygon(면)</p>
</li>
<li><p>Mesh(모델)</p>
</li>
<li><p>Texture (+UV-Mapping)</p>
</li>
<li><p>Material</p>
</li>
<li><p>Shader</p>
</li>
</ul>
<h3 id="그래픽-처리-일련-과정">그래픽 처리 일련 과정</h3>
<ul>
<li>1~8단계 키워드 기억하기</li>
</ul>
<h3 id="unity가-가지고-가는-rp-이해하기-forward">Unity가 가지고 가는 RP 이해하기 (Forward)</h3>
<p>1) Built-in Pipeline (Legacy)
    - 개발자가 내부 구조를 수정할 수 없음
    - 유니티에서 제공해주는 옵션 조정만 가능</p>
<p>2) SRP (Scriptable-Render-Pipeline)
-&gt; 기반 템플릿 URP/HDRP
    - Built-in 한계
    - SRP 초기: C#, HLSL 언어(2018)
    - SRP 기반 템플릿 -&gt; URP/HDRP(2019)</p>
<h3 id="q-urp의-장점은">Q. URP의 장점은?</h3>
<ul>
<li>SRP Batcher (드로우 콜 최적화)</li>
<li>Forward+</li>
<li>GPU Resident Drawer</li>
</ul>
<h2 id="1-forward-render-pipeline">1) Forward Render Pipeline</h2>
<ul>
<li>오브젝트를 그리면서 조명을 그때그때 계산함</li>
</ul>
<h2 id="2-deffered-render-pipeline">2) Deffered Render Pipeline</h2>
<ul>
<li>먼저 화면에 필요한 정보들을 저장<ul>
<li>위치</li>
<li>노멀</li>
<li>메테리얼</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL-260204] Team Project - 발표 및 시연회]]></title>
            <link>https://velog.io/@23m-rft68/TIL-260204</link>
            <guid>https://velog.io/@23m-rft68/TIL-260204</guid>
            <pubDate>Wed, 04 Feb 2026 08:57:25 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-발표-및-시연">오늘 발표 및 시연</h1>
<hr>
<blockquote>
<h3 id="발표">발표</h3>
</blockquote>
<ul>
<li>각팀의 게임에 대한 발표를 듣고 각각의 게임의 구현된 코드와 사용된 로직이나 기법을 알게되었고, QnA 시간을 통해 서로의 게임에서 궁금한점을 물어보는 시간을 가졌다.</li>
</ul>
<blockquote>
<h3 id="시연회">시연회</h3>
</blockquote>
<p><img src="https://velog.velcdn.com/images/23m-rft68/post/af818e65-4f3c-4ed5-84ff-0208ac0f8b16/image.png" alt="">
<img src="https://velog.velcdn.com/images/23m-rft68/post/0b524ea8-fcdc-4c74-8ea4-2b95fac9ebf5/image.png" alt=""></p>
<h4 id="에셋-저작권으로-인해-게임-영상이나-사진은-올리지-못했습니다"><del>(에셋 저작권으로 인해 게임 영상이나 사진은 올리지 못했습니다...)</del></h4>
<hr>
<blockquote>
<h3 id="느낀점">느낀점</h3>
</blockquote>
<ul>
<li>어제 갑작스럽게 기획반에서 개발팀 게임을 시연하고 싶다고해서 오늘 시연회는 기획팀도 참가하여 우리반이 만든 게임을 해보고 방명록을 남겨주셨다. 생각보다 많은 기획자분들과 같은반 개발팀들이 우리팀의 게임을 즐겨주셨고, <code>&quot;내가 만든 게임을 누군가가 플레이 해준다는 것&quot;</code>이 얼마나 뿌듯하고 기분좋은지 알게되었으며, 편의성 관련 팁이나 조언을 주시는 분들의 의견 또한 앞으로 어떤 방식으로 게임을 만들때 더 생각 해보면 좋을지에 대해서 깨닫게 되는 시간이 되었던것같다.</li>
<li>짧은 기간이었지만, 완성도 높은 게임을 만들어준 우리 팀원들에게 엄청나게 감사했고, 고생 많이해줘서 고마웠다.</li>
<li>프로젝트가 하나 끝나고 팀 디코방에서 후일담을 나누면서 헤어질때 이대로 끝나는게 약간 아쉽다는 느낌을 많이 받았다.</li>
</ul>
<hr>
<blockquote>
<h3 id="팀프로젝트를-마치며">팀프로젝트를 마치며..</h3>
</blockquote>
<ul>
<li>그동안 프로젝트를 하냐고 정신없이 코드를 생각하고, 밤을 새면서 고민하다가 기술블로그에 대해서 완전히 깜빡하고있었다! 그래서 오늘 프로젝트가 끝나서 한주간 밀렸던 TIL을 내가 한주동안 프로젝트에서 했던 담당파트와 담당로직, 회고와 같은 내용으로 쓰게되었다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL-260203] Team Project - Day 7]]></title>
            <link>https://velog.io/@23m-rft68/TIL-260203</link>
            <guid>https://velog.io/@23m-rft68/TIL-260203</guid>
            <pubDate>Wed, 04 Feb 2026 08:56:26 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-진행한-내용">오늘 진행한 내용</h1>
<h2 id="--빌드를-뽑고-직접-플레이">- 빌드를 뽑고 직접 플레이</h2>
<h2 id="--프로젝트-작품-설명-ppt-작성">- 프로젝트 작품 설명 PPT 작성</h2>
<hr>
<blockquote>
<h3 id="빌드-뽑고-직접-플레이">빌드 뽑고 직접 플레이</h3>
</blockquote>
<ul>
<li>오늘은 우리가 한 주 동안 만든 게임을 깃에서 병합하고 메인까지 병합 작업을 한 뒤 빌드를 뽑아내서 직접 플레이하며, 게임의 난이도와 버그가 있는지 테스트를 진행해보았다.</li>
<li>플레이하면서 발견된 버그는 몹들이 죽었을때 몬스터의 시체가 유령이 되어 계속 남아있는 버그와 우리가 직접 만든 맵이 아닌 에셋을 활용한 맵이라 그런지 계단부분에서 미끄러지는 현상과 걸림 현상이 발견되었다.</li>
</ul>
<blockquote>
<h3 id="ppt-작성">PPT 작성</h3>
</blockquote>
<ul>
<li>일단 우리가 지금까지 만든 게임의 설명, 사용한 주요 코드, 다른사람들도 알았으면하는 코드, 시연 영상, 회고등을 적어서 내일 있을 팀프로젝트 발표에 사용하기 위해 PPT로 발표자료를 만들었다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL-260202] Team Project - Day 6]]></title>
            <link>https://velog.io/@23m-rft68/TIL-260201</link>
            <guid>https://velog.io/@23m-rft68/TIL-260201</guid>
            <pubDate>Wed, 04 Feb 2026 08:55:49 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-내가-맡은-파트">오늘 내가 맡은 파트</h1>
<h2 id="--esp-manager">- ESP Manager</h2>
<ul>
<li>몬스터 위치 스캔 기능 (ESP)</li>
</ul>
<hr>
<blockquote>
<h3 id="내가-맡은-파트">내가 맡은 파트</h3>
</blockquote>
<ul>
<li>우리가 이번에 사용하는 맵이 생각보다 넓기 때문에 남은 몬스터가 어디있는지 알아내서 편의성을 높혀주자는 이야기가 나와서 플레이어의 스킬로 스캔기능을 넣어주기로 했다. </li>
</ul>
<hr>
<blockquote>
<h3 id="데일리-스크럼">데일리 스크럼</h3>
</blockquote>
<h3 id="🌞-오늘-할-일-today">🌞 오늘 할 일 (Today)</h3>
<ul>
<li>몬스터 위치 스캔 기능 (ESP)</li>
</ul>
<hr>
<h3 id="🚧-현재-문제점--고민">🚧 현재 문제점 / 고민</h3>
<ul>
<li>몬스터가 한 종류만 아웃라인이 그려지고 다른 종류의 몬스터는 아웃라인이 그려지지 않는 현상이 있어서 어떻게 고쳐야할지 모르겠다.</li>
</ul>
<hr>
<h3 id="💬-기타-메모">💬 기타 메모</h3>
<ul>
<li>아웃라인을 그려주는 <code>Quick Outline</code> 에셋을 사용하여, 맵 어디있던 아웃라인을 그려줘서 위치를 찾아주는것이 가능한걸 알아냈으나, 몬스터 2종류중 1종류만 보이는 현상을 어떻게 고쳐야할지 가늠이 가지 않았는데 팀원의 도움으로 아웃라인 로직에서 좀더 코드를 수정할 수 있었고, 몬스터 프리펩에서 모델의 Write/Read 가 꺼져있어서 아웃라인이 mesh를 읽어 오지 못해서 일어난 현상이란것을 알게되었다.</li>
</ul>
<hr>
<blockquote>
<h3 id="일일-회고">일일 회고</h3>
</blockquote>
<ul>
<li>오늘은 적들의 위치를 찾아내는 ESP기능을 구현했는데 나혼자 구현을 못해서 팀원들의 도움을 통해 결국 구현해내서 방법도 알게되어 배운점이 많은것같다</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL-260130] Team Project - Day 5]]></title>
            <link>https://velog.io/@23m-rft68/TIL-260130</link>
            <guid>https://velog.io/@23m-rft68/TIL-260130</guid>
            <pubDate>Fri, 30 Jan 2026 00:38:51 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-내가-맡은-파트">오늘 내가 맡은 파트</h1>
<h2 id="--damage-text-ui">- Damage Text UI</h2>
<ul>
<li>몬스터 피격시 피해량 UI</li>
</ul>
<hr>
<blockquote>
<h3 id="내가-맡은-파트">내가 맡은 파트</h3>
</blockquote>
<ul>
<li>타격감을 주기위해서 몬스터에게 총을 쏴서 피격되었을때 몬스터에서 피해량을 띄워주는 UI를 넣어서 </li>
</ul>
<hr>
<blockquote>
<h3 id="데일리-스크럼">데일리 스크럼</h3>
</blockquote>
<h3 id="🌞-오늘-할-일-today">🌞 오늘 할 일 (Today)</h3>
<ul>
<li>몬스터 피격시 피해량 UI</li>
</ul>
<hr>
<h3 id="🚧-현재-문제점--고민">🚧 현재 문제점 / 고민</h3>
<ul>
<li>몬스터 피격 피해량을 띄워주는 UI는 만들었는데 어떻게 이어줘야하는지 모르겠따..</li>
</ul>
<hr>
<h3 id="💬-기타-메모">💬 기타 메모</h3>
<ul>
<li>몬스터 피격 시 피해량을 띄워주는 로직은 만들었지만, 피해량의 int값을 어디서 어떻게 가져와야 할지 잘 몰라서 진도가 나가지 못했다.</li>
</ul>
<hr>
<blockquote>
<h3 id="일일-회고">일일 회고</h3>
</blockquote>
<ul>
<li>몬스터 피격시 피해량 로직이 완벽한지 아닌지 정확하게 확인하지 못했다(값을 받아오는 참조를 걸어줘야하는데 어디서 어떻게 가져올지 몰라서 못해줬다.)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL-260129] Team Project - Day 4]]></title>
            <link>https://velog.io/@23m-rft68/TIL-260129</link>
            <guid>https://velog.io/@23m-rft68/TIL-260129</guid>
            <pubDate>Fri, 30 Jan 2026 00:37:54 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-내가-맡은-파트">오늘 내가 맡은 파트</h1>
<h2 id="--캐릭터-컨트롤러">- 캐릭터 컨트롤러</h2>
<ul>
<li>플레이어 기준 카메라</li>
</ul>
<hr>
<blockquote>
<h3 id="내가-맡은-파트">내가 맡은 파트</h3>
</blockquote>
<ul>
<li>내가 캐릭터 컨트롤러에 넣어둔 카메라가 위와 아래를 볼때 캐릭터 기준으로 오르내리는게 아니라 카메라 위치 기준으로 오르락 내리락해서 일명 <code>&quot;카메라 끄덕끄덕 현상&quot;</code>이 일어나서 고치기로 했다.</li>
</ul>
<hr>
<blockquote>
<h3 id="데일리-스크럼">데일리 스크럼</h3>
</blockquote>
<h3 id="🌞-오늘-할-일-today">🌞 오늘 할 일 (Today)</h3>
<ul>
<li>카메라 시점 버그 수정</li>
</ul>
<hr>
<h3 id="🚧-현재-문제점--고민">🚧 현재 문제점 / 고민</h3>
<ul>
<li>캐릭터 컴포넌트를 다 바꾸게 되었는데 카메라 시점을 기준으로 총을쏘는게 어떻게 되는건지 궁금하다</li>
</ul>
<hr>
<h3 id="💬-기타-메모">💬 기타 메모</h3>
<ul>
<li>카메라 시점버그 수정을 성공해서 다행이라고 느꼈다.</li>
<li>우선 카메라 컨트롤러 스크립트를 새로 만들어주고 전에 수업시간에 배웠던 벽과 플레이어가 가까워질때 카메라가 플레이어쪽으로 줌인 되는 카메라 오브젝트 기법을 사용해서 시점을 좀 더 업그레이드 시켜주었고, 끄덕끄덕하던 현상은 플레이어 몸통에 오브젝트를 추가하여 그 오브젝트에 카메라를 상속시켜주어 카메라가 정상적으로 캐릭터 기준으로 위아래로 볼 수 있게되었다.</li>
</ul>
<hr>
<blockquote>
<h3 id="일일-회고">일일 회고</h3>
</blockquote>
<ul>
<li>카메라가 고개만 까딱거리는버그가 있어서 화면을 내리면 캐릭터가 시야를 가리는 버그가있었는데 강의영상과 인터넷 검색을 통해 해결방법을 찾아내어 카메라 시점 버그를 수정해서 좋았다! 어떤 원리인지 아직 정확하게 이해하진 못했지만 그래도 카메라를 구성할때 필요한것들을 조금이나마 알게되었다. </li>
</ul>
]]></description>
        </item>
    </channel>
</rss>