<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>dev_heoyoon.log</title>
        <link>https://velog.io/</link>
        <description>C# 클라이언트 프로그래밍 지망</description>
        <lastBuildDate>Mon, 29 Dec 2025 02:42:24 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>dev_heoyoon.log</title>
            <url>https://velog.velcdn.com/images/dev_heoyoon/profile/9dbc04e1-43e9-4ffd-b8e6-9448b5d5adda/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. dev_heoyoon.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/dev_heoyoon" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[SDK)[AddMob : 1]Unity에서 googleAdsMob SDK 설치]]></title>
            <link>https://velog.io/@dev_heoyoon/SDK-Unity%EC%97%90%EC%84%9C-googleAdsMob-SDK-%EC%82%AC%EC%9A%A9-%EC%8B%A4%EC%8A%B5</link>
            <guid>https://velog.io/@dev_heoyoon/SDK-Unity%EC%97%90%EC%84%9C-googleAdsMob-SDK-%EC%82%AC%EC%9A%A9-%EC%8B%A4%EC%8A%B5</guid>
            <pubDate>Mon, 29 Dec 2025 02:42:24 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h1 id="구글-애드몹">구글 애드몹</h1>
<p><a href="https://github.com/googleads/googleads-mobile-unity">깃 링크</a>
<a href="https://developers.google.com/admob/unity/quick-start?hl=ko#import_the_mobile_ads_for_unity_plugin">가이드 링크</a></p>
</blockquote>
<ul>
<li>구글 애드몹이란?<ul>
<li>구글이 제공하는 광고 플랫폼</li>
<li>사용자의 광고 시청을 개발자에게 수익화 시킬 수 있도록 도와준다</li>
</ul>
</li>
<li>기본 요건<ul>
<li>Unity Editor 2019.4이상 사용</li>
<li>IOS 기본 요건<ul>
<li>Xcode 16.0 이상</li>
<li>IOS 12.0 이상 타겟팅</li>
<li>cocoaPods</li>
</ul>
</li>
<li>Android 기본 요건<ul>
<li>최소 Android API 23 이상</li>
<li>Android API 수준 35 이상 타겟팅</li>
</ul>
</li>
<li>필요 절차<ul>
<li>Admob 계정생성 선행 필요(구글)</li>
<li><a href="https://github.com/googleads/googleads-mobile-unity/releases">최신릴리즈</a> 유니티 패키지 설치</li>
<li>Assets&gt;GoogleMobileAds&gt;Settings에서 Android Ios App ID 기입</li>
<li><a href="https://admob.google.com/v2/home">에드센스 아이디 발급</a>광고 단위까지 설정하면 ID를 얻을 수 있다.</li>
</ul>
</li>
</ul>
</li>
<li>핵심 메서드 및 클래스<blockquote>
</blockquote>
<table>
<thead>
<tr>
<th>클래스명 (네임스페이스)</th>
<th>메서드명</th>
<th>접근 방식</th>
<th>기능 설명</th>
</tr>
</thead>
<tbody><tr>
<td>MobileAds (GoogleMobileAds.Api)</td>
<td>Initialize(Action<InitializationStatus>)</td>
<td>정적 호출</td>
<td>AdMob SDK 초기화. 광고 사용 전 1회 호출.</td>
</tr>
<tr>
<td>MobileAds</td>
<td>RaiseAdEventsOnUnityMainThread</td>
<td>정적 프로퍼티</td>
<td>광고 콜백을 Unity 메인 스레드에서 처리할지 설정.</td>
</tr>
<tr>
<td>MobileAds</td>
<td>SetiOSAppPauseOnBackground(bool)</td>
<td>정적 호출</td>
<td>iOS 백그라운드 전환 시 앱 일시정지 동작 제어.</td>
</tr>
<tr>
<td>RequestConfiguration</td>
<td>Builder(), SetTestDeviceIds(List<string>)</td>
<td>인스턴스</td>
<td>테스트 디바이스 설정(실광고 클릭 방지).</td>
</tr>
<tr>
<td>MobileAds</td>
<td>SetRequestConfiguration(RequestConfiguration)</td>
<td>정적 호출</td>
<td>광고 요청 공통 설정 적용.</td>
</tr>
<tr>
<td>AdRequest</td>
<td>new AdRequest()</td>
<td>인스턴스 생성</td>
<td>광고 로드 요청 객체 생성.</td>
</tr>
<tr>
<td>BannerView</td>
<td>BannerView(adUnitId, AdSize, AdPosition)</td>
<td>인스턴스 생성</td>
<td>배너 광고 객체 생성.</td>
</tr>
<tr>
<td>BannerView</td>
<td>LoadAd(AdRequest)</td>
<td>인스턴스 호출</td>
<td>배너 광고 로드.</td>
</tr>
<tr>
<td>BannerView</td>
<td>Show(), Hide()</td>
<td>인스턴스 호출</td>
<td>배너 광고 표시/숨김.</td>
</tr>
<tr>
<td>BannerView</td>
<td>Destroy()</td>
<td>인스턴스 호출</td>
<td>배너 광고 해제.</td>
</tr>
<tr>
<td>InterstitialAd</td>
<td>Load(adUnitId, AdRequest, Action&lt;InterstitialAd, LoadAdError&gt;)</td>
<td>정적 호출</td>
<td>전면 광고 로드(비동기).</td>
</tr>
<tr>
<td>InterstitialAd</td>
<td>CanShowAd()</td>
<td>인스턴스 호출</td>
<td>전면 광고 표시 가능 여부 확인.</td>
</tr>
<tr>
<td>InterstitialAd</td>
<td>Show()</td>
<td>인스턴스 호출</td>
<td>전면 광고 표시.</td>
</tr>
<tr>
<td>InterstitialAd</td>
<td>Destroy()</td>
<td>인스턴스 호출</td>
<td>전면 광고 해제.</td>
</tr>
<tr>
<td>RewardedAd</td>
<td>Load(adUnitId, AdRequest, Action&lt;RewardedAd, LoadAdError&gt;)</td>
<td>정적 호출</td>
<td>리워드 광고 로드(비동기).</td>
</tr>
<tr>
<td>RewardedAd</td>
<td>CanShowAd()</td>
<td>인스턴스 호출</td>
<td>리워드 광고 표시 가능 여부 확인.</td>
</tr>
<tr>
<td>RewardedAd</td>
<td>Show(Action<Reward>)</td>
<td>인스턴스 호출</td>
<td>리워드 광고 표시 및 보상 콜백 수신.</td>
</tr>
<tr>
<td>RewardedAd</td>
<td>Destroy()</td>
<td>인스턴스 호출</td>
<td>리워드 광고 해제.</td>
</tr>
<tr>
<td>AppOpenAd</td>
<td>Load(adUnitId, AdRequest, ScreenOrientation, Action&lt;AppOpenAd, LoadAdError&gt;)</td>
<td>정적 호출</td>
<td>앱 오프닝 광고 로드.</td>
</tr>
<tr>
<td>AppOpenAd</td>
<td>CanShowAd(), Show(), Destroy()</td>
<td>인스턴스 호출</td>
<td>앱 오프닝 광고 표시/해제.</td>
</tr>
<tr>
<td>Reward</td>
<td>Type, Amount</td>
<td>인스턴스 프로퍼티</td>
<td>리워드 보상 타입 및 수량.</td>
</tr>
<tr>
<td>LoadAdError</td>
<td>GetMessage(), GetCode()</td>
<td>인스턴스 호출</td>
<td>광고 로드 실패 원인 확인.</td>
</tr>
<tr>
<td>AdError</td>
<td>GetMessage(), GetCode()</td>
<td>인스턴스 호출</td>
<td>광고 표시 중 에러 정보 확인.</td>
</tr>
<tr>
<td>AdValue</td>
<td>Value, CurrencyCode, Precision</td>
<td>인스턴스 프로퍼티</td>
<td>광고 수익 값 정보(노출 수익 분석).</td>
</tr>
</tbody></table>
</li>
</ul>
<p>실습 중 추가 사항
  <img src="https://velog.velcdn.com/images/dev_heoyoon/post/c61c90d6-7a1a-4c1a-8739-7df31de98dba/image.png" alt=""></p>
<p>  프로젝트 세팅의 서비스탭의 인앱구매,광고중계자 등 추가패키지 설치 가능</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[면접준비)Delegate,Func,Action의 차이]]></title>
            <link>https://velog.io/@dev_heoyoon/%EB%A9%B4%EC%A0%91%EC%A4%80%EB%B9%84DelegateFuncAction%EC%9D%98-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@dev_heoyoon/%EB%A9%B4%EC%A0%91%EC%A4%80%EB%B9%84DelegateFuncAction%EC%9D%98-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Mon, 22 Dec 2025 02:54:06 GMT</pubDate>
            <description><![CDATA[<p>셋 다 함수 포인터인데 뭐가 다를까?
아래 표로 설명해보겠다.</p>
<table>
<thead>
<tr>
<th>종류</th>
<th>반환타입</th>
<th>매개변수</th>
</tr>
</thead>
<tbody><tr>
<td>Delegate</td>
<td>public event Delegate <span style="color: red">float</span> AA(float a, int b)</td>
<td>뒤의 괄호</td>
</tr>
<tr>
<td>Action</td>
<td>void</td>
<td>Action의 제네릭타입</td>
</tr>
<tr>
<td>Func</td>
<td>마지막 제네릭 타입</td>
<td>Func의 제네릭타입</td>
</tr>
</tbody></table>
<p>해당 함수포인터를 다룰땐 event키워드도 긴밀하니 event에 대해서도 알아두자</p>
<blockquote>
<h2 id="event-키워드란">event 키워드란?</h2>
<p>델리게이트를 “외부에서는 구독/해지만 가능하도록 제한하는
접근 제어 문법(언어 차원의 보호 장치)”이다.
선언 예시 : <code>public event System.Action&lt;float&gt; action;</code></p>
</blockquote>
<table>
<thead>
<tr>
<th>종류</th>
<th>null 대입</th>
<th>함수 추가,제거</th>
<th>외부 호출</th>
</tr>
</thead>
<tbody><tr>
<td>event</td>
<td>X</td>
<td>O</td>
<td>X</td>
</tr>
<tr>
<td>none</td>
<td>O</td>
<td>O</td>
<td>O</td>
</tr>
<tr>
<td>즉 event키워드는 타 클래스에서 자신이 등록한 함수 외에는 수정 할 수 없도록</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>캡슐화해주는 역할을 한다.</td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[면접준비)Solid 원칙 정리]]></title>
            <link>https://velog.io/@dev_heoyoon/%EB%A9%B4%EC%A0%91%EC%A4%80%EB%B9%84Solid-%EC%9B%90%EC%B9%99-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@dev_heoyoon/%EB%A9%B4%EC%A0%91%EC%A4%80%EB%B9%84Solid-%EC%9B%90%EC%B9%99-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sat, 20 Dec 2025 14:36:42 GMT</pubDate>
            <description><![CDATA[<table>
<thead>
<tr>
<th>이니셜</th>
<th>이름</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td>S</td>
<td>Single Resposibility</td>
<td>단일 책임 원칙(SRP)으로 하나의 클래스는 하나의 책임만을 가져야 한다</td>
</tr>
<tr>
<td>O</td>
<td>Open Closed</td>
<td>확장엔 열려있고 수정엔 닫혀있어야 한다(OCP)는 원칙</td>
</tr>
<tr>
<td>L</td>
<td>Liskov Substitution</td>
<td>부모가 같은 클래스는 서로 바꿔도 작동해야한다(LSP)는 다형성 원칙</td>
</tr>
<tr>
<td>I</td>
<td>Interface Segregation</td>
<td>인터페이스분리 원칙(ISP)으로 인터페이스를 사용 의도에 맞게끔 잘게 분리해놔야 한다는 원칙</td>
</tr>
<tr>
<td>D</td>
<td>Dependency Inversion</td>
<td>의존성 역전 원칙(DIP)으로 하위모듈(Truck) 자체가 아닌 상위모듈(Vehicle)에 의존하여 구현하여야 한다는 원칙</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[면접준비)통신객체의 경량화와 오프라인 보상시스템]]></title>
            <link>https://velog.io/@dev_heoyoon/%ED%86%B5%EC%8B%A0%EA%B0%9D%EC%B2%B4%EC%9D%98-%EA%B2%BD%EB%9F%89%ED%99%94%EC%99%80-%EC%98%A4%ED%94%84%EB%9D%BC%EC%9D%B8-%EB%B3%B4%EC%83%81%EC%8B%9C%EC%8A%A4%ED%85%9C</link>
            <guid>https://velog.io/@dev_heoyoon/%ED%86%B5%EC%8B%A0%EA%B0%9D%EC%B2%B4%EC%9D%98-%EA%B2%BD%EB%9F%89%ED%99%94%EC%99%80-%EC%98%A4%ED%94%84%EB%9D%BC%EC%9D%B8-%EB%B3%B4%EC%83%81%EC%8B%9C%EC%8A%A4%ED%85%9C</guid>
            <pubDate>Fri, 19 Dec 2025 12:33:11 GMT</pubDate>
            <description><![CDATA[<ul>
<li><h2 id="통신객체-경량화">통신객체 경량화</h2>
<ul>
<li>통신에 사용되는 모든 객체에서 지켜져야 할 세가지<ul>
<li>실 사용 변수 외의 메모리를 할당하지 말자(함수 자체도 메모리를 할당)</li>
<li>실 사용 변수의 메모리의 Min과 Max를 고려하여 변수를 할당하자</li>
<li>만일 값을 정제해야하는 상황이 있을 시 외부 스크립트의 함수에서 정제해주자</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>안좋은 통신객체의 예제</p>
<pre><code class="language-cs">int gold;
int level;
int exp;
public void GetGold()
{

}</code></pre>
<p>그나마 고민을 조금 한 통신객체의 예제 </p>
<pre><code class="language-cs">double Mantissa; // 1.0 ~ 1000.0
int Exponent;    // 0,1,2... //큰 수를 표현하기 위한 Double,Int로 구성된 Struct객체
ushort level;
float exp;</code></pre>
<ul>
<li><h2 id="오프라인-보상-시스템에서-시간-구하기">오프라인 보상 시스템에서 시간 구하기</h2>
</li>
</ul>
<pre><code class="language-cs">
    public static double GetOfflineSecond()
    {
        DateTime last = DateTime.UtcNow;//마지막 접속시간을 return
        DateTime now = DateTime.UtcNow;
        TimeSpan offline = now - last;
        double result = offline.TotalSeconds;
        if (result &lt;= 0f) return 0f;
        return result;
    }</code></pre>
<p>여기에 배수만 붙여주면 된다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[(25/09/11)파이어베이스]]></title>
            <link>https://velog.io/@dev_heoyoon/%ED%8C%8C%EC%9D%B4%EC%96%B4%EB%B2%A0%EC%9D%B4%EC%8A%A4</link>
            <guid>https://velog.io/@dev_heoyoon/%ED%8C%8C%EC%9D%B4%EC%96%B4%EB%B2%A0%EC%9D%B4%EC%8A%A4</guid>
            <pubDate>Thu, 11 Sep 2025 08:22:10 GMT</pubDate>
            <description><![CDATA[<ul>
<li><p>파이어 베이스란?</p>
<ul>
<li>구글이 제공하는 앱 개발을 위한 백엔드 서비스</li>
<li>서버를 직접 구현하지 않고 필요한 기능을 바로 사용 할 수 있게 도와준다</li>
</ul>
</li>
<li><p>핵심 개념</p>
<ul>
<li>서버 없이도 앱을 빠르게 개발 할 수 있다.</li>
</ul>
</li>
<li><p>주요 기능</p>
<ul>
<li>인증(Authentication)<ul>
<li>이메일/비밀번호 로그인</li>
<li>구글,애플,페북,깃허브와 같은 소셜 로그인</li>
<li>게스트(익명)로그인</li>
</ul>
</li>
<li>데이터 베이스<ul>
<li>Realtime Database : Json트리구조,빠른 실시간 동기화</li>
<li>Cloud Firestore 문서 기반 쿼리 기능</li>
</ul>
</li>
<li>저장소 : 이미지 파일 등 저장 가능</li>
<li>호스팅 : 웹 앱,사이트 배포 가능</li>
<li>클라우드 함수 : 서버 코드 없이 이벤트 발생 시 자동 실행되는 서버리스 함수</li>
<li>분석 : 사용자 행동 로그 추적,이벤트 분석</li>
<li>원격 구성 : 앱 재배포 없이 서버에서 설정값을 바꿔 앱 동작 변경</li>
<li>푸시 메세지 : 모바일 앱에 푸시 알림 보내기</li>
</ul>
</li>
<li><p>게임 개발자FireBase 사용 이유</p>
<ul>
<li>서버 없이도 로그인 시스템 구현 가능</li>
<li>유저 데이터,인벤,랭킹 등을 클라우드 저장 가능</li>
<li>패치없이 서버 설정 변경 가능</li>
<li>분석/알림/마케팅이 한번에 지원</li>
</ul>
</li>
</ul>
<p><a href="https://console.firebase.google.com/">https://console.firebase.google.com/</a>
파이어베이스 콘솔 홈페이지</p>
<ul>
<li>파이어베이스 프로젝트 생성
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/fa4a2612-29ff-486c-aace-4814d2ce47c5/image.png" alt="">
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/a4e10ee9-5f15-4e23-a97c-f1ef5297e561/image.png" alt=""></li>
</ul>
<p>생성 후
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/45393fd9-38ec-45a2-9c4b-fff31419cc32/image.png" alt="">
대상 유니티 프로젝트 빌드세팅을 안드로이드로 변경
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/de626a2f-1ccd-4778-81c4-a38ee6795719/image.png" alt="">
패키지 네임을 찾아서
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/0ef53efe-29fa-4e46-9f19-73242477af0c/image.png" alt="">
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/eca995f8-72ec-4910-9dd8-f525b1bea08e/image.png" alt="">
해당 service json을 프로젝트에 넣어줌
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/c98e86e3-f13d-4014-b52d-315e6cdf5464/image.png" alt="">
파이어베이스 SDK 추가</p>
<p><a href="https://firebase.google.com/docs/unity/setup?hl=ko&amp;authuser=0&amp;_gl=1*nvfvdi*_ga*NzUyNjA5NDAuMTc1NzU3OTg4MA..*_ga_CW55HF8NVT*czE3NTc1Nzk4ODAkbzEkZzEkdDE3NTc1ODEzNDYkajM2JGwwJGgw#add-sdks">https://firebase.google.com/docs/unity/setup?hl=ko&amp;authuser=0&amp;_gl=1*nvfvdi*_ga*NzUyNjA5NDAuMTc1NzU3OTg4MA..*_ga_CW55HF8NVT*czE3NTc1Nzk4ODAkbzEkZzEkdDE3NTc1ODEzNDYkajM2JGwwJGgw#add-sdks</a>
유니티 추가 안내페이지
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/ac37b93b-6d1b-4428-a23d-ba2348eb8f88/image.png" alt="">
해당 페이지에서 SDK 설치</p>
<p>이후 내용은 개인 레파지토리
<a href="https://github.com/parechae123/FirebaseExample">https://github.com/parechae123/FirebaseExample</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[(2025/09/08)트러블슈팅) 어드레서블 ]]></title>
            <link>https://velog.io/@dev_heoyoon/20250908%ED%8A%B8%EB%9F%AC%EB%B8%94%EC%8A%88%ED%8C%85-%EC%96%B4%EB%93%9C%EB%A0%88%EC%84%9C%EB%B8%94</link>
            <guid>https://velog.io/@dev_heoyoon/20250908%ED%8A%B8%EB%9F%AC%EB%B8%94%EC%8A%88%ED%8C%85-%EC%96%B4%EB%93%9C%EB%A0%88%EC%84%9C%EB%B8%94</guid>
            <pubDate>Mon, 08 Sep 2025 01:59:21 GMT</pubDate>
            <description><![CDATA[<h1 id="상황-설명">상황 설명</h1>
<ul>
<li>빌드 시 총알 및 몬스터 sprite가 빌드 시 렌더링되지 않음 </li>
<li>에디터 환경에선 해당 이슈가 없었음</li>
</ul>
<h2 id="절차">절차</h2>
<ul>
<li>animator에 있는 sprite의 누락을 의심하여 어드레서블 빌드에 모든 스프라이트를 추가함</li>
<li>이후에도 해결되지 않아 scriptableobject로 관리하고있는 몬스터와 총알 정보 또한 어드레서블 빌드에 추가하였다.</li>
<li>appdata의 해당 프로젝트 Player를 문서를 통해 디버깅 해본 결과 다음과 같았다<ul>
<li>데이터 로딩은 성공적</li>
<li>spriteRenderer의 sprite 또한 정상적</li>
<li>다만 최초 실행시에 실행되기에 정확한 디버깅은 불가능</li>
</ul>
</li>
<li>기존 UI메니저에 테스트 코드를 추가하여 같은 타이밍에 UI Image에서 해당 스프라이트를 대입<ul>
<li>결과는 첫 프레임에는 Sprite가 적용되었으나 즉시 해제되는것을 시각적으로 확인</li>
<li>리소스 메니저에서 해당 sprite를 release 해주는 타이밍에서 이슈 발생을 확인</li>
</ul>
</li>
</ul>
<h1 id="해결">해결</h1>
<ul>
<li>handle로 가져온 오브젝트를 obj로 보관하지 않고 string,handle 형태의 딕셔너리로 보관하고 미사용시 해제해주는 방법으로 해결</li>
</ul>
<h1 id="요약">요약</h1>
<ul>
<li>에디터 상에서는 release 해주어도 에셋이 missing 되지 않았으나 이는 에디터의 에셋폴더를 즉시 참조할 수 있어 발생하지 않는 문제였다</li>
<li>빌드 시 어드레서블로 지정된 에셋만 빌드한다는 한정성과 handle의 특성을 고려하여 ResourceManager를 작성해야함을 깨달았다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[(25/08/29) Unity FPS 표시 & 메모리 관리]]></title>
            <link>https://velog.io/@dev_heoyoon/%EC%B5%9C%EC%A0%81%ED%99%94</link>
            <guid>https://velog.io/@dev_heoyoon/%EC%B5%9C%EC%A0%81%ED%99%94</guid>
            <pubDate>Thu, 28 Aug 2025 07:07:39 GMT</pubDate>
            <description><![CDATA[<h2 id="한글-주석-깨짐-방지">한글 주석 깨짐 방지</h2>
<p><code>.editorconfig</code> 파일에 아래 옵션 추가  </p>
<pre><code class="language-ini">indent_style = space
charset = utf-8</code></pre>
<p>✅ 한글 주석 깨짐 방지 완.</p>
<hr>
<h2 id="fps-표시하기">FPS 표시하기</h2>
<p>FPS를 UI 텍스트로 표시하는 간단한 스크립트  </p>
<pre><code class="language-csharp">using UnityEngine;
using UnityEngine.UI;

public class FPSDisplay : MonoBehaviour
{
    public Text fpsText;  // FPS 표시용 UI 텍스트
    float deltaTimeFloat = 0f;  // 델타타임 보간용
    float m;    // ms 단위 프레임 시간
    float fps;  // FPS 값

    void Start()
    {
        QualitySettings.vSyncCount = 1;
        // 0 → V-Sync 끔 (무제한 FPS)
        // 1 → 모니터 주사율 맞춤 (예: 60Hz → 60FPS)
        // 2 → 주사율 절반 맞춤 (예: 60Hz → 30FPS)

        Application.targetFrameRate = -1; // 프레임 제한 해제
    }

    void Update()
    {
        deltaTimeFloat += (Time.unscaledDeltaTime - deltaTimeFloat) * 0.1f;
        m = deltaTimeFloat * 1000.0f;   // ms 단위 프레임 시간
        fps = 1.0f / deltaTimeFloat;    // FPS 계산
        fpsText.text = fps.ToString(&quot;F0&quot;); // 정수 출력 (&quot;F1&quot; → 소수점 1자리)
    }
}</code></pre>
<hr>
<h2 id="v-sync-옵션-정리">V-Sync 옵션 정리</h2>
<ul>
<li><strong>Don&#39;t Sync</strong> → V-Sync 미사용, FPS 무제한  </li>
<li><strong>Every V Blank (기본값)</strong> → 모니터 주사율에 맞춰 동기화  <ul>
<li>ex) 60Hz 모니터 → 60FPS 제한  </li>
</ul>
</li>
<li><strong>Every Second V Blank</strong> → 주사율 절반에 동기화  <ul>
<li>ex) 60Hz 모니터 → 30FPS (성능 절약용)  </li>
</ul>
</li>
</ul>
<p>그래픽 드라이버 &amp; 모니터 환경변수에 따라 FPS 제한이 결정됨.</p>
<hr>
<h2 id="메모리-관리-destroy-필요-리소스">메모리 관리 (Destroy 필요 리소스)</h2>
<p>Unity에서 <strong>GC가 자동 수집하지 않는 리소스</strong>는 수동 파기 필수.  </p>
<h3 id="destroy-해줘야-하는-것들"><code>Destroy()</code> 해줘야 하는 것들</h3>
<ul>
<li><code>RenderTexture</code></li>
<li><code>Mesh</code></li>
<li><code>Material</code> / <code>Shader</code></li>
<li><code>AudioClip</code></li>
<li><code>Font</code></li>
<li><code>Sprite</code></li>
<li><code>ComputeBuffer</code></li>
<li><code>GraphicsBuffer</code></li>
</ul>
<h3 id="주의사항">주의사항</h3>
<ul>
<li><code>Texture2D</code>, <code>Sprite</code> 등도 더 이상 사용하지 않을 경우 <code>Destroy()</code> 필요  </li>
<li>해제하지 않으면 <strong>메모리 누수(memory leak)</strong> 발생  </li>
</ul>
<hr>
<h2 id="오늘의-배움">오늘의 배움</h2>
<ul>
<li><code>.editorconfig</code>에 <code>charset = utf-8</code> → 한글 주석 깨짐 방지  </li>
<li>FPS 표시 스크립트로 성능 확인 가능  </li>
<li>V-Sync 옵션 이해 → FPS 제어  </li>
<li>리소스는 꼭 <code>Destroy()</code> 해줘야 메모리 누수 방지  </li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[(08/08/22)노드 형식의 레이저 무한호출 트러블슈팅]]></title>
            <link>https://velog.io/@dev_heoyoon/080822%EB%85%B8%EB%93%9C-%ED%98%95%EC%8B%9D%EC%9D%98-%EB%A0%88%EC%9D%B4%EC%A0%80-%EB%AC%B4%ED%95%9C%ED%98%B8%EC%B6%9C-%ED%8A%B8%EB%9F%AC%EB%B8%94%EC%8A%88%ED%8C%85</link>
            <guid>https://velog.io/@dev_heoyoon/080822%EB%85%B8%EB%93%9C-%ED%98%95%EC%8B%9D%EC%9D%98-%EB%A0%88%EC%9D%B4%EC%A0%80-%EB%AC%B4%ED%95%9C%ED%98%B8%EC%B6%9C-%ED%8A%B8%EB%9F%AC%EB%B8%94%EC%8A%88%ED%8C%85</guid>
            <pubDate>Fri, 22 Aug 2025 01:18:22 GMT</pubDate>
            <description><![CDATA[<h1 id="상황-설명">상황 설명</h1>
<ul>
<li>모든 Laser의 호출은 하나의 LaserOut 스크립트의 Update 함수에서 호출이 된다.</li>
<li>즉 Reflecter가 서로를 쏘면 너무 많은 호출로 스택 메모리가 오버플로우 되어버리는 현상이 발생</li>
</ul>
<h2 id="절차">절차</h2>
<ul>
<li><p>스텍 메모리 오버플로우 현상 발생</p>
<ul>
<li>호출 a ⇒ b⇒ c ⇒ a 로 무한루프가 발생하고 있음을 확인</li>
</ul>
</li>
<li><p>단순 상호 비교 실행</p>
<ul>
<li><p>아래와 같이 구현을 하였으나 맵에 몇개의 리플렉션과 기본적인 portal reflection까지 감안한다면 너무 추가예외가 발생하여</p>
</li>
<li><p>실질적인 블로킹 역할을 하지 못했다</p>
<p><img src="https://velog.velcdn.com/images/dev_heoyoon/post/8473cb2c-99cd-4624-9d9f-5de8c4c5ae73/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<ul>
<li>인접노드를 재귀호출하여 탐색<ul>
<li>자신과 같은 target이 다음 currColide이라면 그건 확실한 무한루프의 증거이므로 true를 리턴</li>
<li>null도 아니고 다음 노드도 아닌데 타겟이 스스로인 경우 == 내부 실행이므로 작성 의도에 맞지않으므로 false를 리턴</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/dev_heoyoon/post/f90c544c-1d92-499b-ab63-9912fc424893/image.png" alt=""></p>
<h1 id="요약">요약</h1>
<ul>
<li>다음 노드로 명령을 호출할때 무한루프 방지를 위한 제약이 필요하다</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[25.08.28)렌더텍스쳐 세팅 이슈 해결]]></title>
            <link>https://velog.io/@dev_heoyoon/25.08.21%EB%A0%8C%EB%8D%94%ED%85%8D%EC%8A%A4%EC%B3%90-%EC%84%B8%ED%8C%85-%EC%9D%B4%EC%8A%88-%ED%95%B4%EA%B2%B0</link>
            <guid>https://velog.io/@dev_heoyoon/25.08.21%EB%A0%8C%EB%8D%94%ED%85%8D%EC%8A%A4%EC%B3%90-%EC%84%B8%ED%8C%85-%EC%9D%B4%EC%8A%88-%ED%95%B4%EA%B2%B0</guid>
            <pubDate>Thu, 21 Aug 2025 10:07:00 GMT</pubDate>
            <description><![CDATA[<p>RenderTexture 출력 시 의도한 바 보다 어둡고 후처리가 적용되지 않았던 문제</p>
<p><img src="https://velog.velcdn.com/images/dev_heoyoon/post/94b508b6-b6fe-44c5-ba51-c5e1adfb9d10/image.png" alt=""></p>
<p>1.실제 화면보다 어둡게 렌더링되는 이슈
2.PostProcessing이 적용되지 않는 이슈</p>
<blockquote>
<p>원인파악 프로세스</p>
</blockquote>
<ul>
<li><ol>
<li>카메라의 포스트 프로세싱 옵션 OnOff확인</li>
</ol>
</li>
<li><ol start="2">
<li>Volume 스크립트 추가 여부</li>
</ol>
<ul>
<li>Volume 프로필 적용 여부</li>
</ul>
</li>
<li><ol start="3">
<li>둘 다 확인 하였음에도 PostProcess는 적용 되나 여전히 텍스쳐가 어두운것을 발견</li>
</ol>
<ul>
<li>텍스쳐가 투영된 오브젝트 자체에 음영이 진 가능성</li>
<li>메쉬 자체가 음영이 진 것으로 확인</li>
<li>머테리얼을 Unlit으로 바꾸자 음영이 제거된 것을 확인</li>
</ul>
</li>
</ul>
<h1 id="마무리">마무리)</h1>
<ul>
<li>이번 트러블 슈팅에서 얻은 교훈은 3가지입니다.<ul>
<li>Render Texture는 텍스쳐 뿐이라는 점</li>
<li>Shader를 통해 Render Texture도 음영을 받는다는 점</li>
<li>카메라를 통해 Render Texture를 업데이트 해주는 과정은 캡처를 텍스쳐를 쓰는 과정이라는 점</li>
</ul>
</li>
</ul>
<p>이렇게 세가지로 마무리 지을 수 있겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[(25/08/18)Camera To Texture Rendering]]></title>
            <link>https://velog.io/@dev_heoyoon/250818Camera-To-Texture-Rendering</link>
            <guid>https://velog.io/@dev_heoyoon/250818Camera-To-Texture-Rendering</guid>
            <pubDate>Mon, 18 Aug 2025 13:01:28 GMT</pubDate>
            <description><![CDATA[<h2 id="0-목차">0. 목차</h2>
<ol>
<li><a href="#1-%EC%B9%B4%EB%A9%94%EB%9D%BC%EB%A5%BC-%ED%85%8D%EC%8A%A4%EC%B2%98%EB%A1%9C-%EB%A0%8C%EB%8D%94%EB%A7%81%ED%95%9C-%EC%8B%A4%EC%A0%9C-%EA%B2%8C%EC%9E%84-%EC%82%AC%EB%A1%80">카메라를 텍스처(Render Texture)로 렌더링한 실제 게임 사례</a>  </li>
<li><a href="#2-unity%EC%97%90%EC%84%9C-%EC%B9%B4%EB%A9%94%EB%9D%BC-%EC%B6%9C%EB%A0%A5%EC%9D%84-texture%EB%A1%9C-%EA%B5%AC%ED%98%84%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95">Unity에서 카메라 출력을 Texture로 구현하는 절차</a></li>
</ol>
<hr>
<hr>
<h2 id="1-카메라를-텍스처로-렌더링한-실제-게임-사례">1. 카메라를 텍스처로 렌더링한 실제 게임 사례</h2>
<h3 id="fallout-4의-tv">Fallout 4의 TV</h3>
<ul>
<li>Fallout 4에서 TV 화면에 실제 게임 내 다른 공간이 <strong>실시간 렌더링</strong>되어 보여집니다.</li>
<li>TV에 비치는 장면은 <strong>맵 내에 별도로 구현된 공간</strong>을 각각의 카메라가 촬영하여, 해당 화면을 텍스처로 TV에 출력합니다.</li>
<li>해당 공간에 오브젝트를 추가하면 TV 화면에도 실시간으로 반영되는 것을 확인할 수 있습니다.</li>
</ul>
<h3 id="게임-속-cctv">게임 속 CCTV</h3>
<ul>
<li>일반적으로 CCTV처럼 구현되는 화면도 <strong>카메라로 특정 공간을 촬영</strong>하여, 해당 영상을 Texture로 렌더링 후 모니터 오브젝트 등에 매핑합니다.</li>
<li>주로 플레이어가 돌아다니는 공간에 별도의 카메라를 설치해 촬영하고, 이 결과를 Texture로 표시합니다.</li>
</ul>
<h3 id="portal-시리즈">Portal 시리즈</h3>
<ul>
<li>Portal 게임에서는 포탈(게이트)을 연결한 두 지점에서, 각각의 포탈을 렌더링합니다.</li>
<li>예를 들어, 파란 포탈에서는 주황 포탈의 시점을 <strong>실시간으로 Texture에 렌더링</strong>해, 실제로 공간이 연결된 듯한 효과를 줍니다.</li>
<li>이 때, 각 포탈 텍스처는 서로 수직인 방향으로 렌더링되는 특징이 있습니다.</li>
</ul>
<blockquote>
<p><img src="https://velog.velcdn.com/images/dev_heoyoon/post/56f15f6f-acee-413b-bc9d-ecceac9c9253/image.png" alt=""><br>(Portal 시리즈의 포탈 텍스처 구현 예시)</p>
</blockquote>
<hr>
<h2 id="2-unity에서-카메라-출력을-texture로-구현하는-방법">2. Unity에서 카메라 출력을 Texture로 구현하는 방법</h2>
<p>Unity에서는 <strong>별도의 코드 없이 에디터만으로</strong> 카메라를 텍스처로 렌더링할 수 있습니다.</p>
<h3 id="1단계-render-texture-생성">1단계. Render Texture 생성</h3>
<ul>
<li><strong>Project</strong> 뷰에서 새 Render Texture를 만듭니다.</li>
</ul>
<blockquote>
<p><img src="https://velog.velcdn.com/images/dev_heoyoon/post/908272b4-9e45-4e82-b845-fe45f9465507/image.png" alt=""></p>
</blockquote>
<h3 id="2단계-새로운-카메라-생성-및-output-설정">2단계. 새로운 카메라 생성 및 Output 설정</h3>
<ul>
<li>새로운 카메라를 만들어서 <strong>Output Texture</strong> 항목에 위에서 만든 Render Texture를 지정합니다.</li>
<li>이때 <strong>RenderType</strong>을 &quot;Base&quot;로 지정해야 Output 탭이 노출됩니다.</li>
</ul>
<blockquote>
<p><img src="https://velog.velcdn.com/images/dev_heoyoon/post/51b3d0b0-74d8-4057-88b8-84704f584468/image.png" alt=""></p>
</blockquote>
<h3 id="3단계-render-texture-세부-설정">3단계. Render Texture 세부 설정</h3>
<ul>
<li>Render Texture의 <strong>Dimension은 2D</strong>, 필요한 <strong>해상도</strong>를 입력합니다.</li>
<li><strong>Depth Stencil Format</strong>도 설정해주는 것이 좋습니다.</li>
</ul>
<blockquote>
<p><img src="https://velog.velcdn.com/images/dev_heoyoon/post/b07a5fa6-c5ac-4d8e-af18-b08474beeaea/image.png" alt=""></p>
</blockquote>
<h3 id="4단계-새로운-material-생성-및-셰이더-지정">4단계. 새로운 Material 생성 및 셰이더 지정</h3>
<ul>
<li>새로운 Material을 만들고, Shader를 <strong>Unlit/Texture</strong>로 선택합니다.</li>
<li>이 Material의 &quot;Texture&quot; 슬롯에 Render Texture를 넣어줍니다.</li>
</ul>
<blockquote>
<p><img src="https://velog.velcdn.com/images/dev_heoyoon/post/4a0a3652-a659-4aa4-ab10-089737fb458f/image.png" alt=""></p>
</blockquote>
<h3 id="5단계-오브젝트에-material-적용">5단계. 오브젝트에 Material 적용</h3>
<ul>
<li>원하는 3D 오브젝트(예: TV, 모니터)의 Material 슬롯에 위에서 만든 Material을 할당하면 끝입니다.</li>
</ul>
<blockquote>
<p><img src="https://velog.velcdn.com/images/dev_heoyoon/post/803cea97-56c7-4842-ab84-d0997869df8d/image.png" alt=""></p>
</blockquote>
<hr>
<p><strong>정리</strong><br>이 방식은 여러 게임에서 사용되는 대표적인 카메라-텍스처 렌더링 기법으로, Unity에서도 매우 쉽게 구현이 가능합니다. 직관적으로 카메라 시점을 Texture처럼 활용하여 다양한 연출이 가능합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[(25/08/14)소수판별 알고리즘]]></title>
            <link>https://velog.io/@dev_heoyoon/250814%EC%86%8C%EC%88%98%ED%8C%90%EB%B3%84-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
            <guid>https://velog.io/@dev_heoyoon/250814%EC%86%8C%EC%88%98%ED%8C%90%EB%B3%84-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</guid>
            <pubDate>Thu, 14 Aug 2025 13:02:58 GMT</pubDate>
            <description><![CDATA[<h1 id="til-단일-숫자-소수-판별과-에라토스테네스의-체">TIL: 단일 숫자 소수 판별과 에라토스테네스의 체</h1>
<h2 id="단일-숫자-소수-판별-√n까지만-검사">단일 숫자 소수 판별 (√N까지만 검사)</h2>
<ul>
<li>어떤 자연수 N이 소수인지 확인할 때, <strong>2부터 √N까지만 나눠보면 충분</strong>.</li>
<li>이유: N이 합성수라면 반드시 √N 이하의 약수를 가짐.</li>
<li>예시: N = 14 → 2와 3만 검사하면 충분.</li>
</ul>
<pre><code class="language-csharp">public bool IsPrime(int n)
{
    if (n &lt; 2) return false; // 0, 1은 소수가 아님

    for (int i = 2; i * i &lt;= n; i++)
    {
        if (n % i == 0) return false;
    }

    return true;
}</code></pre>
<ul>
<li>시간 복잡도: O(√N)</li>
<li>핵심 포인트: 0, 1 처리, 나누어 떨어지면 합성수 판정, √N까지만 검사</li>
</ul>
<hr>
<h2 id="에라토스테네스의-체-범위-내-모든-소수-구하기">에라토스테네스의 체 (범위 내 모든 소수 구하기)</h2>
<ul>
<li><p><strong>2부터 N까지의 모든 소수를 한 번에 구하는 방법</strong>.</p>
</li>
<li><p>핵심 아이디어:</p>
</li>
<li><ol>
<li>2부터 N까지 숫자 리스트 생성</li>
<li>2 제외한 2의 배수를 모두 제거</li>
<li>리스트에서 다음 남은 수(3) 선택, 3의 배수 제거</li>
<li>이 과정을 √N 이하 수까지 반복</li>
</ol>
</li>
<li><p>결과: 리스트에 남은 수가 모두 소수</p>
</li>
</ul>
<h3 id="예시-n--14">예시: N = 14</h3>
<ol>
<li>처음 리스트: 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14</li>
<li>2의 배수 제거 → 2, 3, 5, 7, 9, 11, 13</li>
<li>3의 배수 제거 → 2, 3, 5, 7, 11, 13</li>
<li>√14 ≈ 3.74 → 여기서 종료, 남은 수가 소수: 2, 3, 5, 7, 11, 13</li>
</ol>
<p><strong>C# 코드 예시</strong></p>
<pre><code class="language-csharp">bool[] Sieve(int n)
{
    bool[] isPrime = new bool[n + 1];
    for (int i = 2; i &lt;= n; i++) isPrime[i] = true;

    for (int i = 2; i * i &lt;= n; i++)
    {
        if (isPrime[i])
        {
            for (int j = i * i; j &lt;= n; j += i) //i의 모든 배수
            {
                isPrime[j] = false;
            }
        }
    }
    return isPrime;
}</code></pre>
<ul>
<li>시간 복잡도: O(N log log N)</li>
<li>장점: 범위 내 모든 소수를 효율적으로 구할 수 있음</li>
<li>핵심 포인트: 2부터 시작, √N까지만 배수 제거, 남은 수가 소수</li>
</ul>
<h2 id="나만의-단어로-정리하기">나만의 단어로 정리하기</h2>
<ul>
<li>단일 소수판별 = √N까지만 탐색하여 i와 나눠지는 숫자가 없다면 N == Prime</li>
<li>범위 내의 소수 판별 = N 범위 안의 2를 초과하는 모든 숫자의 배수를 소수에서 제외해준다</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[(25/08/12)디자인 패턴 정리]]></title>
            <link>https://velog.io/@dev_heoyoon/250812%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@dev_heoyoon/250812%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Tue, 12 Aug 2025 02:43:57 GMT</pubDate>
            <description><![CDATA[<h1 id="디자인-패턴-정리">디자인 패턴 정리</h1>
<h2 id="목차">목차</h2>
<ol>
<li><a href="#singleton">Singleton</a></li>
<li><a href="#factory">Factory</a></li>
<li><a href="#observer">Observer</a></li>
<li><a href="#mediator">Mediator</a></li>
<li><a href="#state">State</a></li>
<li><a href="#command">Command</a></li>
<li><a href="#strategy">Strategy</a></li>
<li><a href="#state-vs-strategy-%EC%B0%A8%EC%9D%B4">State vs Strategy 차이</a></li>
</ol>
<h1 id="디자인-패턴-정리-1">디자인 패턴 정리</h1>
<h2 id="singleton">Singleton</h2>
<p><strong>정의</strong><br>프로그램 실행 중 하나의 인스턴스만 존재하도록 보장하는 패턴.<br>전역 접근이 가능하며 보통 <code>static</code> 필드를 이용해 구현하지만, 핵심은 &quot;전역에서 단 하나&quot;라는 제약을 설계 의도로 담는 것.</p>
<p><strong>예제 (C#)</strong>  </p>
<pre><code class="language-csharp">public class GameManager
{
    private static GameManager _instance;
    public static GameManager Instance =&gt; _instance ??= new GameManager();

    private GameManager() { }

    public void InitGame() { /* 초기화 로직 */ }
}</code></pre>
<hr>
<h2 id="factory">Factory</h2>
<p><strong>정의</strong><br>객체 생성을 전담하는 패턴. 생성 로직을 별도의 메서드나 클래스로 분리하여, 클라이언트가 구체적인 클래스 대신 인터페이스나 추상 클래스에 의존하게 만든다.</p>
<p><strong>예제 (C#)</strong>  </p>
<pre><code class="language-csharp">public interface IWeapon { void Attack(); }

public class Sword : IWeapon { public void Attack() =&gt; Console.WriteLine(&quot;검 휘두르기&quot;); }
public class Bow : IWeapon { public void Attack() =&gt; Console.WriteLine(&quot;화살 쏘기&quot;); }

public static class WeaponFactory
{
    public static IWeapon Create(string type) =&gt;
        type switch
        {
            &quot;Sword&quot; =&gt; new Sword(),
            &quot;Bow&quot; =&gt; new Bow(),
            _ =&gt; throw new ArgumentException(&quot;잘못된 타입&quot;)
        };
}</code></pre>
<hr>
<h2 id="observer">Observer</h2>
<p><strong>정의</strong><br>객체의 상태 변화를 감지하여, 이를 구독하고 있는 다른 객체들에게 자동으로 알리는 패턴.</p>
<p><strong>예제 (C#)</strong>  </p>
<pre><code class="language-csharp">public interface IObserver { void Update(int hp); }

public class HPBar : IObserver
{
    public void Update(int hp) =&gt; Console.WriteLine($&quot;HP 바 업데이트: {hp}&quot;);
}

public class Player
{
    private List&lt;IObserver&gt; observers = new();
    private int hp;
    public void Attach(IObserver observer) =&gt; observers.Add(observer);
    public void SetHP(int value)
    {
        hp = value;
        foreach (var obs in observers) obs.Update(hp);
    }
}</code></pre>
<hr>
<h2 id="mediator">Mediator</h2>
<p><strong>정의</strong><br>서로 직접 참조하지 않는 객체들이 중재자를 통해 상호작용하는 패턴. 객체 간 결합도를 낮추고 상호작용을 한 곳에서 관리한다.<br>이벤트 버스(Event Aggregator)와 유사하지만, Mediator는 로직을 직접 중재하고 오케스트레이션한다.</p>
<p><strong>예제 (C#)</strong>  </p>
<pre><code class="language-csharp">public interface IMediator
{
    void Send(string message, Colleague sender);
}

public abstract class Colleague
{
    protected IMediator mediator;
    public Colleague(IMediator m) =&gt; mediator = m;
}

public class ConcreteMediator : IMediator
{
    public ColleagueA A { get; set; }
    public ColleagueB B { get; set; }

    public void Send(string message, Colleague sender)
    {
        if (sender == A) B.Receive(message);
        else A.Receive(message);
    }
}

public class ColleagueA : Colleague
{
    public ColleagueA(IMediator m) : base(m) { }
    public void Send(string msg) =&gt; mediator.Send(msg, this);
    public void Receive(string msg) =&gt; Console.WriteLine($&quot;A가 받은 메시지: {msg}&quot;);
}

public class ColleagueB : Colleague
{
    public ColleagueB(IMediator m) : base(m) { }
    public void Send(string msg) =&gt; mediator.Send(msg, this);
    public void Receive(string msg) =&gt; Console.WriteLine($&quot;B가 받은 메시지: {msg}&quot;);
}</code></pre>
<hr>
<h2 id="state">State</h2>
<p><strong>정의</strong><br>객체가 가질 수 있는 상태를 객체화하고, 상태 변화에 따라 행동이 달라지도록 만드는 패턴. 상태 전이 규칙이 핵심.</p>
<p><strong>예제 (C#)</strong>  </p>
<pre><code class="language-csharp">public interface IState
{
    void Enter(Player p);
    void Update(Player p);
}

public class Idle : IState
{
    public void Enter(Player p) { Console.WriteLine(&quot;Idle 상태&quot;); }
    public void Update(Player p)
    {
        if (p.Input.Move) p.ChangeState(new Run());
    }
}

public class Run : IState
{
    public void Enter(Player p) { Console.WriteLine(&quot;Run 상태&quot;); }
    public void Update(Player p)
    {
        if (!p.Input.Move) p.ChangeState(new Idle());
    }
}

public class Player
{
    public (bool Move, bool Attack) Input;
    private IState _state = new Idle();

    public void ChangeState(IState state)
    {
        _state = state;
        _state.Enter(this);
    }

    public void Tick() =&gt; _state.Update(this);
}</code></pre>
<hr>
<h2 id="command">Command</h2>
<p><strong>정의</strong><br>요청을 객체로 캡슐화하여 호출, 취소, 재실행이 가능하게 하는 패턴. 명령 이력을 저장하여 나중에 되돌리거나 재실행할 수 있다.</p>
<p><strong>예제 (C#)</strong>  </p>
<pre><code class="language-csharp">public interface ICommand
{
    void Execute();
    void Undo();
}

public class AddHP : ICommand
{
    private Player player;
    private int amount;

    public AddHP(Player p, int a) { player = p; amount = a; }
    public void Execute() =&gt; player.HP += amount;
    public void Undo() =&gt; player.HP -= amount;
}

public class Invoker
{
    private Stack&lt;ICommand&gt; history = new();
    public void ExecuteCommand(ICommand cmd)
    {
        cmd.Execute();
        history.Push(cmd);
    }
    public void Undo()
    {
        if (history.Count &gt; 0) history.Pop().Undo();
    }
}</code></pre>
<hr>
<h2 id="strategy">Strategy</h2>
<p><strong>정의</strong><br>알고리즘을 캡슐화하여 교체 가능하게 만드는 패턴. <code>State</code> 패턴과 달리 내부 전이 규칙 없이, 실행 시점에 전략을 선택해 적용한다.</p>
<p><strong>예제 (C#)</strong>  </p>
<pre><code class="language-csharp">public interface IDamageStrategy
{
    int Calculate(int atk, int def);
}

public class NormalDamage : IDamageStrategy
{
    public int Calculate(int atk, int def) =&gt; Math.Max(0, atk - def);
}

public class CriticalDamage : IDamageStrategy
{
    public int Calculate(int atk, int def) =&gt; Math.Max(0, (int)(atk * 1.5) - def);
}

public class Combat
{
    private IDamageStrategy strategy;
    public Combat(IDamageStrategy s) =&gt; strategy = s;
    public void SetStrategy(IDamageStrategy s) =&gt; strategy = s;
    public int DealDamage(int atk, int def) =&gt; strategy.Calculate(atk, def);
}</code></pre>
<hr>
<h2 id="state-vs-strategy-차이">State vs Strategy 차이</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>State</th>
<th>Strategy</th>
</tr>
</thead>
<tbody><tr>
<td><strong>의도</strong></td>
<td>상태 변화에 따라 행동이 달라짐</td>
<td>알고리즘(정책)을 실행 시점에 교체</td>
</tr>
<tr>
<td><strong>전이 규칙</strong></td>
<td>있음. 상태 객체나 컨텍스트가 전이를 결정</td>
<td>없음. 교체는 외부에서 결정</td>
</tr>
<tr>
<td><strong>사용 예</strong></td>
<td>플레이어 FSM, UI 라이프사이클</td>
<td>정렬 알고리즘, 데미지 계산 방식</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[(250808)InputSystem CSharp Event]]></title>
            <link>https://velog.io/@dev_heoyoon/250808InputSystem-CSharp-Event</link>
            <guid>https://velog.io/@dev_heoyoon/250808InputSystem-CSharp-Event</guid>
            <pubDate>Fri, 08 Aug 2025 13:47:44 GMT</pubDate>
            <description><![CDATA[<p>본론에 들어가기 이전
old input과 같은 다이렉트 처리 방식 접근방법 예제</p>
<pre><code>Mouse mouse
Keyboard keyboard
Gamepad gamePad</code></pre><p>각 변수를 Mouse.current같은 필드를 호출해 대입해주면
old input과 같이 사용이 가능하다</p>
<blockquote>
</blockquote>
<p><img src="https://velog.velcdn.com/images/dev_heoyoon/post/e601cfe3-5b5f-41a8-a2ef-8a7fc6586545/image.png" alt="">
위와같이 설정 된 인풋액션을
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/84f82732-708e-4543-b002-51e54bf1fa57/image.png" alt="">
위와같이 C# Class로 Generate하면 객체가 생겨난다.
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/7c8fc83a-6b2f-48fd-83e2-ff83baaa2fc7/image.png" alt="">
해당 클래스는 
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/094bcc0c-143e-4c2d-9cd9-bd6753a4ef9d/image.png" alt="">
위와같이 performed,canceled,started
이벤트를 연결하여 키를 사용할 수 있다.
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/c84c4d51-9d1b-4d57-a8e4-706c9b727a69/image.png" alt="">
이렇게 활성화를 해주면 사용 가능!
반대로 사용하지 않을 시 Disable로 통제 가능하다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[각 데이터의 특성(CSV,YAM,Json,ScriptableObject)]]></title>
            <link>https://velog.io/@dev_heoyoon/%EA%B0%81-%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%9D%98-%ED%8A%B9%EC%84%B1CSVYAMJsonScriptableObject</link>
            <guid>https://velog.io/@dev_heoyoon/%EA%B0%81-%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%9D%98-%ED%8A%B9%EC%84%B1CSVYAMJsonScriptableObject</guid>
            <pubDate>Wed, 06 Aug 2025 08:57:02 GMT</pubDate>
            <description><![CDATA[<h1 id="직렬화와-역직렬화">직렬화와 역직렬화</h1>
<ul>
<li><p><strong>직렬화(Serialization)</strong><br>메모리에 있는 데이터를 읽을 수 있도록 연속된 데이터로 변환해주는 것</p>
</li>
<li><p><strong>역직렬화(Deserialization)</strong><br>직렬화한 값을 현재 메모리에 넣어주는 행동, 즉 객체에 할당하는 과정</p>
</li>
</ul>
<h1 id="데이터-포맷별-특징">데이터 포맷별 특징</h1>
<h2 id="csv">CSV</h2>
<ul>
<li>객체값 중 <code>,</code>(쉼표)를 사용하면 구문 오류가 발생할 수 있어 반드시 전처리가 필요</li>
</ul>
<h2 id="yaml">YAML</h2>
<ul>
<li>데이터를 여닫는 구조 (HTML과 비슷함)  </li>
<li>사람이 읽기 편함</li>
</ul>
<h2 id="json">JSON</h2>
<ul>
<li>Unity에서는 주로 <code>JsonUtility</code> 또는 <code>NewtonSoft</code> 라이브러리를 사용  </li>
<li><code>JsonUtility</code>가 반응이 빠르고 읽기 쉬움</li>
</ul>
<h1 id="참고-링크">참고 링크</h1>
<ul>
<li>Unity 공식 문서 — JsonUtility<br><a href="https://docs.unity3d.com/ScriptReference/JsonUtility.html">https://docs.unity3d.com/ScriptReference/JsonUtility.html</a></li>
</ul>
<h1 id="scriptable-object">Scriptable Object</h1>
<ul>
<li>유니티에서 자체 지원하는 스크립팅 가능한 데이터 객체  </li>
<li>주로 정적 데이터를 읽어오는 용도로 많이 사용됨</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[(25/08/07)메모리구조(Memory Structure)]]></title>
            <link>https://velog.io/@dev_heoyoon/MemoryStructure</link>
            <guid>https://velog.io/@dev_heoyoon/MemoryStructure</guid>
            <pubDate>Wed, 06 Aug 2025 02:37:28 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/dev_heoyoon/post/e757ad68-9569-40cf-9da0-e6fa3ad76fc1/image.png" alt="">
<a href="https://commons.wikimedia.org/wiki/File:Computer_Systems_-_Von_Neumann_Architecture_Large_poster_anchor_chart.svg">이미지 출처</a>
메모리(Ram) = 실행중인 프로그램의 명령어와 데이터를 저장
CPU = 해당 메모리에 저장된 명령어를 읽어들이고 명령을 실행, 해석하는 부품 
f == 함수 ,r == 결과, 정수 = 변수 </p>
<p>메모리 실행과정 = {f(<code>[1]+[2]</code>),100,120} =&gt; {f,100,120,r(220)}
순서는 메모리에 올려져있는걸 CPU가 읽고 다음 메모리에 기입하는 형태 </p>
<blockquote>
<ul>
<li>Q : 그렇다면 함수도 메모리에 저장 되는 것으로 보이는데 스텍영역으로 사용 후 회수가 되는걸까요?</li>
</ul>
</blockquote>
<ul>
<li>A : O(다만 함수 호출 자체는 메모리를 생성하진 않음 함수가 끝날때 매개변수와 지역변수 해제<ul>
<li>Q(1번 케이스가 stack영역일시) : Action같은 delegate 기반의 객체들을 필드로 선언두면 함수의 포인터를 저장하는 인스턴스로 알고있습니다.
제가 기억하기로는 참조형 == 힙영역, 값타입 == 스텍영역 으로 기억하고있는데 함수포인터는 실행 시 스텍영역을 할당받는건가요?</li>
</ul>
</li>
<li>A : 힙메모리에 할당이 되긴함<ul>
<li>실행에 스텍영역을 받는다면 GC를 호출시마다 실행하진 않을 것 같고 참조형이니 저장은 힙, 실행은 스텍 이렇게 이해하면 될지요?</li>
<li>A : O</li>
</ul>
</li>
<li>또 제가 작업할때 구조때문에 함수 포인터를 자주 쓰는편인데 저장에 힙영역을 할당받는다면 사용 빈도를 줄이는게 좋을 까요?<ul>
<li>A : 구조우선, 메모리도 중요하나 협업 가능한 코드를 짜는것이 더 중요</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/dev_heoyoon/post/72344b5b-fbbf-4174-a25c-e243a9b6747a/image.png" alt=""></p>
<blockquote>
<ul>
<li>코드영역</li>
</ul>
</blockquote>
<ul>
<li><p>readOnly, const와 컴파일된 코드들이 저장되는 공</p>
<ul>
<li>데이터영역</li>
</ul>
</li>
<li><p>static이나 field같은 변수를 저장하는 공간</p>
<ul>
<li>스텍 영역</li>
</ul>
</li>
<li><p>지역변수,매개변수,struct</p>
</li>
<li><p>함수 실행 시 할당되는 지역,매개변수는 함수 종료와 함께 메모리 해제</p>
<ul>
<li>힙 영역</li>
</ul>
</li>
<li><p>이 공간에 메모리 할당하는것이 동적할당</p>
</li>
<li><p>참조형을 저장하는 공간(new키워드로 생성하는 객체)</p>
</li>
<li><p>만일 지역번수로 참조형을 사용한다면?</p>
<ul>
<li><p>생성 자체는 힙영역에 할당(본체), 지역변수는 포인터를 가져온 스텍 메모리 영역, 없으면 그냥 GC수거</p>
</li>
<li><p>Q : 그렇다면 지역변수에서도 사용이 끝난 힙 객체들은 null로 설정해두어야 하나요?</p>
</li>
<li><h1 id="gc-garbage-collection">GC (Garbage Collection)</h1>
</li>
<li><h2 id="장점">장점</h2>
</li>
<li><p>자동 메모리 관리</p>
</li>
<li><p>메모리 누수 방지</p>
</li>
<li><p>생산성 향상 = 매번 해제해주지 않아도 된다</p>
</li>
<li><h2 id="단점">단점</h2>
</li>
<li><p>메모리 관리 오버헤드 : GC 호출에도 메모리가 사용되므로 성능저하가 생길 수 있음</p>
</li>
<li><p>예측 불가능한 실행 시점 : GC 호출 시점이 예측하기 어렵다</p>
</li>
<li><h2 id="gc-를-피하는-방법">GC 를 피하는 방법</h2>
</li>
<li><p>ObejctPooling 사용</p>
</li>
<li><p>구조체 사용</p>
</li>
<li><p>큰 객체 사용 지양(85KB 이상의 객체는 LOH에 할당되므로 사용 최소화와 분할 객체 사용이 필요)</p>
</li>
<li><p>임시 객체 생성 최소화 및 명시적 해제</p>
</li>
<li><h2 id="etc">ETC</h2>
</li>
<li><p>GC는 System.GC로 호출이 가능하나 고비용의 호출이라 많이 쓰진 않는다.</p>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[(25/08/01)네브메쉬2D 트러블슈팅]]></title>
            <link>https://velog.io/@dev_heoyoon/250801</link>
            <guid>https://velog.io/@dev_heoyoon/250801</guid>
            <pubDate>Fri, 01 Aug 2025 12:19:13 GMT</pubDate>
            <description><![CDATA[<h1 id="상황-설명">상황 설명</h1>
<ul>
<li>몬스터의 특성에 따라 움직임과 공격 구현을 따로 해야하는 기획을 받았다.</li>
<li>공격은 이미 모듈로 구현을 해놓은 상태</li>
<li>이동은 몬스터 스크립트 자체에 구현이 되어있었기에 분리하는 작업이 필요</li>
</ul>
<h2 id="절차">절차</h2>
<p>인터페이스로 무브 핸들러를 구현
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/2e23c893-6279-431a-ac3b-09761975b260/image.png" alt="">
설정에 따른 각각의 움직임을 구현
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/6097891b-0d99-4154-9929-dbb091b4e6b6/image.png" alt="">
몬스터 실제 몬스터 객체에 적용
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/9773a8ba-4e92-4541-b585-57a941d8914a/image.png" alt=""></p>
<p>그런데....</p>
<ul>
<li><h2 id="네브메쉬-오류발생">네브메쉬 오류발생</h2>
<ul>
<li><h3 id="플레이어에게-돌진하는-몬스터를-구현해야하는-상황">플레이어에게 돌진하는 몬스터를 구현해야하는 상황..</h3>
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/126dac0f-8630-4ed8-aa22-bf81218b69b9/image.gif" alt="">
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/b64c5e27-2e4b-44fd-abbe-bd57b275cb79/image.png" alt=""></li>
<li>벡터 방향성의 문제가 없다는 것은 중단점을 통해 확인하였다.<ul>
<li>velocity의 문제인것이 거의 확실해진 상황</li>
</ul>
</li>
<li>그렇다면 velocity가 아닌 다른 방법을 통해서 이동을 구현해야한다...
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/b3b686d2-0bd2-43e7-943a-131e6b14f7b7/image.png" alt="">
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/ed9126b7-e169-43ce-908c-e608496648cf/image.gif" alt=""><blockquote>
<p>문제없이 작동하는 모습, 다만 navMesh의 좌표와 현재 트랜스폼의 좌표가 일치하지 않기에
돌아가는 현상이 있어 완료시 Warp를 통해 위치값을 바꿔주어야 한다.</p>
</blockquote>
</li>
</ul>
</li>
</ul>
<h1 id="요약">요약</h1>
<ul>
<li>agent.velocity를 임의로 컨트롤 하기때문에 생긴 문제</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[(25/07/31)해상도 대응을 위한 CanvasScaler]]></title>
            <link>https://velog.io/@dev_heoyoon/%ED%95%B4%EC%83%81%EB%8F%84-%EB%8C%80%EC%9D%91%ED%95%B4%EC%83%81%EB%8F%84-%EB%8C%80%EC%9D%91</link>
            <guid>https://velog.io/@dev_heoyoon/%ED%95%B4%EC%83%81%EB%8F%84-%EB%8C%80%EC%9D%91%ED%95%B4%EC%83%81%EB%8F%84-%EB%8C%80%EC%9D%91</guid>
            <pubDate>Thu, 31 Jul 2025 07:29:23 GMT</pubDate>
            <description><![CDATA[<h1 id="목차">목차</h1>
<ol>
<li><a href="#canvasscaler%EB%9E%80">CanvasScaler란</a></li>
<li><a href="#scalemode-%EB%AA%A8%EB%93%9C">ScaleMode 모드</a></li>
<li><a href="#%ED%99%94%EB%A9%B4%EB%B9%84%EC%9C%A8%EC%97%90-%EB%A7%9E%EB%8A%94-ui-%EB%B0%B0%EC%B9%98%EB%B2%95">화면비율에 맞는 UI 배치법</a></li>
</ol>
<hr>
<h1 id="canvasscaler란">CanvasScaler란</h1>
<ul>
<li>canvas의 사이즈를 조정하는 컴포넌트로 Scale With Screen Size를 통해 해상도에 맞는 UI 사이즈 대응을 할 수 있다.</li>
</ul>
<h1 id="scalemode-모드">ScaleMode 모드</h1>
<table>
<thead>
<tr>
<th>모드</th>
<th>설명</th>
<th>주요 특징</th>
<th>주 사용 사례</th>
</tr>
</thead>
<tbody><tr>
<td>Constant Pixel Size</td>
<td>해상도와 상관없이 UI가 항상 같은 픽셀 크기로 표시됨</td>
<td>화면 해상도 높으면 작게, 낮으면 크게 보임</td>
<td>단일 해상도 대상 UI</td>
</tr>
<tr>
<td>Scale With Screen Size</td>
<td>기준 해상도에 따라 실제 해상도 비례로 UI 크기가 자동 조정됨</td>
<td>다양한 기기 지원, 기준 해상도와 화면 비율 매칭 옵션 제공</td>
<td>반응형 UI, 다양한 기기</td>
</tr>
<tr>
<td>Constant Physical Size</td>
<td>실제 인치(mm, inch 등) 등 물리적 크기 기준 UI가 표시됨</td>
<td>장치의 DPI 정보 활용, DPI 정보 미제공 시 Fallback 값 사용</td>
<td>인쇄용, 전문 장비 UI</td>
</tr>
</tbody></table>
<h1 id="화면비율에-맞는-ui-배치법">화면비율에 맞는 UI 배치법</h1>
<ul>
<li>scale with screen size 모드를 선택 후  </li>
<li>캔버스상의 pivot을 설정하고  </li>
<li>RectTransform의 Anchors를 화면의 특정 위치를 지정해준 뒤  </li>
<li>RectTransform의 right, left, down, up을 0 혹은 원하는 위치로 지정하면 대부분의 해상도에 대응이 가능하다.</li>
</ul>
<p>드디어 무한 해상도 지옥에서 해방 된 기분이다<br>이전에 동적 <a href="https://github.com/parechae123/Header/blob/main/Header/Assets/GameManagingScripts/Managers/UIManager.cs">UI 할당</a>을 하느랴고 미련한 짓을 한 적이 있었는데 굉장히 큰 쾌거인 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[(25/07/30)NavMesh2D]]></title>
            <link>https://velog.io/@dev_heoyoon/250730NavMesh2D</link>
            <guid>https://velog.io/@dev_heoyoon/250730NavMesh2D</guid>
            <pubDate>Wed, 30 Jul 2025 00:41:27 GMT</pubDate>
            <description><![CDATA[<p><a href="https://github.com/h8man/NavMeshPlus"><img src="https://velog.velcdn.com/images/dev_heoyoon/post/987adafe-12e1-4d4f-977d-a1327b46dc7c/image.png" alt="해당 깃" title="NavMesh2D Git"></a></p>
<h1 id="목차">목차</h1>
<ul>
<li><a href="#navmesh2d%EB%9E%80">NavMesh2D란</a></li>
<li><a href="#navmesh2d-%EC%84%B8%ED%8C%85%EB%B0%A9%EB%B2%95">NavMesh2D 세팅방법</a></li>
<li><a href="#%EC%A3%BC%EC%9A%94-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0-properties">NavMeshAgent의 프로퍼티</a></li>
<li><a href="#%EC%A3%BC%EC%9A%94-%EB%A9%94%EC%84%9C%EB%93%9C-public-methods">NavMeshAgent의 주요 메서드</a></li>
</ul>
<blockquote>
<h1 id="navmesh2d란">NavMesh2D란?</h1>
<p>기존의 3D 프로젝트 환경에서 사용하는 NavMesh 라이브러리를
2D 프로젝트 환경에서 사용할 수 있도록 만들어주는 커스텀 라이브러리이다.
설치방법은 위 링크의 설명에서 자세히 설명되어있다.</p>
</blockquote>
<h2 id="nbsp"> &amp;nbsp</h2>
<p> &amp;nbsp</p>
<blockquote>
<h1 id="navmesh2d-세팅방법">NavMesh2D 세팅방법</h1>
<p><img src="https://velog.velcdn.com/images/dev_heoyoon/post/17cb8e11-c443-497b-8e4d-951df406015b/image.png" alt=""></p>
</blockquote>
<ul>
<li><h3 id="navmesh의-navigation-modifier스크립트">NavMesh의 navigation Modifier스크립트</h3>
<ul>
<li>mesh의 크기만큼 area의 옵션을 설정하는 옵션</li>
<li>최단거리 알고리즘에서 가중치를 설정해줄 수 있듯 Cost를 설정하여 Agent의 경로를 유도 할 수 있다.(높을수록 낮은 우선순위)
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/ef146b16-45f9-4167-b9c2-bf0df5913a9d/image.png" alt=""></li>
</ul>
</li>
<li><h3 id="map-baking">Map Baking</h3>
<ul>
<li>Navigation CollectSources2D : Rotation Surface to XY 버튼으로 3d 기반인 navMesh의 축을 2D에 맞게 변환해준다.</li>
<li>Navigation Surface : 맵에 존재하는 navigation Modifier들을 처리하여 베이킹해준다</li>
</ul>
</li>
</ul>
<h2 id="nbsp-1"> &amp;nbsp</h2>
<p> &amp;nbsp</p>
<h1 id="주요-프로퍼티-properties">주요 프로퍼티 (Properties)</h1>
<table>
<thead>
<tr>
<th>프로퍼티 이름</th>
<th>반환값 (Type)</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>acceleration</code></td>
<td><code>(float)</code></td>
<td>최대 가속도 (m/s²)</td>
</tr>
<tr>
<td><code>angularSpeed</code></td>
<td><code>(float)</code></td>
<td>회전 속도 (도/초)</td>
</tr>
<tr>
<td><code>areaMask</code></td>
<td><code>(int)</code></td>
<td>통과 가능한 NavMesh 영역 마스크</td>
</tr>
<tr>
<td><code>autoBraking</code></td>
<td><code>(bool)</code></td>
<td>목적지 도착 시 자동 감속 여부</td>
</tr>
<tr>
<td><code>autoRepath</code></td>
<td><code>(bool)</code></td>
<td>경로 무효 시 자동 재탐색 여부</td>
</tr>
<tr>
<td><code>autoTraverseOffMeshLink</code></td>
<td><code>(bool)</code></td>
<td>OffMeshLink 자동 이동 여부</td>
</tr>
<tr>
<td><code>avoidancePriority</code></td>
<td><code>(int)</code></td>
<td>장애물 회피 우선순위 (0~99, 낮을수록 우선)</td>
</tr>
<tr>
<td><code>baseOffset</code></td>
<td><code>(float)</code></td>
<td>NavMesh 위 에이전트 높이 오프셋</td>
</tr>
<tr>
<td><code>desiredVelocity</code></td>
<td><code>(Vector3)</code></td>
<td>현재 원하는 속도 (읽기 전용)</td>
</tr>
<tr>
<td><code>destination</code></td>
<td><code>(Vector3)</code></td>
<td>이동 목적지 좌표</td>
</tr>
<tr>
<td><code>hasPath</code></td>
<td><code>(bool)</code></td>
<td>유효한 경로 존재 여부 (읽기 전용)</td>
</tr>
<tr>
<td><code>height</code></td>
<td><code>(float)</code></td>
<td>에이전트 높이</td>
</tr>
<tr>
<td><code>isOnNavMesh</code></td>
<td><code>(bool)</code></td>
<td>에이전트가 NavMesh 위에 있는지 여부 (읽기 전용)</td>
</tr>
<tr>
<td><code>isOnOffMeshLink</code></td>
<td><code>(bool)</code></td>
<td>현재 OffMeshLink 위에 있는지 여부 (읽기 전용)</td>
</tr>
<tr>
<td><code>isStopped</code></td>
<td><code>(bool)</code></td>
<td>이동 멈춤 여부</td>
</tr>
<tr>
<td><code>nextPosition</code></td>
<td><code>(Vector3)</code></td>
<td>다음 이동 위치, 강제 설정 가능</td>
</tr>
<tr>
<td><code>obstacleAvoidanceType</code></td>
<td><code>(ObstacleAvoidanceType)</code></td>
<td>장애물 회피 품질 수준</td>
</tr>
<tr>
<td><code>path</code></td>
<td><code>(NavMeshPath)</code></td>
<td>현재 경로</td>
</tr>
<tr>
<td><code>pathPending</code></td>
<td><code>(bool)</code></td>
<td>경로 계산 중인지 여부 (읽기 전용)</td>
</tr>
<tr>
<td><code>pathStatus</code></td>
<td><code>(NavMeshPathStatus)</code></td>
<td>경로 상태 (완료, 부분, 없음 등)</td>
</tr>
<tr>
<td><code>radius</code></td>
<td><code>(float)</code></td>
<td>에이전트 회피 반경</td>
</tr>
<tr>
<td><code>remainingDistance</code></td>
<td><code>(float)</code></td>
<td>목적지까지 남은 거리 (읽기 전용)</td>
</tr>
<tr>
<td><code>speed</code></td>
<td><code>(float)</code></td>
<td>최대 이동 속도</td>
</tr>
<tr>
<td><code>steeringTarget</code></td>
<td><code>(Vector3)</code></td>
<td>현재 경로 목표 위치 (읽기 전용)</td>
</tr>
<tr>
<td><code>stoppingDistance</code></td>
<td><code>(float)</code></td>
<td>목적지에서 멈출 거리</td>
</tr>
<tr>
<td><code>updatePosition</code></td>
<td><code>(bool)</code></td>
<td>Transform 위치 자동 업데이트 여부</td>
</tr>
<tr>
<td><code>updateRotation</code></td>
<td><code>(bool)</code></td>
<td>Transform 회전 자동 업데이트 여부</td>
</tr>
<tr>
<td><code>velocity</code></td>
<td><code>(Vector3)</code></td>
<td>현재 속도</td>
</tr>
</tbody></table>
<hr>
<h2 id="주요-메서드-public-methods">주요 메서드 (Public Methods)</h2>
<table>
<thead>
<tr>
<th>메서드명</th>
<th>반환값 (Type)</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>SetDestination(Vector3 targetPos)</code></td>
<td><code>(bool)</code></td>
<td>이동 목적지 설정 및 경로 탐색 시작</td>
</tr>
<tr>
<td><code>ResetPath()</code></td>
<td><code>(void)</code></td>
<td>현재 경로 삭제</td>
</tr>
<tr>
<td><code>CalculatePath(Vector3 targetPos, NavMeshPath path)</code></td>
<td><code>(bool)</code></td>
<td>특정 위치까지 경로 직접 계산하여 <code>path</code>에 저장</td>
</tr>
<tr>
<td><code>Move(Vector3 offset)</code></td>
<td><code>(void)</code></td>
<td>현재 위치에서 상대 이동량 적용</td>
</tr>
<tr>
<td><code>Warp(Vector3 newPosition)</code></td>
<td><code>(bool)</code></td>
<td>지정 위치로 즉시 이동 (물리적 이동X)</td>
</tr>
<tr>
<td><code>FindClosestEdge(out NavMeshHit hit)</code></td>
<td><code>(bool)</code></td>
<td>주변 NavMesh 가장자리 위치 탐색</td>
</tr>
<tr>
<td><code>SamplePathPosition(NavMeshPathStatus status, float distance, out NavMeshHit hit)</code></td>
<td><code>(bool)</code></td>
<td>경로를 따라 특정 거리 위치 샘플링</td>
</tr>
<tr>
<td><code>GetAreaCost(int areaIndex)</code></td>
<td><code>(float)</code></td>
<td>특정 NavMesh 영역 비용 조회</td>
</tr>
<tr>
<td><code>SetAreaCost(int areaIndex, float cost)</code></td>
<td><code>(void)</code></td>
<td>특정 NavMesh 영역 비용 설정</td>
</tr>
<tr>
<td><code>ActivateCurrentOffMeshLink(bool activate)</code></td>
<td><code>(void)</code></td>
<td>OffMeshLink 자동 이동 활성화/비활성화</td>
</tr>
<tr>
<td><code>CompleteOffMeshLink()</code></td>
<td><code>(void)</code></td>
<td>OffMeshLink 이동 강제 완료</td>
</tr>
</tbody></table>
<hr>
<p>2D 환경에서 단기간안에 몬스터 이동구현을 어떻게 해야하나 고민하고 있었는데
마침 머릿속에 스쳐지나간 navmesh2D덕분에 살았다.
이번에 학습을 해두었으니 앞으로 급할때 자주 사용하는 라이브러리가 될 것 같다.
내일은 탄막패턴을 만들어야해서 탄막을 공부할 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[25.07.28)개인과제 트러블슈팅]]></title>
            <link>https://velog.io/@dev_heoyoon/%ED%8A%B8%EB%9F%AC%EB%B8%94%EC%8A%88%ED%8C%85</link>
            <guid>https://velog.io/@dev_heoyoon/%ED%8A%B8%EB%9F%AC%EB%B8%94%EC%8A%88%ED%8C%85</guid>
            <pubDate>Sun, 27 Jul 2025 06:43:08 GMT</pubDate>
            <description><![CDATA[<p>NewtonSoft.Json을 사용하여 객체를 파싱하는 작업 도중 테이블이 제대로 출력되지 않는 이슈를 발견하였습니다.</p>
<p><img src="https://velog.velcdn.com/images/dev_heoyoon/post/ce59a0f7-dcc1-4082-ba45-565716882988/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/dev_heoyoon/post/1a10792d-eba8-46d7-99f7-5147c3ed4e19/image.png" alt=""></p>
<blockquote>
<p>위)역직렬화를 받을 객체
아래)직렬화된 원본 데이터(Json)</p>
</blockquote>
<p>일단 정상파싱이 되지 않는 케이스는 크게 두가지를 염두하고 있었습니다.
1.데이터의 이름이 올바르지 않다.
2.객체 타입이 올바르지 않다.
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/b59f12db-c119-4051-83db-677aad5c2035/image.png" alt="">
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/390690ad-ca9a-4f39-a783-d9955ebc18dd/image.png" alt="">
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/276f0634-9e27-47ec-9e2c-cb4371b8a116/image.png" alt="">
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/c02db135-3165-42e8-9638-32c732616844/image.png" alt="">
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/cd18c8d9-3e63-4c3c-9b82-36a571f3c655/image.png" alt=""></p>
<blockquote>
<p>원인파악 프로세스</p>
</blockquote>
<ul>
<li><ol>
<li>중단점을 통해 Linq 쿼리문이 잘못되었는지 확인.<ul>
<li>확인하였으나 쿼리문의 문제 이전 역직렬화 과정에서 문제가 있음을 확인</li>
</ul>
</li>
</ol>
</li>
<li><ol start="2">
<li>역직렬화를 받아와야 할 객체가 비어있음을 확인<ul>
<li>엑셀데이터를 jsonData로 변환하였기에 Sheet라는 래핑 데이터가 상위에 있을것을 고려</li>
</ul>
</li>
</ol>
</li>
<li><ol start="3">
<li>역직렬화를 받아와야 할 객체를 DialogData에 DialogStruct 데이터를 배열형으로 선언하여 파싱받을 수 있도록 작업.<ul>
<li>하지만 또다시 변환되지 않아 dataTable에 문제가 있음을 확인</li>
</ul>
</li>
</ol>
</li>
<li><ol start="4">
<li>스프레드 시트로 작업을 하였는데 자동적으로 Sheet가 아닌 시트1라는 객체로 래핑되어있음을 최종 확인<ul>
<li>sheet로 변경하며 최종 수정 하여 문제 해결</li>
</ul>
</li>
</ol>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/dev_heoyoon/post/4399c81d-027e-40bf-baa0-227e1ed6db33/image.png" alt="">
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/61e73b01-ae90-43f4-9480-242c087d8a6d/image.png" alt=""></p>
<h1 id="마무리">마무리)</h1>
<ul>
<li>이번 트러블 슈팅에서 얻은 교훈은 3가지입니다.<ul>
<li>데이터의 구조를 잘 확인하는 습관을 가지자</li>
<li>저렇게 래핑되어있다면 시트가 길어질때 where절로 처리하기엔 부적합하므로 더 적합한 방법을 찾아봐야 함을 인지</li>
<li>코드,시트,데이터에서 반드시 오탈자 확인을 꼼꼼히 하자</li>
</ul>
</li>
</ul>
<p>이렇게 세가지로 마무리 지을 수 있겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[(25/07/25)역직렬화할 텍스트가 없다면?]]></title>
            <link>https://velog.io/@dev_heoyoon/250725%EC%97%AD%EC%A7%81%EB%A0%AC%ED%99%94%ED%95%A0-%ED%85%8D%EC%8A%A4%ED%8A%B8%EA%B0%80-%EC%97%86%EB%8B%A4%EB%A9%B4</link>
            <guid>https://velog.io/@dev_heoyoon/250725%EC%97%AD%EC%A7%81%EB%A0%AC%ED%99%94%ED%95%A0-%ED%85%8D%EC%8A%A4%ED%8A%B8%EA%B0%80-%EC%97%86%EB%8B%A4%EB%A9%B4</guid>
            <pubDate>Fri, 25 Jul 2025 11:35:40 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/dev_heoyoon/post/1defe938-b970-4fe6-828c-eaa09ae56d9e/image.png" alt="">
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/5e906023-9c41-4602-a2bd-9f1f5782d5a8/image.png" alt="">
어제까지만 해도 잘 되던 Json역직렬화가 갑자기 안된다..!
처음엔 path 오류인가 싶었다가 저장된 폴더를 확인해보니
메모장이 비어있었고 뒤늦게나마 오류메세지를 자세히 보니 nullable한 오브젝트가 아니어서 발생한
오류라는데...</p>
<p>혹시 텍스트파일이 피어져있나 확인차 파일을 확인해보니...
<img src="https://velog.velcdn.com/images/dev_heoyoon/post/e635a2ee-eebf-481b-bee4-ef2be03b8567/image.png" alt="">
역직렬화 할 Json파일의 내용이 보이지 않는다!</p>
<h1 id="즉-데이터가-없어서-발생한-오류인것">즉 데이터가 없어서 발생한 오류인것</h1>
<p><img src="https://velog.velcdn.com/images/dev_heoyoon/post/655af60b-b8a7-440a-ae67-bb6ef5365c64/image.png" alt="">
역직렬화를 하는 순간 오류가 발생하기에 이를 막으려면
try catch문으로 제어할 수 있겠다고 생각하여 추가하니
제대로 추가가 되었다.</p>
<p>또한 객체 저장 시
SpriteAtlass에서 긁어온 sprite의 이름을 저장시</p>
<pre><code>{&quot;hairName&quot;:&quot;Hair_8(Clone)&quot;,&quot;beardName&quot;:&quot;FaceHair_1(Clone)&quot;}</code></pre><p>위와같이 표기되는데
저장 함수에 Replace해주니 해결되었다.
검색을 해보니 다른 오브젝트와 충돌하는것을 막기 위해 clone으로 가져온다고 한다.</p>
<p>코드에서 잔실수가 많고 이 때문에 시간소모가 의외로 많이 되었다.
키값 확인,데이터 확인은 꼭 1순위로 확인해야 할 것 같다.</p>
]]></description>
        </item>
    </channel>
</rss>