<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Unity Archives - 어제와 내일의 나 그 사이의 이야기</title>
	<atom:link href="https://lycos7560.com/category/unity/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>생각의 흐름을 타고 다니며 만드는 블로그</description>
	<lastBuildDate>Tue, 10 Feb 2026 21:02:50 +0000</lastBuildDate>
	<language>ko-KR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://lycos7560.com/wp-content/uploads/2022/11/cropped-cropped-cropped-log-1-150x150-1-80x80.png</url>
	<title>Unity Archives - 어제와 내일의 나 그 사이의 이야기</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Unity Package Manager &#8220;Invalid Signature&#8221;</title>
		<link>https://lycos7560.com/unity/unity-package-manager-invalid-signature/40434/</link>
					<comments>https://lycos7560.com/unity/unity-package-manager-invalid-signature/40434/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Tue, 10 Feb 2026 21:02:46 +0000</pubDate>
				<category><![CDATA[Unity]]></category>
		<category><![CDATA[개인 공부 저장용]]></category>
		<category><![CDATA[기타]]></category>
		<category><![CDATA[error]]></category>
		<category><![CDATA[Invalid Signature]]></category>
		<category><![CDATA[Manager]]></category>
		<category><![CDATA[package]]></category>
		<category><![CDATA[Package Manager]]></category>
		<category><![CDATA[study]]></category>
		<category><![CDATA[공부]]></category>
		<category><![CDATA[기초]]></category>
		<category><![CDATA[버그]]></category>
		<category><![CDATA[유나티]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=40434</guid>

					<description><![CDATA[<p>문제 상황 Unity 에디터의 Package Manager에서 Services Core 패키지가 빨간색 경고와 함께 &#8220;Invalid Signature&#8221; 표시 광고 초기화 실패(Gateway communication failure) 등의 문제가 발생 이는 패키지 자체의 손상이 아니라 Package Manager의 서명 검증 시스템 오류 오류의 의미와 영향 Package Manager의 서명 검증 실패 Unity Package Manager는 모든 패키지의 디지털 서명을 확인하는 검증 메커니즘을 가지고 있 &#8220;Invalid [&#8230;]</p>
<p>The post <a href="https://lycos7560.com/unity/unity-package-manager-invalid-signature/40434/">Unity Package Manager &#8220;Invalid Signature&#8221;</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-31667817      "
					data-scroll= "1"
					data-offset= "30"
					style=""
				>
				<div class="uagb-toc__wrap">
						<div class="uagb-toc__title">
							목차						</div>
																						<div class="uagb-toc__list-wrap ">
						<ol class="uagb-toc__list"><li class="uagb-toc__list"><a href="#문제-상황" class="uagb-toc-link__trigger">문제 상황</a><li class="uagb-toc__list"><a href="#오류의-의미와-영향" class="uagb-toc-link__trigger">오류의 의미와 영향</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#package-manager의-서명-검증-실패" class="uagb-toc-link__trigger">Package Manager의 서명 검증 실패</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#unity-ads-초기화-실패와의-연결" class="uagb-toc-link__trigger">Unity Ads 초기화 실패와의 연결</a></li></ul></li><li class="uagb-toc__list"><a href="#해결-방법-개인적인" class="uagb-toc-link__trigger">해결 방법 (개인적인)</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#package-manager-캐시-삭제" class="uagb-toc-link__trigger">Package Manager 캐시 삭제</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#reset-packages-to-defaults-마지막-수단" class="uagb-toc-link__trigger">Reset Packages to Defaults (마지막 수단)</a></ul></ul></ol>					</div>
									</div>
				</div>
			


<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">문제 상황</h2>



<p>Unity 에디터의 Package Manager에서 <strong>Services Core 패키지가 빨간색 경고와 함께 &#8220;Invalid Signature&#8221;</strong> 표시</p>



<p>광고 초기화 실패(<code>Gateway communication failure</code>) 등의 문제가 발생</p>



<p>이는 패키지 자체의 손상이 아니라 <strong>Package Manager의 서명 검증 시스템 오류</strong></p>



<figure class="wp-block-image size-full"><img fetchpriority="high" decoding="async" width="828" height="320" src="https://lycos7560.com/wp-content/uploads/2026/02/image.png" alt="" class="wp-image-40435" srcset="https://lycos7560.com/wp-content/uploads/2026/02/image.png 828w, https://lycos7560.com/wp-content/uploads/2026/02/image-300x116.png 300w, https://lycos7560.com/wp-content/uploads/2026/02/image-768x297.png 768w" sizes="(max-width: 828px) 100vw, 828px" /></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">오류의 의미와 영향</h2>



<h3 class="wp-block-heading">Package Manager의 서명 검증 실패</h3>



<p>Unity Package Manager는 모든 패키지의 디지털 서명을 확인하는 검증 메커니즘을 가지고 있</p>



<p>&#8220;Invalid Signature&#8221;는 <strong>Package Manager의 서명 검증 로직이 정상적인 패키지를 잘못 거부하는 버그</strong></p>



<p>실제 패키지는 정상이지만, Package Manager가 잘못된 판단을 내리고 있는 상태로 생각됨</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">Unity Ads 초기화 실패와의 연결</h3>



<p>Services Core는 단순한 라이브러리가 아니라 <strong>Unity Ads를 포함한 모든 유니티 서비스의 핵심 패키지</strong>입니다. </p>



<p>이 패키지가 손상되면:</p>



<ul class="wp-block-list">
<li>Unity Ads 초기화 실패 <code>Gateway communication failure</code> 오류 발생 광고 로드 및 표시 불가 기타 Unity Services(Analytics, Crash Reporting 등) 동작 불능</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">해결 방법 (개인적인)</h2>



<h3 class="wp-block-heading">Package Manager 캐시 삭제 </h3>



<p>로컬에 저장된 손상된 패키지 캐시를 강제로 삭제</p>



<p><strong>Unity 에디터를 완전히 종료</strong>합니다 다음 폴더로 이동:</p>



<ul class="wp-block-list">
<li><strong>Windows</strong>: <code>%AppData%/Local/Unity/cache/upm</code></li>



<li><strong>Mac</strong>: <code>~/Library/Caches/Unity/upm</code></li>



<li><strong>Linux</strong>: <code>~/.cache/unity/upm</code></li>
</ul>



<p><code>upm</code> 폴더 전체를 삭제합니다 </p>



<p>Unity 에디터를 다시 열면 Package Manager가 서버에서 패키지를 새로 다운로드하고 서명을 다시 검증</p>



<p><strong>주의</strong>: 이 작업은 안전하며, 폴더를 다시 열면 필요한 캐시가 자동으로 재생성됩니다.</p>



<h3 class="wp-block-heading">Reset Packages to Defaults (마지막 수단)</h3>



<p>프로젝트의 패키지 설정이 꼬인 경우 초기화가 필요합니다.</p>



<p>Unity 상단 메뉴: Help &gt; Reset Packages to defaults 선택</p>



<p>확인 대화상자에서 &#8220;Yes&#8221; 클릭</p>



<p>프로젝트의 manifest.json이 기본값으로 되돌려집니다</p>



<p>주의: 이 작업은 프로젝트의 패키지 설정을 초기화하므로:</p>



<p>수동으로 추가했던 다른 패키지가 있다면 다시 설치해야 합니다</p>



<p>Packages/manifest.json 파일이 변경됩니다</p>



<p></p>
<p>The post <a href="https://lycos7560.com/unity/unity-package-manager-invalid-signature/40434/">Unity Package Manager &#8220;Invalid Signature&#8221;</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/unity/unity-package-manager-invalid-signature/40434/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Unity 해상도 대응 코드</title>
		<link>https://lycos7560.com/unity/unity-%ed%95%b4%ec%83%81%eb%8f%84-%eb%8c%80%ec%9d%91-%ec%bd%94%eb%93%9c/40427/</link>
					<comments>https://lycos7560.com/unity/unity-%ed%95%b4%ec%83%81%eb%8f%84-%eb%8c%80%ec%9d%91-%ec%bd%94%eb%93%9c/40427/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Wed, 07 Jan 2026 09:47:17 +0000</pubDate>
				<category><![CDATA[Unity]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=40427</guid>

					<description><![CDATA[<p>The post <a href="https://lycos7560.com/unity/unity-%ed%95%b4%ec%83%81%eb%8f%84-%eb%8c%80%ec%9d%91-%ec%bd%94%eb%93%9c/40427/">Unity 해상도 대응 코드</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using UnityEngine;
using UnityEngine.UI;
using GoogleMobileAds.Api;

[RequireComponent(typeof(CanvasScaler))]
public class CanvasResolutionController : MonoBehaviour
{
    private GoogleAdMobManager AdManager => GoogleAdMobManager.Instance;
    private CanvasScaler _CanvasScaler;

    private RectTransform safeAreaWrapper;
    private RectTransform uiContainer;
    private RectTransform adBannerSpace;
    private RectTransform contentArea;

    private const float TARGET_ASPECT = 1440f / 2560f; // 9:16

    // 캐싱
    private Rect lastSafeArea; 
    private Vector2 lastScreenSize;
    private bool lastAdStatus;
    // ------------------

    void Awake()
    {
        _CanvasScaler = GetComponent&lt;CanvasScaler>();
        _CanvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
        _CanvasScaler.referenceResolution = new Vector2(1440, 2560);
        _CanvasScaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight;

        CreateUIHierarchy();

        if (AdManager != null)
            AdManager.OnBannerAdLoaded += ApplySafeLayout;
    }

    void Start() => ApplySafeLayout();

    void LateUpdate()
    {
        if (CheckForChanges())
        {
            ApplySafeLayout();
        }
    }

    /// &lt;summary>
    /// 레이아웃 업데이트가 필요한 변화가 있는지 확인
    /// &lt;/summary>
    private bool CheckForChanges()
    {
        bool isChanged = false;

        // 1. 화면 해상도 체크
        if (Screen.width != lastScreenSize.x || Screen.height != lastScreenSize.y)
        {
            lastScreenSize = new Vector2(Screen.width, Screen.height);
            isChanged = true;
        }

        // 2. Safe Area 체크
        if (Screen.safeArea != lastSafeArea)
        {
            lastSafeArea = Screen.safeArea;
            isChanged = true;
        }

        // 3. 광고 로드 상태 체크
        bool currentAdStatus = (AdManager != null &amp;&amp; AdManager.IsBannerLoaded);
        if (currentAdStatus != lastAdStatus)
        {
            lastAdStatus = currentAdStatus;
            isChanged = true;
        }

        return isChanged;
    }

    void CreateUIHierarchy()
    {
        safeAreaWrapper = CreateRectElement("Safe_Area_Wrapper", transform);
        uiContainer = CreateRectElement("UI_Container", safeAreaWrapper);
        adBannerSpace = CreateRectElement("AdBannerSpace", uiContainer);
        contentArea = CreateRectElement("ContentArea", uiContainer);

        var fitter = contentArea.gameObject.AddComponent&lt;AspectRatioFitter>();
        fitter.aspectRatio = TARGET_ASPECT;
        fitter.aspectMode = AspectRatioFitter.AspectMode.FitInParent;
        fitter.enabled = true;
    }

    public void ApplySafeLayout()
    {
        if (safeAreaWrapper == null || contentArea == null) return;

        Rect safe = Screen.safeArea;
        float sw = Screen.width;
        float sh = Screen.height;

        // 1. Safe Area 적용
        safeAreaWrapper.anchorMin = new Vector2(safe.x / sw, safe.y / sh);
        safeAreaWrapper.anchorMax = new Vector2((safe.x + safe.width) / sw, (safe.y + safe.height) / sh);
        ResetOffsets(safeAreaWrapper);

        // 2. 광고 높이 계산
        float adHeightPx = lastAdStatus ? GetAdBannerHeightInPixels() : 0f;
        float adHeightNormalized = adHeightPx / safe.height;

        // 3. 광고 및 콘텐츠 영역 분할
        adBannerSpace.anchorMin = new Vector2(0, 1 - adHeightNormalized);
        adBannerSpace.anchorMax = new Vector2(1, 1);
        ResetOffsets(adBannerSpace);

        contentArea.anchorMin = Vector2.zero;
        contentArea.anchorMax = new Vector2(1, 1 - adHeightNormalized);
        ResetOffsets(contentArea);

        // 4. 동적 Match 수정
        UpdateCanvasMatch(safe.width, safe.height - adHeightPx);

        Debug.Log($"[LayoutUpdate] Match: {_CanvasScaler.matchWidthOrHeight}, AdHeight: {adHeightPx}");
    }

    private void UpdateCanvasMatch(float availableW, float availableH)
    {
        if (availableW &lt;= 0 || availableH &lt;= 0) return;

        float availableAspect = availableW / availableH;

        // 가로가 남는 환경(패드) -> 세로에 맞춤
        if (availableAspect > TARGET_ASPECT)
        {
            _CanvasScaler.matchWidthOrHeight = 1f;
        }
        else // 세로가 남는 환경(플립) -> 가로에 맞춤
        {
            _CanvasScaler.matchWidthOrHeight = 0f;
        }
    }

    private RectTransform CreateRectElement(string name, Transform parent)
    {
        GameObject obj = new GameObject(name, typeof(RectTransform));
        obj.transform.SetParent(parent, false);
        RectTransform rt = obj.GetComponent&lt;RectTransform>();
        rt.anchorMin = Vector2.zero;
        rt.anchorMax = Vector2.one;
        ResetOffsets(rt);
        return rt;
    }

    private void ResetOffsets(RectTransform rt) => rt.offsetMin = rt.offsetMax = Vector2.zero;

    private float GetAdBannerHeightInPixels()
    {
        int widthInDp = MobileAds.Utils.GetDeviceSafeWidth();
        AdSize adaptiveSize = AdSize.GetCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(widthInDp);
        return (float)adaptiveSize.Height * Screen.dpi / 160f;
    }

    void OnDestroy()
    {
        if (AdManager != null)
            AdManager.OnBannerAdLoaded -= ApplySafeLayout;
    }
}</pre>
<p>The post <a href="https://lycos7560.com/unity/unity-%ed%95%b4%ec%83%81%eb%8f%84-%eb%8c%80%ec%9d%91-%ec%bd%94%eb%93%9c/40427/">Unity 해상도 대응 코드</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/unity/unity-%ed%95%b4%ec%83%81%eb%8f%84-%eb%8c%80%ec%9d%91-%ec%bd%94%eb%93%9c/40427/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Unity Netcode for Entities – Synchronizing states and inputs (1)</title>
		<link>https://lycos7560.com/unity/unity-netcode-for-entities-synchronizing-states-and-inputs-1/40012/</link>
					<comments>https://lycos7560.com/unity/unity-netcode-for-entities-synchronizing-states-and-inputs-1/40012/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Sun, 04 May 2025 11:00:58 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Unity]]></category>
		<category><![CDATA[study]]></category>
		<category><![CDATA[공부]]></category>
		<category><![CDATA[기초]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=40012</guid>

					<description><![CDATA[<p>🔥 Synchronizing states and inputs Netcode for Entities 1.5.0v Ghosts, Commands, RPC를 사용해 서버와 클라이언트 간 상태 및 입력 동기화합니다. 주제 설명 1️⃣ Ghosts를 이용한 동기화 유령(Ghost)을 사용하면 서버와 클라이언트 간 상태를 일관되면서도 유연하게 동기화하고 복제할 수 있습니다. 2️⃣ RPC(Remote Procedure Call)를 통한 통신 원격 프로시저 호출(RPC)은 게임의 상위 흐름 이벤트를 전달하거나 클라이언트에서 서버로 예측되지 [&#8230;]</p>
<p>The post <a href="https://lycos7560.com/unity/unity-netcode-for-entities-synchronizing-states-and-inputs-1/40012/">Unity Netcode for Entities – Synchronizing states and inputs (1)</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-cbe7176c      "
					data-scroll= "1"
					data-offset= "30"
					style=""
				>
				<div class="uagb-toc__wrap">
						<div class="uagb-toc__title">
							목차						</div>
																						<div class="uagb-toc__list-wrap ">
						<ol class="uagb-toc__list"><li class="uagb-toc__list"><a href="#synchronizing-states-and-inputs" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Synchronizing states and inputs</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-ghosts를-이용한-동기화" class="uagb-toc-link__trigger">1&#x20e3; Ghosts를 이용한 동기화</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#ghosts-and-snapshots" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Ghosts and snapshots</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#ghosts" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Ghosts</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#create-a-ghost" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Create a ghost</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#supported-ghost-modeoptions-지원되는-고스트-모드" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Supported Ghost Mode options (지원되는 고스트 모드)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#default-ghost-mode-기본-고스트-모드" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Default Ghost Mode (기본 고스트 모드)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#optimization-mode-최적화-모드" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Optimization Mode (최적화 모드)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#synchronize-ghost-components-and-fields" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Synchronize ghost components and fields</a></li></ul><li class="uagb-toc__list"><a href="#snapshots" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Snapshots</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#snapshots-처리" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Snapshots 처리</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#부분-snapshots" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 부분 Snapshots</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#snapshots-시각화-도구" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Snapshots 시각화 도구</a></li></ul></li></ul><li class="uagb-toc__list"><a href="#ghostfieldattribute를-활용한-필드-동기화-및-직렬" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> GhostFieldAttribute를 활용한 필드 동기화 및 직렬</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#ghostfieldattribute-직렬화-사용자-지정" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> GhostFieldAttribute 직렬화 사용자 지정</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#ghostfield-상속" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> GhostField 상속</a></li></ul><li class="uagb-toc__list"><a href="#component-serialization" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Component serialization</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#dynamic-buffer-serialization" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Dynamic buffer serialization</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#icommanddata-및-iinputcomponentdata-직렬화" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> ICommandData 및 IInputComponentData 직렬화</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#사용자-지정-타입에-대한-직렬화-지원-추가" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 사용자 지정 타입에 대한 직렬화 지원 추가</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#추가-리소스" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 추가 리소스</a></li></ul><li class="uagb-toc__list"><a href="#ghostcomponentattribute를-사용한-복제-사용자-지정" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> GhostComponentAttribute를 사용한 복제 사용자 지정</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#ghostcomponentattribute-속성" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> GhostComponentAttribute 속성</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#ownersendtype-세부-정보" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> OwnerSendType 세부 정보</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#prefabtype-세부-정보" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> PrefabType 세부 정보</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#senddataforchildentity-세부-정보" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> SendDataForChildEntity 세부 정보</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#sendtypeoptimization-세부-정보" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> SendTypeOptimization 세부 정보</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#추가-리소스" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 추가 리소스</a></ul></ul></ul></ol>					</div>
									</div>
				</div>
			


<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h1 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Synchronizing states and inputs</h1>



<p><strong>Netcode for Entities 1.5.0v</strong></p>



<p><strong>Ghosts, Commands, RPC</strong>를 사용해 서버와 클라이언트 간 상태 및 입력 동기화합니다.</p>



<figure class="wp-block-table"><table><thead><tr><th>주제</th><th>설명</th></tr></thead><tbody><tr><td>1&#x20e3; <strong>Ghosts를 이용한 동기화</strong></td><td>유령(Ghost)을 사용하면 서버와 클라이언트 간 상태를 일관되면서도 유연하게 동기화하고 복제할 수 있습니다.</td></tr><tr><td>2&#x20e3; <strong>RPC(Remote Procedure Call)를 통한 통신</strong></td><td>원격 프로시저 호출(RPC)은 게임의 상위 흐름 이벤트를 전달하거나 클라이언트에서 서버로 예측되지 않은 단발성 명령을 보낼 때 사용됩니다.</td></tr><tr><td>3&#x20e3; <strong><strong>Commands</strong></strong> <strong>Stream을 통한 입력 처리</strong></td><td>클라이언트는 <code><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.NetworkStreamConnection.html" target="_blank" rel="noreferrer noopener"><code>NetworkStreamConnection</code></a></strong></code>이 인게임 상태로 설정되면 서버로 연속적인 <strong><strong>Commands</strong></strong> <strong>Stream</strong>을 보냅니다.<br>이 <strong>Stream</strong>에는 모든 입력 정보와 마지막으로 수신한 스냅샷에 대한 확인 응답이 포함됩니다.</td></tr></tbody></table></figure>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">1&#x20e3; <strong>Ghosts를 이용한 동기화</strong></h2>



<p><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/synchronization.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/synchronization.html</a></p>



<p><strong>Ghosts</strong>를 사용하여 서버와 클라이언트 간 상태를 일관되고 커스터마이징 가능하게 동기화 및 복제하는 방법입니다.</p>



<figure class="wp-block-table"><table><thead><tr><th>주제</th><th>설명</th></tr></thead><tbody><tr><td><strong><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html" target="_blank" rel="noreferrer noopener">Ghosts and snapshots</a></strong></strong></td><td>Netcode for Entities에서 Ghost과 스냅샷(snapshot)이 무엇인지, 그리고 이를 멀티플레이어 프로젝트에서 상태 동기화에 어떻게 사용하는지를 이해합니다.</td></tr><tr><td><strong><strong><strong><strong><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghostfield-synchronize.html" target="_blank" rel="noreferrer noopener">GhostFieldAttribute</a></code></strong></strong></strong></strong>를 통한<br><strong><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghostfield-synchronize.html" target="_blank" rel="noreferrer noopener">Serialization and synchronization</a></strong></strong></td><td><code><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostFieldAttribute.html" target="_blank" rel="noreferrer noopener">GhostFieldAttribute</a></strong></code>를 사용하여 <br><code><strong><a href="https://docs.unity3d.com/Packages/com.unity.entities@latest?subfolder=/api/Unity.Entities.IComponentData.html" target="_blank" rel="noreferrer noopener">Unity.Entities.IComponentData</a></strong></code> 또는 <code><strong><a href="https://docs.unity3d.com/Packages/com.unity.entities@latest?subfolder=/api/Unity.Entities.IBufferElementData.html" target="_blank" rel="noreferrer noopener">Unity.Entities.IBufferElementData</a></strong></code>의 어떤 필드와 속성이 서버에서 클라이언트로 직렬화 및 복제되어야 하는지를 지정합니다.</td></tr><tr><td><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghostcomponentattribute.html"><code>GhostComponentAttribute</code></a>를 통한 복제 커스터마이징</strong></td><td><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostComponentAttribute.html" target="_blank" rel="noreferrer noopener"><strong>GhostComponentAttribute</strong></a></code>와 그 속성들을 사용하여 런타임에서 복제가 어떻게 처리되는지를 커스터마이징할 수 있습니다.</td></tr><tr><td><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-variants.html" target="_blank" rel="noreferrer noopener">GhostComponentVariationAttribute</a>로 복제 스키마 생성</strong></td><td><code><code><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostComponentVariationAttribute.html" target="_blank" rel="noreferrer noopener">GhostComponentVariationAttribute</a></strong></code></code>를 사용하면 원본 타입이나 필드를 수정하지 않고도 특정 타입에 대해 (컴파일 타임에) 복제 스키마를 정의할 수 있습니다.</td></tr><tr><td><strong><a href="http://Spawning and pre-spawning ghosts" target="_blank" rel="noreferrer noopener">Ghost 생성 및 미리 생성</a></strong></td><td><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></strong>을 게임의 일환으로 생성한 후, 이들이 어떻게 <a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#synchronizing-ghost-components-and-fields" target="_blank" rel="noreferrer noopener">동기화</a>되어야 하는지를 정의한 뒤 Spawn합니다.</td></tr><tr><td><strong><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-types-templates.html" target="_blank" rel="noreferrer noopener">Ghost type templates</a></strong></strong></td><td>Netcode for Entities는 고스트 컴포넌트 타입들이 <a href="https://docs.unity3d.com/Packages/com.unity.entities@latest?subfolder=/manual/baking-overview.html" target="_blank" rel="noreferrer noopener">베이킹(baking)</a> 및 직렬화 과정에서 어떻게 처리될지를 정의하는 기본 템플릿을 제공합니다. <br>또한 사용자 정의 템플릿을 만들어 추가 타입을 등록할 수도 있습니다.</td></tr><tr><td><strong><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-groups.html" target="_blank" rel="noreferrer noopener">Ghost groups</a></strong></strong></td><td>고스트 그룹을 사용하여 여러 고스트 인스턴스 간의 복제 타이밍을 동기화하고, 일반적인 게임플레이 상태 오류를 방지할 수 있습니다.</td></tr></tbody></table></figure>



<div style="height:70px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Ghosts and snapshots</h3>



<p><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html</a></p>



<p>Netcode for Entities에서 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghosts</a></code>와 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#snapshots" target="_blank" rel="noreferrer noopener">Snapshots</a></code>을 이해하고, 멀티플레이어 프로젝트에서 상태를 동기화하는 방법에 대한 내용입니다.</p>



<p>Netcode for Entities는 이벤트를 처리하기 위한 제한적인 형태의 원격 프로시저 호출(RPC) 기능도 지원합니다. </p>



<p>Ghost와 RPC 중 언제 어떤 기능을 사용할지에 대해서는 <a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/rpcs.html#comparing-ghosts-and-rpcs" target="_blank" rel="noreferrer noopener">[RPC  비교]</a>를 참고하세요.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Ghosts</h4>



<p><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code>는 멀티플레이어 게임에서 네트워크를 통해 동기화되는 오브젝트입니다.<br><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code>는 서버가 소유하고 시뮬레이션합니다. 즉, <strong>서버가 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code>에 대한 최종 권한(authority)</strong> 을 가지며, <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code>를 생성, 제거, 업데이트할 수 있습니다.</p>



<p>서버에 연결된 각 클라이언트는 해당 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code>의 복사본을 가지며, 서버가 매 네트워크 틱마다 보내는 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#snapshots" target="_blank" rel="noreferrer noopener">Snapshots</a></code>을 통해 해당 복사본을 업데이트합니다. <br>이 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#snapshots" target="_blank" rel="noreferrer noopener">Snapshots</a></code>은 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code> 상태의 일부를 포함합니다.</p>



<p>클라이언트는 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code>의 상태를 두 가지 타임라인(보간 또는 예측) 중 하나를 통해 게임 시뮬레이션에 반영하며, 이를 통해 부드러운 렌더링이 가능합니다.</p>



<p>중요한 점은, 클라이언트는 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code>를 직접 제어하거나 변경할 수 없습니다. <br>게임 시뮬레이션은 <strong>서버가 권한을 가지므로</strong>, 클라이언트가 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code>를 수정하더라도 이는 <strong>클라이언트 예측(Client Prediction)</strong> 으로 간주되며, 서버에서 보내는 새로운 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#snapshots" target="_blank" rel="noreferrer noopener">Snapshots</a></code>에 의해 되돌려질 수 있습니다.</p>



<p><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code>를 생성할 때는 클라이언트와 서버 간 <strong>동기화 방식을 정의</strong>해야 합니다. 생성 후 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code>를 스폰하는 방법은 <a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghost-spawning.md" target="_blank" rel="noreferrer noopener">Ghost Spawning</a> 페이지를 참고하세요.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Create a ghost</h5>



<p>Unity 에디터에서 <strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.GhostAuthoringComponent.html" target="_blank" rel="noreferrer noopener">GhostAuthoringComponent</a></strong>가 포함된 프리팹을 생성하여 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code>를 만들 수 있습니다.</p>



<p><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.GhostAuthoringComponent.html" target="_blank" rel="noreferrer noopener">GhostAuthoringComponent</a></strong>는 프리팹의 동기화 방식을 구성할 수 있는 에디터 UI를 제공합니다. 다음과 같은 속성들을 설정해야 합니다:</p>



<ul class="wp-block-list">
<li><strong>Name (이름)</strong></li>



<li><strong>Importance (중요도)</strong></li>



<li><strong>Supported Ghost Mode (지원되는 고스트 모드)</strong></li>



<li><strong>Default Ghost Mode (기본 고스트 모드)</strong></li>



<li><strong>Optimization Mode (최적화 모드)</strong></li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="394" height="339" src="https://lycos7560.com/wp-content/uploads/2025/05/image-7.png" alt="" class="wp-image-40013" srcset="https://lycos7560.com/wp-content/uploads/2025/05/image-7.png 394w, https://lycos7560.com/wp-content/uploads/2025/05/image-7-300x258.png 300w" sizes="(max-width: 394px) 100vw, 394px" /><figcaption class="wp-element-caption"><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.GhostAuthoringComponent.html" target="_blank" rel="noreferrer noopener">GhostAuthoringComponent</a></strong></figcaption></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>또한 <strong>MaxSendRate</strong> 값을 설정하면 전체 대역폭 사용량을 줄일 수 있습니다.</p>



<p>Importance 값은 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#snapshots" target="_blank" rel="noreferrer noopener">Snapshots</a></code>에 포함시킬 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code>를 선택할 때 우선 순위를 정하는 데 사용됩니다. </p>



<p><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#snapshots" target="_blank" rel="noreferrer noopener">Snapshots</a></code> 패킷의 크기는 설정으로 조정할 수 있습니다.</p>



<p><strong>MaxSendRate (최대 전송 속도)</strong>는 해당 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code> 프리팹 타입의 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code> Chunk가 초당 몇 회 전송될 수 있는지를 나타냅니다 (단위: Hz)</p>



<p>이는 <strong>전송 가능 최대 빈도</strong>를 의미할 뿐, 다른 요인들에 의해 제한될 수 있습니다.</p>



<p>예를 들어 아래와 같은 상황이 있다면</p>



<p>MaxSendRate가 100Hz인 경우, 기본 NetworkTickRate(60Hz)에 의해 <strong>60Hz로 제한</strong>됩니다.</p>



<p>MaxSendRate가 60Hz인데 <strong>NetworkTickRate가 30Hz인 경우, 30Hz가 최대 전송 속도</strong>입니다.</p>



<p>30Hz NetworkTickRate에 45Hz MaxSendRate를 설정하면, 실제 전송 속도는 <strong>30Hz로 내림(round down)</strong>됩니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Supported Ghost Mode</strong>&nbsp;options (지원되는 고스트 모드)</h5>



<ul class="wp-block-list">
<li><strong>All</strong>: 보간(Interpolated)과 예측(Predicted)을 모두 지원</li>



<li><strong>Interpolated</strong>: 보간만 지원</li>



<li><strong>Predicted</strong>: 예측만 지원</li>
</ul>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Default Ghost Mode (기본 고스트 모드)</h5>



<ul class="wp-block-list">
<li><strong>Interpolated:</strong> 서버에서 받은 모든 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code>를 보간 처리</li>



<li><strong>Predicted:</strong> 서버에서 받은 모든 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code>를 예측 처리</li>



<li><strong>Owner Predicted</strong>: <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code>의 소유 클라이언트에게는 예측 처리, 그 외 클라이언트에게는 보간 처리<br>이 모드를 사용하려면 <strong><code>GhostOwner</code> 컴포넌트를 추가</strong>하고, 코드에서 <strong><code>NetworkId</code> 필드를 설정</strong>해야 합니다.</li>
</ul>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Optimization Mode (최적화 모드)</h5>



<ul class="wp-block-list">
<li><strong>Dynamic</strong>: 상태가 변할 때와 변하지 않을 때 모두 작은 스냅샷 크기로 최적화</li>



<li><strong>Static</strong>: 상태가 변하지 않을 때는 전송하지 않고, 상태가 변할 때는 최적화되지 않음</li>
</ul>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading" id="synchronize-ghost-components-and-fields"><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#synchronize-ghost-components-and-fields"></a><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Synchronize ghost components and fields</h5>



<p><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code>에 어떤 컴포넌트와 필드를 동기화할지 지정하려면 C# 특성(Attribute)을 사용합니다.</p>



<figure class="wp-block-table"><table><thead><tr><th>속성 (Attribute)</th><th>사용법 (Usage)</th><th>추가 정보 (More information)</th></tr></thead><tbody><tr><td><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.GhostFieldAttribute.html" target="_blank" rel="noreferrer noopener"><code>GhostFieldAttribute</code></a></code></td><td>구조체의 필드나 속성에 <code>GhostFieldAttribute</code>를 사용하여 어떤 컴포넌트(또는 버퍼) 필드를 직렬화할지 지정합니다. <br>어떤 컴포넌트든 하나 이상의 필드에 <code>[GhostField]</code>가 지정되면, 해당 컴포넌트는 복제되어 고스트 데이터의 일부로 전송됩니다.</td><td><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.2/manual/ghosts.html" target="_blank" rel="noreferrer noopener">GhostFieldAttribute를 사용한 직렬화 및 동기화</a></td></tr><tr><td><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.GhostEnabledBitAttribute.html" target="_blank" rel="noreferrer noopener"><code>GhostEnabledBitAttribute</code></a></code></td><td><code>IEnableableComponent</code> 구조체 정의에 <code>GhostEnabledBitAttribute</code>를 사용하여 이 컴포넌트의 &#8220;활성화 비트(enabled bit)&#8221;도 직렬화해야 함을 지정합니다.<br>이 속성이 지정되면 활성화 비트도 복제되어 고스트 데이터의 일부로 전송됩니다.</td><td><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.2/manual/ghosts.html#ghostcomponentattribute" target="_blank" rel="noreferrer noopener">GhostComponentAttribute</a></td></tr><tr><td><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.GhostComponentAttribute.html" target="_blank" rel="noreferrer noopener"><code>GhostComponentAttribute</code></a></code></td><td><code>ComponentType</code> 구조체 정의에 <code>GhostComponentAttribute</code>를 사용하여 다음을 선언합니다: <br>&#8211; 어떤 프리팹 버전에 이 컴포넌트가 포함될지 <br>&#8211; 자식 엔티티에 대해 이 컴포넌트를 직렬화할지 여부 <br>&#8211; 어떤 클라이언트 하위 집합에 이 컴포넌트를 복제할지 <br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" />주의: <code>GhostComponentAttribute</code>를 추가한다고 해서 컴포넌트의 필드가 자동으로 복제되지 않습니다. <br>각 필드에 <code>GhostFieldAttribute</code>를 개별적으로 지정해야 합니다.</td><td><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.2/manual/ghosts.html#ghostcomponentattribute" target="_blank" rel="noreferrer noopener">GhostComponentAttribute</a></td></tr></tbody></table></figure>



<div style="height:70px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Snapshots</h4>



<p><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#snapshots" target="_blank" rel="noreferrer noopener">Snapshots</a></code>은 특정 네트워크 틱에서 서버의 모든 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code> 상태를 나타내는 표현입니다.</p>



<p>엔티티용 Netcode는 각 연결된 클라이언트에 틱당 한 번씩 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#snapshots" target="_blank" rel="noreferrer noopener">Snapshots</a></code>을 전송하며, 이는 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.ClientServerTickRate.html#Unity_NetCode_ClientServerTickRate_NetworkTickRate" target="_blank" rel="noreferrer noopener"><code>NetworkTickRate</code></a></code>에 의해 정의된 속도로 이루어집니다(<code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.ClientServerTickRate.html#Unity_NetCode_ClientServerTickRate_SimulationTickRate" target="_blank" rel="noreferrer noopener"><code>SimulationTickRate</code></a></code>와 다를 수 있음). </p>



<p><code>NetworkTickRate</code>가 <code>SimulationTickRate</code>보다 낮을 경우, 엔티티용 Netcode는 연결의 하위 집합 그룹을 생성하고 하위 집합의 각 연결에 하나의 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#snapshots" target="_blank" rel="noreferrer noopener">Snapshots</a></code>을 전송합니다. </p>



<p>그 후 다음 틱에서 다음 하위 집합에 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#snapshots" target="_blank" rel="noreferrer noopener">Snapshots</a></code>을 전송하는 식으로 진행됩니다. </p>



<p>이는 <code>GhostSendSystem</code> 부하를 여러 <code>SimulationTickRate</code> 틱에 분산시키기 때문에 라운드 로빈 접근 방식이라고 합니다.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Snapshots 처리</h5>



<p><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code> 스냅샷 시스템은 서버에 존재하는 엔티티를 모든 클라이언트에 동기화합니다. </p>



<p>성능 향상을 위해 <strong>서버는 엔티티별이 아닌 <a href="https://docs.unity3d.com/Packages/com.unity.entities@1.3/manual/components-chunk.html" target="_blank" rel="noreferrer noopener">Chunk</a>별로 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code>를 처리합니다. </strong></p>



<p>그러나 <strong>수신 클라이언트 측에서는 엔티티별로 처리가 이루어집니다. </strong></p>



<p>서버의 한 <a href="https://docs.unity3d.com/Packages/com.unity.entities@1.3/manual/components-chunk.html" target="_blank" rel="noreferrer noopener">Chunk</a>에 있는 일련의 엔티티가 클라이언트의 한 <a href="https://docs.unity3d.com/Packages/com.unity.entities@1.3/manual/components-chunk.html" target="_blank" rel="noreferrer noopener">Chunk</a>에 있는 동일한 엔티티 집합과 일치하지 않을 수 있기 때문에 양쪽에서 <a href="https://docs.unity3d.com/Packages/com.unity.entities@1.3/manual/components-chunk.html" target="_blank" rel="noreferrer noopener">Chunk</a>별로 처리하는 것은 불가능합니다. </p>



<p>또한 각각 고유한 엔티티-<a href="https://docs.unity3d.com/Packages/com.unity.entities@1.3/manual/components-chunk.html" target="_blank" rel="noreferrer noopener">Chunk</a> 레이아웃을 가진 여러 클라이언트가 있습니다.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 부분 Snapshots </h5>



<p>많은 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code>(또는 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code> 데이터)를 복제할 때, 틱당 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#snapshots" target="_blank" rel="noreferrer noopener">Snapshots</a></code> 데이터 크기는 최대 전송 단위(MTU) 상한으로 제한됩니다. </p>



<p>그 결과, <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#snapshots" target="_blank" rel="noreferrer noopener">Snapshots</a></code>이 모든 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code>의 하위 집합만 포함하는 것은 일반적이고 예상된 일입니다. </p>



<p>이러한 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#snapshots" target="_blank" rel="noreferrer noopener">Snapshots</a></code>을 부분 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#snapshots" target="_blank" rel="noreferrer noopener">Snapshots</a></code>이라고 합니다. </p>



<p>중요도 값이 가장 높은 <a href="https://docs.unity3d.com/Packages/com.unity.entities@1.3/manual/components-chunk.html" target="_blank" rel="noreferrer noopener">Chunk</a>의 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#ghosts" target="_blank" rel="noreferrer noopener">Ghost</a></code>가 먼저 추가되며, 엔티티용 Netcode는 거대한 패킷에 한 번에 모두 전송하는 대신 대규모 월드를 몇 개의 고스트 <a href="https://docs.unity3d.com/Packages/com.unity.entities@1.3/manual/components-chunk.html" target="_blank" rel="noreferrer noopener">Chunk</a>씩 스트리밍합니다. </p>



<p>이는 효과적으로 <strong>중요도 우선순위 큐</strong>입니다.</p>



<p><code>MaxSendRate</code>를 사용하여 각 스냅샷의 중요도 우선순위 큐의 일부로 간주되는 고스트 <a href="https://docs.unity3d.com/Packages/com.unity.entities@1.3/manual/components-chunk.html" target="_blank" rel="noreferrer noopener">Chunk</a>의 수를 줄일 수도 있으며, 이는 총 대역폭 소비를 줄일 수 있습니다.</p>



<p><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#snapshots" target="_blank" rel="noreferrer noopener">Snapshots</a></code>의 최대 크기를 변경할 수 있습니다. </p>



<p>최대 크기를 줄이면 상대적인 헤더 오버헤드가 증가하고 사용 가능한 데이터가 줄어드는 대신 대역폭이 절약되며, </p>



<p>크기를 늘리면 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-snapshots.html#snapshots" target="_blank" rel="noreferrer noopener">Snapshots</a></code>당 여러 UDP 패킷을 전송해야 할 수 있어 패킷 손실 가능성이 증가할 수 있습니다.</p>



<p>자세한 내용은 중요도 스케일링(<a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/optimizations.html#importance-scaling" target="_blank" rel="noreferrer noopener">importance scaling</a>)에 관한 문서를 참조하세요.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Snapshots 시각화 도구</h5>



<p>네트워크를 통해 전송되는 내용을 이해하기 위해 Network Debugger 스냅샷 시각화 도구를 사용할 수 있습니다.</p>



<p>도구를 열려면 <strong>Multiplayer</strong> > <strong>Open NetDbg</strong>로 이동하면 브라우저 창에서 도구가 열립니다. </p>



<p>이 도구는 수신된 각 스냅샷에 대한 세로 막대를 표시하며, 각 스냅샷에 대한 주요 정보 분석을 제공합니다.</p>



<figure class="wp-block-image size-full"><img decoding="async" width="564" height="353" src="https://lycos7560.com/wp-content/uploads/2025/05/image-8.png" alt="" class="wp-image-40015" srcset="https://lycos7560.com/wp-content/uploads/2025/05/image-8.png 564w, https://lycos7560.com/wp-content/uploads/2025/05/image-8-300x188.png 300w" sizes="(max-width: 564px) 100vw, 564px" /></figure>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="1920" height="1714" src="https://lycos7560.com/wp-content/uploads/2025/05/snapshot-debugger.jpg" alt="" class="wp-image-40016" style="width:816px;height:auto" srcset="https://lycos7560.com/wp-content/uploads/2025/05/snapshot-debugger.jpg 1920w, https://lycos7560.com/wp-content/uploads/2025/05/snapshot-debugger-300x268.jpg 300w, https://lycos7560.com/wp-content/uploads/2025/05/snapshot-debugger-768x686.jpg 768w, https://lycos7560.com/wp-content/uploads/2025/05/snapshot-debugger-1536x1371.jpg 1536w" sizes="(max-width: 1920px) 100vw, 1920px" /></figure>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> GhostFieldAttribute를 활용한 필드 동기화 및 직렬</h3>



<p><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghostfield-synchronize.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghostfield-synchronize.html</a></p>



<p><code><a href="https://docs.unity3d.com/Packages/com.unity.entities@latest?subfolder=/api/Unity.Entities.IComponentData.html" target="_blank" rel="noreferrer noopener"><code>Unity.Entities.IComponentData</code></a></code> 또는 <code><a href="https://docs.unity3d.com/Packages/com.unity.entities@latest?subfolder=/api/Unity.Entities.IBufferElementData.html" target="_blank" rel="noreferrer noopener"><code>Unity.Entities.IBufferElementData</code></a></code>의 어떤 필드와 속성이 서버에서 클라이언트로 직렬화되고 복제될지 지정하려면 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostFieldAttribute.html" target="_blank" rel="noreferrer noopener"><code>GhostFieldAttribute</code></a></code>를 사용하세요.</p>



<p>컴포넌트나 버퍼에 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostFieldAttribute.html" target="_blank" rel="noreferrer noopener"><code>GhostFieldAttribute</code></a></code>로 주석이 달린 필드가 하나 이상 포함되면, 컴포넌트 직렬화를 구현하는 구조체가 자동으로 코드 생성됩니다.</p>



<p><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostFieldAttribute.html" target="_blank" rel="noreferrer noopener"><code>GhostFieldAttribute</code></a> </code>외에도 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghostcomponentattribute.html" target="_blank" rel="noreferrer noopener"><code>GhostComponentAttribute</code></a></code>를 사용하여 런타임에서 복제가 처리되는 방식을 추가로 사용자 지정할 수 있습니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> GhostFieldAttribute 직렬화 사용자 지정</h5>



<p>GhostFieldAttribute를 사용하여 컴포넌트와 버퍼의 직렬화를 사용자 지정하려면 다음 속성을 사용하세요. </p>



<p>자세한 내용은 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostFieldAttribute.html" target="_blank" rel="noreferrer noopener"><code>GhostFieldAttribute</code></a> </code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostFieldAttribute.html" target="_blank" rel="noreferrer noopener">API documentation</a>를 참조하세요.</p>



<figure class="wp-block-table"><table><thead><tr><th>속성 (Property)</th><th>기본값 (Default value)</th><th>설명 (Description)</th></tr></thead><tbody><tr><td><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostFieldAttribute.html#Unity_NetCode_GhostFieldAttribute_Quantization" target="_blank" rel="noreferrer noopener"><code>Quantization</code></a></strong></td><td>float 타입은 기본적으로 비활성화됨, int 타입에서는 사용 불가</td><td><code>Quantization</code> 속성은 부동 소수점 숫자(및 다른 지원되는 타입, 예: 고스트 타입 템플릿)에 대해 정밀도를 제한하기 위한 <a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/compression.html#quantization" target="_blank" rel="noreferrer noopener">quantization</a>를 설정합니다. <br>부동 소수점 숫자는 지정된 양자화 값으로 곱해진 후 정수로 변환되어 대역폭을 절약합니다.</td></tr><tr><td><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostFieldAttribute.html#Unity_NetCode_GhostFieldAttribute_Composite" target="_blank" rel="noreferrer noopener"><code>Composite</code></a></strong></td><td>기본적으로 비활성화됨</td><td><code>Composite</code> 속성은 <a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/compression.html#delta-compression" target="_blank" rel="noreferrer noopener">delta compression</a> 시 비원시 타입(예: 구조체)의 변경 비트 마스크를 어떻게 계산할지를 제어합니다. <br><code>true</code>로 설정하면, 구조체 전체에 변경 사항이 있을 경우 단 하나의 변경 비트만 생성됩니다. <br><code>false</code>일 경우 각 필드마다 변경 비트를 가집니다. <br>예를 들어 <code>GUID</code>와 같이 필드들이 함께 수정되는 경우에는 <code>Composite=true</code>를 사용하는 것이 좋습니다.</td></tr><tr><td><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostFieldAttribute.html#Unity_NetCode_GhostFieldAttribute_SendData" target="_blank" rel="noreferrer noopener"><code>SendData</code></a></strong></td><td>기본적으로 활성화됨</td><td><code>SendData</code> 속성은 코드 생성 시 특정 필드를 직렬화 데이터에서 제외하도록 지정합니다. <br>구조체처럼 모든 필드가 기본적으로 직렬화되는 비원시 멤버에 유용합니다.</td></tr><tr><td><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostFieldAttribute.html#Unity_NetCode_GhostFieldAttribute_Smoothing" target="_blank" rel="noreferrer noopener"><code>Smoothing</code></a></strong></td><td>기본값은 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.SmoothingAction.html#Unity_NetCode_SmoothingAction_Clamp" target="_blank" rel="noreferrer noopener"><code>Clamp</code></a></code></td><td><code>Smoothing</code> 속성은 고스트가 <code>GhostMode.Interpolated</code> 모드일 때 필드가 어떻게 갱신될지를 제어합니다. <br><br>옵션은 다음과 같습니다:<br>&#8211; <code>Clamp</code>: 스냅샷이 수신될 때마다 클라이언트 값을 최신 스냅샷 값으로 고정<br>&#8211; <code>Interpolate</code>: 두 스냅샷 값 사이를 프레임마다 보간<br>&#8211; <code>InterpolateAndExtrapolate</code>: 다음 틱에 대한 데이터가 없을 경우 이전 두 스냅샷 값을 기반으로 외삽</td></tr><tr><td><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostFieldAttribute.html#Unity_NetCode_GhostFieldAttribute_MaxSmoothingDistance" target="_blank" rel="noreferrer noopener"><code>MaxSmoothingDistance</code></a></strong></td><td>&#8211;</td><td><code>MaxSmoothingDistance</code> 속성은 스냅샷 간 값 차이가 지정된 한계를 초과할 경우 보간을 비활성화합니다. <br>주로 텔레포트와 같은 상황에서 유용합니다.</td></tr><tr><td><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostFieldAttribute.html#Unity_NetCode_GhostFieldAttribute_SubType" target="_blank" rel="noreferrer noopener"><code>SubType</code></a></strong></td><td>&#8211;</td><td><code>SubType</code> 속성은 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostFieldSubType.html" target="_blank" rel="noreferrer noopener"><code>GhostFieldSubType</code></a></code> API를 사용하여 필드에 대해 사용자 지정 직렬화기를 지정할 때 사용합니다.</td></tr></tbody></table><figcaption class="wp-element-caption">외삽(Extrapolation) &#8211; 수학적인 개념으로, 알려진 데이터 지점들을 기반으로 하여 알려지지 않은 값을 예측하는 방법</figcaption></figure>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 참고 <br>정적 최적화와 보간이 모두 표시된 고스트는 절대 외삽되지 않습니다. <br>정적 최적화된 고스트는 변경되지 않은 경우 스냅샷 업데이트를 전송하지 않기 때문에 &#8216;이 지속적으로 변화하는 값이 변화를 멈췄다&#8217;와 &#8216;아직 다음 연속 값을 받지 못했다&#8217;를 구별할 수 없습니다.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h6 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> GhostField 상속</h6>



<p>기본 타입이 아닌 필드 타입에 [GhostField]가 지정된 경우, 해당 속성(및 일부 속성)은 [GhostField]속성을 직접 구현하지 않는 모든 하위 필드에 자동으로 상속됩니다. </p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">public struct Vector2
{
    public float x;
    [GhostField(Quantization=100)] public float y;
}

public struct MyComponent : IComponentData
{
    //Value.x는 상위 정의에서 지정한 양자화 값(1000)을 상속합니다.
    //Value.y는 원래 양자화 값(100)을 유지합니다.
    [GhostField(Quantized=1000)] public Vector2 Value;
}</pre>



<p>참고- SubType 속성은 항상 기본값으로 재설정됩니다.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Component serialization</h4>



<p>Component serialization 및 복제용으로 표시하려면 전송하려는 값에 [GhostField] 속성을 추가하세요.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">public struct MySerializedComponent : IComponentData
{
    [GhostField]public int MyIntField;
    [GhostField(Quantization=1000)]public float MyFloatField;
    [GhostField(Quantization=1000, Smoothing=SmoothingAction.Interpolate)]public float2 Position;
    public float2 NonSerializedField;
    ...
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>컴포넌트가 직렬화되려면 컴포넌트 자체가 public으로 선언되어야 합니다. </p>



<p>컴포넌트의 public 멤버만 직렬화될 수 있습니다. private 멤버에 [GhostField]를 추가해도 효과가 없습니다.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Dynamic buffer serialization</h4>



<p>버퍼를 직렬화 및 복제용으로 표시하려면 모든 public 필드에 [GhostField] 속성으로 주석을 달아야 합니다.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">public struct SerialisedBuffer : IBufferElementData
{
    [GhostField]public int Field0;
    [GhostField(Quantization=1000)]public float Field1;
    [GhostField(Quantization=1000)]public float2 Position;
    public float2 NonSerialisedField; // public 필드에 [GhostField]가 없으면 오류가 발생 // 명시적인 오류
    private float2 NonSerialisedField; // 이것은 허용됩니다. 읽기 전에 클라이언트에서 이것을 설정해야 합니다. private이므로 직렬화 대상이 아닙니다.
    [GhostField(SendData=false)]public int NotSentAndUninitialised; // 이것은 허용됩니다. 읽기 전에 클라이언트에서 이것을 설정해야 합니다.
    ...
}</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>버퍼가 직렬화되려면 버퍼 자체가 public으로 선언되어야 합니다. </p>



<p>버퍼의 public 멤버만 직렬화될 수 있습니다. private 멤버에 [GhostField]를 추가해도 효과가 없습니다.</p>



<p>필드의 직렬화 및 복제를 건너뛰려면 <a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostFieldAttribute.html#Unity_NetCode_GhostFieldAttribute_SendData" target="_blank" rel="noreferrer noopener">SendData</a> <a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostFieldAttribute.html#Unity_NetCode_GhostFieldAttribute_SendData" target="_blank" rel="noreferrer noopener">property</a>을 사용할 수 있습니다. </p>



<p>이는 다음을 의미합니다:</p>



<ul class="wp-block-list">
<li>복제되지 않는 필드의 값은 절대 변경되지 않습니다.</li>



<li>새 버퍼 요소의 경우 그 내용이 기본값으로 설정되지 않으며 내용은 정의되지 않습니다(어떤 값이든 될 수 있음).</li>



<li>동적 버퍼 필드는 <a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.SmoothingAction.html" target="_blank" rel="noreferrer noopener">SmoothingAction</a>을 지원하지 않으므로 버퍼에서는 <code>GhostFieldAttribute.Smoothing</code> 및 <code>GhostFieldAttribute.MaxSmoothingDistance</code> 속성이 무시됩니다.</li>
</ul>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> ICommandData 및 IInputComponentData 직렬화</h4>



<p>입력 필드에 [GhostField]를 주석으로 달아 서버에서 클라이언트로 복제할 수 있습니다. </p>



<p>이는 예를 들어 로컬 머신에서 다른 플레이어의 캐릭터 컨트롤러에 대한 클라이언트 측 예측을 활성화하는 데 유용할 수 있습니다.</p>



<p>IInputComponentData를 사용한 자동화된 입력 동기화 시:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">public struct MyCommand : IInputComponentData
{
    [GhostField] public int Value;
}</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>ICommandData는 IBufferElementData의 하위 클래스이며 서버에서 클라이언트로의 복제를 위해 직렬화될 수 있습니다. </p>



<p>따라서 버퍼와 동일한 규칙이 적용됩니다: 명령 버퍼가 직렬화되려면 모든 필드에 주석이 달려 있어야 합니다.</p>



<p>ICommandData 사용 시:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">[GhostComponent()]
public struct MyCommand : ICommandData
{
    [GhostField] public NetworkTick Tick {get; set;}
    [GhostField] public int Value;
}</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>명령 데이터 직렬화는 원격 플레이어 예측을 구현하는 데 특히 유용합니다.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 사용자 지정 타입에 대한 직렬화 지원 추가</h4>



<p><code>GhostFieldAttribute</code>로 직렬화할 수 있는 타입은 템플릿을 통해 지정됩니다. </p>



<p>기본적으로 지원되는 타입 목록은 <a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-types-templates.html#supported-types" target="_blank" rel="noreferrer noopener">Ghost 타입 템플릿 페이지</a>를 참조하세요.</p>



<p>기본 지원 타입 외에도 다음을 수행할 수 있습니다:</p>



<ul class="wp-block-list">
<li>새 타입에 대한 자체 템플릿 추가</li>



<li>타입에 대한 사용자 지정 직렬화 템플릿을 제공하고 <code>GhostFieldAttribute</code>의 <code>SubType </code>속성을 사용하여 대상 지정</li>
</ul>



<p>템플릿 작성 및 사용 방법에 대한 자세한 내용은 <a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-types-templates.html#defining-additional-templates" target="_blank" rel="noreferrer noopener">템플릿 사용 및 작성 방법</a>을 참조하세요.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 추가 리소스</h4>



<p><code>GhostFieldAttribute</code>로 직렬화할 수 있는 타입은 템플릿을 통해 지정됩니다. </p>



<ul class="wp-block-list">
<li><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostFieldAttribute.html" target="_blank" rel="noreferrer noopener"><code>GhostFieldAttribute</code> API documentation</a></li>



<li><a href="https://docs.unity3d.com/Packages/com.unity.entities@latest?subfolder=/api/Unity.Entities.IComponentData.html" target="_blank" rel="noreferrer noopener"><code>Unity.Entities.IComponentData</code> API documentation</a></li>



<li><a href="https://docs.unity3d.com/Packages/com.unity.entities@latest?subfolder=/api/Unity.Entities.IBufferElementData.html" target="_blank" rel="noreferrer noopener"><code>Unity.Entities.IBufferElementData</code> API documentation</a></li>



<li><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-types-templates.html" target="_blank" rel="noreferrer noopener">Ghost types templates</a></li>



<li><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghost-variants.html" target="_blank" rel="noreferrer noopener">Ghost variants</a></li>



<li><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghostcomponentattribute.html" target="_blank" rel="noreferrer noopener">Customizing replication with <code>GhostComponentAttribute</code></a></li>
</ul>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> GhostComponentAttribute를 사용한 복제 사용자 지정</h3>



<p><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghostcomponentattribute.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghostcomponentattribute.html</a></p>



<p><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostComponentAttribute.html" target="_blank" rel="noreferrer noopener"><code>GhostComponentAttribute</code></a></code>와 그 속성을 사용하여 런타임에서 복제가 처리되는 방식을 사용자 지정할 수 있습니다.</p>



<p><code><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostComponentAttribute.html" target="_blank" rel="noreferrer noopener"><code>GhostComponentAttribute</code></a></code></code>를 사용하기 전에 먼저 <code>GhostComponentAttribute</code>로 컴포넌트에 주석을 달아 <strong>직렬화 및 복제 대상으로 표시</strong>해야 합니다.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> GhostComponentAttribute 속성</h4>



<p><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostComponentAttribute.html" target="_blank" rel="noreferrer noopener"><code>GhostComponentAttribute</code></a></code>를 사용하여 복제를 수정하는 방법을 사용자 지정하려면 다음 속성을 사용하세요. 자세한 내용은 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostComponentAttribute.html" target="_blank" rel="noreferrer noopener"><code>GhostComponentAttribute</code></a></code> <a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostComponentAttribute.html" target="_blank" rel="noreferrer noopener">API 문서를 참조</a>하세요.</p>



<figure class="wp-block-table"><table><thead><tr><th>속성 (Property)</th><th>기본값 (Default value)</th><th>설명 (Description)</th></tr></thead><tbody><tr><td><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostComponentAttribute.html#Unity_NetCode_GhostComponentAttribute_OwnerSendType" target="_blank" rel="noreferrer noopener"><code>OwnerSendType</code></a></strong></td><td><code>All</code></td><td><code>OwnerSendType</code> 속성은 ( <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.SendToOwnerType.html" target="_blank" rel="noreferrer noopener"><code>SendToOwnerType</code></a></code> 사용) 어떤 클라이언트 그룹에 구성 요소를 복제할지를 지정합니다. <br>예를 들어, 입력 명령을 자신의 플레이어에게만 복제하도록 설정할 수 있습니다. </td></tr><tr><td><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostComponentAttribute.html#Unity_NetCode_GhostComponentAttribute_PrefabType" target="_blank" rel="noreferrer noopener"><code>PrefabType</code></a></strong></td><td><code>All</code></td><td><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghostcomponentattribute.html#prefabtype-details" target="_blank" rel="noreferrer noopener"><code>PrefabType</code></a></code> 속성은 ( <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostPrefabType.html" target="_blank" rel="noreferrer noopener"><code>GhostPrefabType</code></a></code> 사용) 구성 요소가 어떤 프리팹 버전에서 사용 가능한지를 지정합니다. <br>예를 들어, 렌더링 관련 구성 요소를 서버 월드의 고스트 버전에서는 제거하는 데 사용할 수 있습니다. </td></tr><tr><td><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostComponentAttribute.html#Unity_NetCode_GhostComponentAttribute_SendDataForChildEntity" target="_blank" rel="noreferrer noopener"><code>SendDataForChildEntity</code></a></strong></td><td><code>false</code></td><td><code>SendDataForChildEntity</code> 속성은 고스트 엔티티의 자식에 붙은 구성 요소를 복제할지를 지정합니다. <br>고스트 자식 엔티티의 복제는 부모보다 훨씬 느리므로 주의가 필요합니다. <br>이 속성은 [GhostEnabledBit]에도 적용됩니다.</td></tr><tr><td><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostComponentAttribute.html#Unity_NetCode_GhostComponentAttribute_SendTypeOptimization" target="_blank" rel="noreferrer noopener"><code>SendTypeOptimization</code></a></strong></td><td><code>AllClients</code></td><td><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghostcomponentattribute.html#sendtypeoptimization-details" target="_blank" rel="noreferrer noopener"><code>SendTypeOptimization</code></a></code> 속성은 ( <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostSendType.html" target="_blank" rel="noreferrer noopener"><code>GhostSendType</code></a></code> 사용) 고스트가 예측(predicted)인지 보간(interpolated)인지에 따라 구성 요소 복제를 제어합니다. <br>예를 들어, 실제로 고스트의 물리 상태를 예측할 때만 <code>PhysicsVelocity</code>를 복제하도록 설정할 수 있습니다. </td></tr></tbody></table></figure>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">[GhostComponent(PrefabType=GhostPrefabType.All, SendTypeOptimization=GhostSendType.OnlyInterpolatedClients, SendDataForChildEntity=false)]
public struct MyComponent : IComponentData
{
    [GhostField(Quantized=1000)] public float3 Value;
}
</pre>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> OwnerSendType 세부 정보</h4>



<p>소유권에 기반하여 컴포넌트가 복제되는 클라이언트를 지정하려면 GhostComponentAttribute의 OwnerSendType 속성을 사용하세요. </p>



<p>OwnerSendType은 SendToOwnerType에 정의된 대로 다음 중 하나일 수 있습니다.</p>



<ul class="wp-block-list">
<li>None: 컴포넌트가 어떤 클라이언트에도 복제되지 않습니다.</li>



<li>All: 컴포넌트가 모든 클라이언트에 복제됩니다.</li>



<li>SendToOwner: 컴포넌트는 고스트를 소유한 클라이언트에만 복제됩니다.</li>



<li>SendToNonOwner: 컴포넌트는 고스트를 소유한 클라이언트를 제외한 모든 클라이언트에 복제됩니다.</li>
</ul>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> PrefabType 세부 정보</h4>



<p>컴포넌트가 사용 가능한 고스트 프리팹 버전을 지정하려면 GhostComponentAttribute의 PrefabType 속성을 사용하세요. </p>



<p>PrefabType은 GhostPrefabType에 정의된 대로 다음 중 하나일 수 있습니다.</p>



<ul class="wp-block-list">
<li>None: 컴포넌트가 어떤 고스트 프리팹 유형에서도 사용할 수 없습니다.</li>



<li>All: 컴포넌트가 서버와 모든 클라이언트에서 사용 가능합니다.</li>



<li>Server: 컴포넌트는 서버에서만 사용 가능합니다.</li>



<li>Client: 고스트가 예측되든 보간되든 관계없이 컴포넌트는 클라이언트에서만 사용 가능합니다.</li>



<li>AllPredicted: 컴포넌트는 서버와 고스트가 예측되는 클라이언트에서 사용 가능합니다.</li>



<li>PredictedClient: 컴포넌트는 고스트가 예측되는 클라이언트에서만 사용 가능합니다.</li>



<li>InterpolatedClient: 컴포넌트는 고스트가 보간되는 클라이언트에서만 사용 가능합니다.</li>
</ul>



<p>예를 들어, RenderMesh에 [GhostComponent(PrefabType=GhostPrefabType.Client)]를 추가하면 고스트는 서버 월드에 인스턴스화될 때 RenderMesh를 가지지 않지만 클라이언트 월드에 인스턴스화될 때는 가지게 됩니다.</p>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" />참고 <br>따라서 런타임 예측 전환은 예측 모드가 변경됨에 따라 고스트에서 라이브로 컴포넌트를 추가하고 제거할 수 있는 가능성이 있습니다.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> SendDataForChildEntity 세부 정보</h4>



<p>컴포넌트가 고스트 엔터티의 자식에 연결된 경우 복제할지 여부를 지정하려면 GhostComponentAttribute의 SendDataForChildEntity 속성을 사용하세요. </p>



<p>자식 엔터티를 직렬화하고 복제하는 것은 계산 비용이 많이 드므로 이 속성의 기본값은 false입니다.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> SendTypeOptimization 세부 정보</h4>



<p>고스트가 해당 클라이언트에서 보간되거나 예측되는지에 따라 컴포넌트가 복제되는 클라이언트를 지정하려면 GhostComponentAttribute의 SendTypeOptimization 속성을 사용하세요. </p>



<p>SendTypeOptimization은 GhostSendType에 정의된 대로 다음 중 하나일 수 있습니다.</p>



<ul class="wp-block-list">
<li>DontSend: 컴포넌트가 어떤 클라이언트에도 복제되지 않습니다. 엔티티용 Netcode는 데이터를 수신하지 않는 클라이언트에서 컴포넌트를 수정하지 않습니다.</li>



<li>AllClients: 컴포넌트가 모든 클라이언트에 복제됩니다.</li>



<li>OnlyPredictedClients: 컴포넌트는 고스트를 예측하는 클라이언트에만 복제됩니다.</li>



<li>OnlyInterpolatedClients: 컴포넌트는 고스트를 보간하는 클라이언트에만 복제됩니다.</li>
</ul>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" />참고 <br>SendTypeOptimization 및/또는 OwnerSendType을 설정하여 컴포넌트를 복제해야 하는 클라이언트 유형을 지정해도 프리팹의 컴포넌트 존재에는 영향을 미치지 않으며, 데이터를 수신하지 않은 클라이언트의 컴포넌트를 수정하지도 않습니다.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 추가 리소스</h4>



<ul class="wp-block-list">
<li><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostComponentAttribute.html"><code>GhostComponentAttribute</code> API documentation</a></li>



<li><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/ghostfield-synchronize.html">Serializing and synchronizing with <code>GhostFieldAttribute</code></a></li>



<li><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.SendToOwnerType.html"><code>SendToOwnerType</code> API documentation</a></li>



<li><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostPrefabType.html"><code>GhostPrefabType</code> API documentation</a></li>



<li><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/api/Unity.NetCode.GhostSendType.html"><code>GhostSendType</code> API documentation</a></li>
</ul>



<p></p>
<p>The post <a href="https://lycos7560.com/unity/unity-netcode-for-entities-synchronizing-states-and-inputs-1/40012/">Unity Netcode for Entities – Synchronizing states and inputs (1)</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/unity/unity-netcode-for-entities-synchronizing-states-and-inputs-1/40012/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Unity Netcode for Entities – Connecting server and clients</title>
		<link>https://lycos7560.com/c/unity-netcode-for-entities-creating-multiplayer-gameplay/39997/</link>
					<comments>https://lycos7560.com/c/unity-netcode-for-entities-creating-multiplayer-gameplay/39997/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Thu, 01 May 2025 06:21:00 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Unity]]></category>
		<category><![CDATA[client]]></category>
		<category><![CDATA[Client / Server worlds]]></category>
		<category><![CDATA[dtls]]></category>
		<category><![CDATA[IP]]></category>
		<category><![CDATA[multiplayer]]></category>
		<category><![CDATA[Netcode]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[study]]></category>
		<category><![CDATA[TCP]]></category>
		<category><![CDATA[UDP]]></category>
		<category><![CDATA[WSS]]></category>
		<category><![CDATA[공부]]></category>
		<category><![CDATA[기초]]></category>
		<category><![CDATA[유니티]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=39997</guid>

					<description><![CDATA[<p>🔥 Connecting server and clients Netcode for Entities 1.5.0v https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/creating-multiplayer-gameplay.html 주제 설명 서버와 클라이언트 연결Connecting server and clients Netcode for Entities는 Unity Transport 패키지를 사용하여 연결을 관리합니다. 각 연결은 하나의 엔티티로 저장되며, 해당 엔티티는 NetworkStreamConnection 컴포넌트를 포함하고 있어, 연결에 사용되는 Transport 핸들을 참조합니다. 이 엔티티의 이름은 일반적으로 'NetworkConnection [nid]' 형식입니다. 상태 및 입력 동기화Synchronizing states [&#8230;]</p>
<p>The post <a href="https://lycos7560.com/c/unity-netcode-for-entities-creating-multiplayer-gameplay/39997/">Unity Netcode for Entities – Connecting server and clients</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-cbe7176c      "
					data-scroll= "1"
					data-offset= "30"
					style=""
				>
				<div class="uagb-toc__wrap">
						<div class="uagb-toc__title">
							목차						</div>
																						<div class="uagb-toc__list-wrap ">
						<ol class="uagb-toc__list"><li class="uagb-toc__list"><a href="#connecting-server-and-clients" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Connecting server and clients</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#서버와-클라이언트-연결" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 서버와 클라이언트 연결</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#명령-수신-대상-설정" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 명령 수신 대상 설정</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#게임-상태-진입" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 게임 상태 진입</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#연결-해제-요청" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 연결 해제 요청</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#수신-버퍼-incoming-buffers" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 수신 버퍼 (Incoming Buffers)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#송신-버퍼-outgoing-buffers" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 송신 버퍼 (Outgoing Buffers)</a></li></ul><li class="uagb-toc__list"><a href="#연결-흐름-connection-flow" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 연결 흐름 (Connection flow)</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-수동-연결-리스닝-manually-listen-or-connect" class="uagb-toc-link__trigger">1&#x20e3; 수동 연결 / 리스닝 (Manually listen or connect )</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#2-autoconnectport-사용-using-theautoconnectport" class="uagb-toc-link__trigger">2&#x20e3; AutoConnectPort 사용 (Using the AutoConnectPort)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#3-networkstreamrequest로-연결-흐름-제어" class="uagb-toc-link__trigger">3&#x20e3; NetworkStreamRequest로 연결 흐름 제어</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#4-network-simulator" class="uagb-toc-link__trigger">4&#x20e3; Network simulator</a></li></ul><li class="uagb-toc__list"><a href="#클라이언트-연결-이벤트-수신" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 클라이언트 연결 이벤트 수신</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-netcodeconnectionevents-on-the-client" class="uagb-toc-link__trigger">1&#x20e3; NetCodeConnectionEvents on the client</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#2-netcodeconnectionevents-on-the-server" class="uagb-toc-link__trigger">2&#x20e3; NetCodeConnectionEvents on the server</a></li></ul><li class="uagb-toc__list"><a href="#connection-approval" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Connection approval</a></li></ul></li><li class="uagb-toc__list"><a href="#연결-확인-sample-코드" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 연결 확인 Sample 코드</a></ul></ol>					</div>
									</div>
				</div>
			


<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Connecting server and clients</h2>



<p><strong>Netcode for Entities 1.5.0v</strong></p>



<p><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/creating-multiplayer-gameplay.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/creating-multiplayer-gameplay.html</a></p>



<figure class="wp-block-table"><table><thead><tr><th>주제</th><th>설명</th></tr></thead><tbody><tr><td><strong>서버와 클라이언트 연결</strong><br><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/network-connection.html" target="_blank" rel="noreferrer noopener">Connecting server and clients</a></strong></td><td>Netcode for Entities는 Unity Transport 패키지를 사용하여 연결을 관리합니다. <br>각 연결은 하나의 엔티티로 저장되며, 해당 엔티티는 <code><strong>NetworkStreamConnection</strong></code> 컴포넌트를 포함하고 있어, 연결에 사용되는 Transport 핸들을 참조합니다. <br>이 엔티티의 이름은 일반적으로 <code><strong>'NetworkConnection [nid]'</strong></code> 형식입니다.</td></tr><tr><td><strong>상태 및 입력 동기화</strong><br><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/synchronization.html" target="_blank" rel="noreferrer noopener">Synchronizing states and inputs</a></strong></td><td>Netcode는 고스트(ghost) 상태와 입력/명령을 동기화합니다. <br>이 항목에서는 지원되는 타입 목록과, 어떤 필드와 컴포넌트를 <strong>eventual consistency 모델</strong>을 통해 복제할지 표시하는 방법(마크업)을 설명합니다.</td></tr><tr><td><strong>시간 동기화</strong><br><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/time-synchronization.html" target="_blank" rel="noreferrer noopener">Time synchronization</a></strong></td><td>Netcode는 <strong>서버 권한 모델(server authoritative model)</strong> 을 사용합니다. <br>서버는 고정된 시간 간격으로 시뮬레이션을 실행하며, 이 간격은 마지막 업데이트 이후 경과한 시간에 따라 결정됩니다. <br>따라서 <strong>클라이언트는 항상 서버 시간과 동기화되어야 이 모델이 제대로 작동</strong>합니다.</td></tr><tr><td><strong>보간 및 예측보간</strong><br><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/interpolation.html" target="_blank" rel="noreferrer noopener">Interpolation and extrapolation</a></strong></td><td>게임에서 <strong>보간(interpolation)</strong> 및 <strong>예측보간(extrapolation)</strong> 을 사용하여, 불안정한 네트워크 환경에서도 부드러운 게임플레이 경험을 제공할 수 있습니다.</td></tr><tr><td><strong>예측</strong><br><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/prediction.html" target="_blank" rel="noreferrer noopener">Prediction</a></strong></td><td>게임의 지연(latency)을 보완하기 위해 <strong>예측 로직</strong>을 사용할 수 있습니다. <br>예측은 클라이언트가 로컬에서 먼저 행동을 시뮬레이션하고, 이후 서버로부터 확정된 결과를 받는 방식입니다.</td></tr><tr><td><strong>물리</strong><br><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/physics.html" target="_blank" rel="noreferrer noopener">Physics</a></strong></td><td><strong>Netcode 패키지는 Unity Physics와의 일부 통합 기능을 제공</strong>합니다. <br>이를 통해 네트워크 환경에서도 물리 기반 오브젝트를 보다 쉽게 사용할 수 있습니다. <br>이 통합 기능은 <strong>predicted ghosts</strong>와 <strong>interpolated ghosts</strong> 양쪽 모두에 대한 물리 처리를 지원합니다.</td></tr></tbody></table></figure>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 서버와 클라이언트 연결</h3>



<p><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/network-connection.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/network-connection.html</a></p>



<p><strong>Netcode for Entities</strong>는 연결을 관리하기 위해 <strong>Unity Transport 패키지</strong>를 사용하며, 각 연결을 하나의 <strong>엔티티</strong>로 저장합니다.</p>



<p>이 엔티티는 <code>NetworkStreamConnection</code> 컴포넌트를 가지며, 연결에 사용된 <strong>Transport 핸들</strong>을 포함합니다. </p>



<p>연결이 종료되면(서버가 유저 연결을 끊거나 클라이언트가 요청한 경우) 이 엔티티는 삭제됩니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 명령 수신 대상 설정</h4>



<p><code>[AutoCommandTarget feature]</code>를 사용하지 않거나 더 세밀한 제어가 필요한 경우, <strong>CommandTarget</strong>을 설정해야 합니다. </p>



<p>이 설정은 클라이언트에서 받은 명령을 저장할 엔티티를 지정합니다. </p>



<p>이 엔티티 참조를 최신 상태로 유지하는 것은 게임 개발자의 책임입니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 게임 상태 진입</h4>



<p>게임은 <code>NetworkStreamInGame</code> 컴포넌트를 연결 엔티티에 수동으로 추가해야 합니다. 이 작업은 자동으로 이루어지지 않습니다. </p>



<p>이 컴포넌트가 추가되기 전에는 클라이언트가 명령을 전송하지 않으며, 서버도 스냅샷을 전송하지 않습니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 연결 해제 요청</h4>



<p>연결을 해제하려면 해당 엔티티에 <code>NetworkStreamRequestDisconnect</code> 컴포넌트를 추가하세요. </p>



<p>Transport 드라이버를 통한 <strong>직접적인 연결 해제는 지원되지 않습니다.</strong></p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 수신 버퍼 (Incoming Buffers)</h4>



<p>각 연결은 최대 3개의 수신 버퍼를 가질 수 있습니다:</p>



<ul class="wp-block-list">
<li>명령: <code><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.IncomingRpcDataStreamBuffer.html" target="_blank" rel="noreferrer noopener">IncomingRpcDataStreamBuffer</a></strong></code></li>



<li>RPC: <code><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.IncomingCommandDataStreamBuffer.html" target="_blank" rel="noreferrer noopener">IncomingCommandDataStreamBuffer</a></strong></code></li>



<li>스냅샷 (클라이언트 전용): <code><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.IncomingSnapshotDataStreamBuffer.html" target="_blank" rel="noreferrer noopener">IncomingSnapshotDataStreamBuffer</a></strong></code></li>
</ul>



<p>서버에서 클라이언트로 스냅샷이 전송되면 버퍼에 저장되고 나중에 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.IncomingSnapshotDataStreamBuffer.html" target="_blank" rel="noreferrer noopener"><strong>GhostReceiveSystem</strong></a></code>에 의해 처리됩니다.</p>



<p>RPC 및 명령도 동일한 방식으로 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.NetworkStreamReceiveSystem.html"><strong>NetworkStreamReceiveSystem</strong></a></code>이 수집하고, 이후 각각의 시스템이 처리합니다.</p>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 서버는 <code>IncomingSnapshotDataStreamBuffer</code>를 가지지 않습니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 송신 버퍼 (Outgoing Buffers)</h4>



<p>각 연결은 최대 2개의 송신 버퍼를 가질 수 있습니다:</p>



<ul class="wp-block-list">
<li>명령 (클라이언트 전용): <code><strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.OutgoingRpcDataStreamBuffer.html" target="_blank" rel="noreferrer noopener">OutgoingRpcDataStreamBuffer</a></strong></code></li>



<li>RPC:<strong> <code>OutgoingRpcDataStreamBuffer</code></strong></li>
</ul>



<p>생성된 명령은 먼저 송신 버퍼에 저장되고, 클라이언트가 매 틱마다 이 버퍼를 전송합니다. </p>



<p>RPC도 마찬가지로 해당 송신 시스템이 버퍼에 인코딩하고, <code>RpcSystem</code>이 이를 묶어 MTU 단위로 전송합니다.</p>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 연결 흐름 (Connection flow)</h3>



<p>Netcode는 게임 시작 시 <strong>자동으로 서버 또는 클라이언트 연결을 설정하지 않습니다</strong>. </p>



<p>기본적으로 <code>ClientServerBootstrap</code>는 클라이언트와 서버 월드만 생성합니다. </p>



<p>연결 채널을 여는 방식은 개발자가 결정합니다.</p>



<p><strong>선택 가능한 방법:</strong></p>



<ul class="wp-block-list">
<li>1&#x20e3; <code><strong>NetworkStreamDriver</strong></code>를 사용하여 직접 <strong><code>Connect</code> </strong>또는 <strong><code>Listen</code> </strong>호출</li>



<li>2&#x20e3; <strong><code>AutoConnectPort</code> </strong>및 <strong><code>DefaultConnectAddress</code> </strong>설정</li>



<li><strong><code>NetworkStreamRequestConnect</code> </strong>및 <strong><code>NetworkStreamRequestListen</code> </strong>요청 엔티티 생성</li>
</ul>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 주의 </p>



<p>연결 중에는 반드시 <code>Application.runInBackground = true</code>로 설정해야 하며, 그렇지 않으면 <strong>포커스를 잃었을 때 연결이 끊길 수 있습니다.</strong></p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading">1&#x20e3; 수동 연결 / 리스닝 (Manually listen or connect )</h4>



<p><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.NetworkStreamDriver.html" target="_blank" rel="noreferrer noopener">NetworkStreamDriver</a></code> 싱글톤을 사용해 <code>Connect</code> 또는 <code>Listen</code> 메서드를 호출합니다. </p>



<p>코드 예시는 <a href="https://github.com/Unity-Technologies/EntityComponentSystemSamples/blob/master/NetcodeSamples/Assets/Samples/HelloNetcode/1_Basics/01_BootstrapAndFrontend/Frontend/Frontend.cs#L80" target="_blank" rel="noreferrer noopener">DOTS samples repository</a> 참고</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">        public void StartClientServer(string sceneName)
        {
            Debug.Log($"[StartClientServer] Called with '{sceneName}'.");
            if (ClientServerBootstrap.RequestedPlayType != ClientServerBootstrap.PlayType.ClientAndServer)
            {
                Debug.LogError($"Creating client/server worlds is not allowed if playmode is set to {ClientServerBootstrap.RequestedPlayType}");
                return;
            }

            var server = ClientServerBootstrap.CreateServerWorld("ServerWorld");
            var client = ClientServerBootstrap.CreateClientWorld("ClientWorld");

            SceneManager.LoadScene("FrontendHUD");

            //Destroy the local simulation world to avoid the game scene to be loaded into it
            //This prevent rendering (rendering from multiple world with presentation is not greatly supported)
            //and other issues.
            DestroyLocalSimulationWorld();
            if (World.DefaultGameObjectInjectionWorld == null)
                World.DefaultGameObjectInjectionWorld = server;
            SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);

            var port = ParsePortOrDefault(Port.text);

            NetworkEndpoint ep = NetworkEndpoint.AnyIpv4.WithPort(port);
            {
                using var drvQuery = server.EntityManager.CreateEntityQuery(ComponentType.ReadWrite&lt;NetworkStreamDriver>());
                drvQuery.GetSingletonRW&lt;NetworkStreamDriver>().ValueRW.RequireConnectionApproval = sceneName.Contains("ConnectionApproval", StringComparison.OrdinalIgnoreCase);
                drvQuery.GetSingletonRW&lt;NetworkStreamDriver>().ValueRW.Listen(ep);
            }

            ep = NetworkEndpoint.LoopbackIpv4.WithPort(port);
            {
                using var drvQuery = client.EntityManager.CreateEntityQuery(ComponentType.ReadWrite&lt;NetworkStreamDriver>());
                drvQuery.GetSingletonRW&lt;NetworkStreamDriver>().ValueRW.Connect(client.EntityManager, ep);
            }
        }</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading">2&#x20e3; <strong>AutoConnectPort 사용 (Using the&nbsp;AutoConnectPort)</strong></h4>



<p><code>ClientServerBootstrap</code>  <a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.ClientServerBootstrap.html#Unity_NetCode_ClientServerBootstrap_AutoConnectPort" target="_blank" rel="noreferrer noopener"><code>AutoConnectPort</code></a>필드에는 서버와 클라이언트가 처음 설정될 때 각각 자동으로 수신하고 연결하도록 지시하는 데 사용할 수 있는 두 가지 특수 속성이 포함되어 있습니다.</p>



<ul class="wp-block-list">
<li><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.ClientServerBootstrap.html#Unity_NetCode_ClientServerBootstrap_DefaultConnectAddress" target="_blank" rel="noreferrer noopener">DefaultConnectAddress</a></li>



<li><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.ClientServerBootstrap.html#Unity_NetCode_ClientServerBootstrap_DefaultListenAddress" target="_blank" rel="noreferrer noopener">DefaultListenAddress</a></li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">public class AutoConnectBootstrap : ClientServerBootstrap
{
    public override bool Initialize(string defaultWorldName)
    {
        AutoConnectPort = 7979;
        CreateDefaultClientServerWorlds();
        return true;
    }
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>서버는 와일드카드 주소(<code>DefaultListenAddress:AutoConnectPort</code>)에서 리슨을 시작합니다. </p>



<p><code>DefaultConnectAddress</code>는 기본적으로 <code>NetworkEndpoint.AnyIpv4</code>로 설정되어 있습니다. </p>



<p>클라이언트는 서버 주소(<code>DefaultConnectAddress:AutoConnectPort</code>)로 연결을 시작하며, 이 <code>DefaultConnectAddress</code>는 기본적으로 <code>NetworkEndpoint.Loopback</code>으로 설정되어 있습니다.</p>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>참고:</strong></p>



<p>에디터에서는 <strong>PlayMode 도구</strong>를 사용해 <code>AutoConnectAddress</code>와 <code>AutoConnectPort</code> 값을 오버라이드할 수 있습니다. </p>



<p>그러나 <strong><code>AutoConnectPort</code>를 0으로 설정한 경우</strong>에는 PlayMode 도구의 오버라이드 기능이 작동하지 않으며, 이 경우 <strong>수동으로 연결을 트리거해야 합니다.</strong></p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading">3&#x20e3; <strong>NetworkStreamRequest로 연결 흐름 제어</strong></h4>



<p><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.NetworkStreamDriver.html" target="_blank" rel="noreferrer noopener">NetworkStreamDriver</a></code>에서 직접 메서드를 호출하는 대신, 다음과 같은 싱글톤을 생성하여 연결 흐름을 제어할 수 있습니다:</p>



<ul class="wp-block-list">
<li><strong><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.NetworkStreamRequestConnect.html" target="_blank" rel="noreferrer noopener">NetworkStreamRequestConnect</a></code> singleton&nbsp;</strong>: 원하는 서버 주소/포트로 연결을 요청할 때 사용합니다.</li>



<li><strong><code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.NetworkStreamRequestListen.html" target="_blank" rel="noreferrer noopener">NetworkStreamRequestListen</a></code> singleton&nbsp;</strong>: 서버가 원하는 주소/포트에서 리슨을 시작하도록 요청할 때 사용합니다.</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// 클라이언트 월드에서, NetworkStreamRequestConnect가 있는 새 엔티티 생성
// 이 엔티티는 이후 NetworkStreamReceiveSystem에 의해 처리됩니다.
var connectRequest = clientWorld.EntityManager.CreateEntity(typeof(NetworkStreamRequestConnect));
EntityManager.SetComponentData(connectRequest, new NetworkStreamRequestConnect { Endpoint = serverEndPoint });

// 서버 월드에서, NetworkStreamRequestListen이 있는 새 엔티티 생성
// 이 엔티티도 마찬가지로 NetworkStreamReceiveSystem에 의해 처리됩니다.
var listenRequest = serverWorld.EntityManager.CreateEntity(typeof(NetworkStreamRequestListen));
EntityManager.SetComponentData(listenRequest, new NetworkStreamRequestListen { Endpoint = serverEndPoint });
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>이러한 요청은 런타임에 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.NetworkStreamReceiveSystem.html" target="_blank" rel="noreferrer noopener">NetworkStreamReceiveSystem</a></code>에 의해 소비되어 실제 연결 동작을 수행합니다.</p>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>참고 :</strong></p>



<p>실행 중 오류가 발생하면 <strong>PlayMode Tools</strong> 창을 열고 다시 <strong>Play Mode</strong>로 진입해 보세요.</p>



<p>만약 월드가 이미 존재한다면, 부트스트랩 코드(위 설명 참조)에 의해 자동으로 월드가 생성되고 있을 가능성이 큽니다.</p>



<p>서버가 이미 리슨 중이거나 클라이언트가 이미 연결 중이라면, 자동 연결 기능이 이미 활성화되어 있는 것입니다.</p>



<p>이 경우 수동 연결 방식을 사용하려면 <strong>부트스트랩 코드에서 자동 연결을 비활성화</strong>해야 합니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading">4&#x20e3; <strong>Network simulator</strong></h4>



<p>Unity Transport는 <code><strong>SimulatorUtility</strong></code>를 제공합니다. </p>



<p>이 도구는 <strong>Netcode for Entities 패키지</strong>에 포함되어 있으며, 에디터 내에서 다음 경로를 통해 접근하고 설정할 수 있습니다:</p>



<p>Multiplayer &gt; PlayMode Tools</p>



<p>실제 네트워크 상황을 보다 현실적으로 반영하기 위해, 시뮬레이터를 활성화한 상태로 자주 게임플레이를 테스트해보는 것이 좋습니다.</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="1261" height="990" src="https://lycos7560.com/wp-content/uploads/2025/05/image-6.png" alt="" class="wp-image-39999" style="width:838px;height:auto" srcset="https://lycos7560.com/wp-content/uploads/2025/05/image-6.png 1261w, https://lycos7560.com/wp-content/uploads/2025/05/image-6-300x236.png 300w, https://lycos7560.com/wp-content/uploads/2025/05/image-6-768x603.png 768w" sizes="(max-width: 1261px) 100vw, 1261px" /><figcaption class="wp-element-caption">PlayMode Tools</figcaption></figure>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 클라이언트 연결 이벤트 수신</h3>



<p><code>NetworkStreamDriver</code> 싱글톤을 통해 제공되는 <code>ConnectionEventsForTick</code> (형식: <code>NativeArray&lt;NetCodeConnectionEvent&gt;.ReadOnly</code>) 컬렉션을 사용하여, </p>



<p>클라이언트 및 서버에서 클라이언트 연결 이벤트를 반복(iterate)하면서 반응할 수 있습니다.</p>



<p>이 이벤트는 오직 <strong>단일 SimulationSystemGroup 틱 동안만 존재</strong>하며, 각각 <code>NetworkStreamConnectSystem</code>과 <code>NetworkStreamListenSystem</code>에서 초기화됩니다.</p>



<p>시스템이 위 시스템들의 job 이후에 실행되면, 같은 틱에서 발생한 이벤트를 수신하게 됩니다.</p>



<p>반면, 그 이전에 컬렉션을 조회하면 <strong>이전 틱의 값들을 반복</strong>하게 됩니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// 예제 시스템
[UpdateAfter(typeof(NetworkReceiveSystemGroup))]
[BurstCompile]
public partial struct NetCodeConnectionEventListener : ISystem
{
    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        var connectionEventsForClient = SystemAPI.GetSingleton&lt;NetworkStreamDriver>().ConnectionEventsForTick;
        foreach (var evt in connectionEventsForClient)
        {
            UnityEngine.Debug.Log($"[{state.WorldUnmanaged.Name}] {evt.ToFixedString()}!");
        }
    }
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>주의 :</strong></p>



<p>서버는 고정된 델타 타임으로 실행되기 때문에, <code>SimulationSystemGroup</code>은 각 렌더 프레임마다 <strong>0번 이상 실행</strong>될 수 있습니다.</p>



<p>따라서 <code>ConnectionEventsForTick</code>은 반드시 <code>SimulationSystemGroup</code> 내에서 실행되는 시스템 안에서만 읽어야 합니다.</p>



<p>예를 들어 <code>InitializationSystemGroup</code>, <code>PresentationSystemGroup</code>, 또는 어떤 MonoBehaviour 메서드 내에서 접근하면 다음과 같은 문제가 발생할 수 있습니다:</p>



<p>b) 시뮬레이션이 <strong>이 프레임에서 실행되지 않을 경우, 이벤트를 중복 수신</strong></p>



<p>a) 이전 틱 이벤트를 <strong>놓치고 현재 틱만 받음</strong></p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading">1&#x20e3; NetCodeConnectionEvents on the client</h4>



<figure class="wp-block-table"><table><thead><tr><th>상태</th><th>호출 규칙</th></tr></thead><tbody><tr><td>Unknown</td><td>절대 발생하지 않음</td></tr><tr><td>Connecting</td><td>자신의 클라이언트에서 한 번 발생. <code>NetworkStreamReceiveSystem</code>이 <code>Connect</code> 호출을 인식한 시점 (호출 프레임 다음일 수 있음)</td></tr><tr><td>Handshake</td><td>내부 transport 드라이버가 <code>Connected</code> 상태에 진입하면 한 번 발생</td></tr><tr><td>Approval</td><td>연결 승인 기능이 활성화된 경우에만 발생. Handshake 이후</td></tr><tr><td>Connected</td><td>서버가 <code>NetworkId</code>를 보내면 발생</td></tr><tr><td>Disconnected</td><td>연결 종료 또는 타임아웃 또는 서버에 의해 연결 해제 시 발생. <code>DisconnectReason</code>이 설정됨</td></tr></tbody></table></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>주의 :</strong></p>



<p>클라이언트는 다른 클라이언트의 이벤트를 수신하지 않습니다. 클라이언트 월드에서 발생한 이벤트는 <strong>자신의 클라이언트</strong>에 대한 이벤트뿐입니다.</p>



<p>Handshake 및 Approval 단계는 실패할 수 있으며, <code>ClientServerTickRate.HandshakeApprovalTimeoutMS</code> (기본값: 5000ms)의 타임아웃을 가집니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading">2&#x20e3; NetCodeConnectionEvents on the server</h4>



<figure class="wp-block-table"><table><thead><tr><th>상태</th><th>호출 규칙</th></tr></thead><tbody><tr><td>Unknown</td><td>절대 발생하지 않음</td></tr><tr><td>Connecting</td><td>클라이언트가 연결을 시작하는 순간을 서버는 알 수 없으므로 발생하지 않음</td></tr><tr><td>Handshake</td><td>모든 클라이언트에 대해 발생. transport 연결이 수락되면 진입</td></tr><tr><td>Approval</td><td>승인 기능이 활성화된 경우에만 발생. Handshake 성공 후</td></tr><tr><td>Connected</td><td>클라이언트가 <code>NetworkId</code>를 부여받는 순간 발생</td></tr><tr><td>Disconnected</td><td>클라이언트가 연결 해제되거나 타임아웃되면 발생. <code>DisconnectReason</code> 설정됨</td></tr></tbody></table></figure>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>주의 :</strong></p>



<p>서버는 바인딩 성공이나 리스닝 시작에 대한 이벤트는 발생시키지 않습니다. <strong>기존 API를 통해 상태를 확인해야 합니다.</strong></p>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Connection approval</h3>



<p>서버에서 각 클라이언트 연결에 대해 <strong>승인을 요구하도록 설정할 수 있습니다</strong>.</p>



<p>연결 승인은 다음과 같은 목적으로 사용됩니다:</p>



<ul class="wp-block-list">
<li>플레이어 편의성: 화이트리스트 / 블랙리스트, 비밀번호 보호된 서버 등</li>



<li>보안 검증: 매치메이킹 응답으로 받은 <strong>시크릿 토큰</strong>을 사용하여, 매치메이킹된 플레이어만 서버에 입장하도록 제한</li>
</ul>



<p>연결 승인이 활성화되면 다음과 같은 변경이 발생 :</p>



<ol class="wp-block-list">
<li>클라이언트는 <strong>Handshake</strong> 및 <strong>Approval</strong> 단계에서만 <code>IApprovalRpcCommand</code> 형식의 RPC를 서버에 전송할 수 있습니다.</li>



<li>모든 클라이언트는 <strong>Handshake</strong> 상태에서 곧바로 <strong>Connected</strong>로 넘어가는 것이 아니라 <strong>Approval</strong> 상태로 이동합니다.</li>



<li>서버는 연결된 각 클라이언트의 엔티티에 <strong><code>ConnectionApproved</code> 컴포넌트</strong>를 <strong>직접 추가</strong>해야만 승인됩니다.</li>



<li><code>NetworkId</code>는 <strong>승인 성공 이후</strong>에만 할당됩니다. 승인에 실패하면 클라이언트는 연결이 끊어집니다.</li>



<li>승인 과정에는 <strong>타임아웃</strong>이 존재합니다 (<code>ClientServerTickRate.HandshakeApprovalTimeoutMS</code> 참조, 기본값: 5000ms)</li>
</ol>



<p>다시 강조하면:</p>



<ul class="wp-block-list">
<li>Handshake 및 Approval 단계 동안, 클라이언트는 <strong>여러 개의 RPC 메시지를 보낼 수 있습니다.</strong></li>



<li>단, 이들 모두 <code>IApprovalRpcCommand</code> 타입이어야 합니다.</li>



<li>이 RPC의 payload에는 인증 토큰, 플레이어 정보 등 클라이언트의 유효성을 검증하기 위한 모든 정보를 담을 수 있습니다.</li>



<li>서버는 <code>ConnectionApproved</code> 컴포넌트를 클라이언트의 연결 엔티티에 추가함으로써 연결을 승인합니다. 이후 연결 흐름이 계속 진행됩니다.</li>
</ul>



<p><code>NetworkStreamDriver</code>에는 <code>RequireConnectionApproval</code> 필드가 있으며, <strong>클라이언트와 서버 모두에서 true로 설정</strong>해야 연결 승인 흐름이 올바르게 작동합니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:2px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">if (isServer)
{
    using var drvQuery = server.EntityManager.CreateEntityQuery(ComponentType.ReadWrite&lt;NetworkStreamDriver>());
    drvQuery.GetSingletonRW&lt;NetworkStreamDriver>().ValueRW.RequireConnectionApproval = true;
    drvQuery.GetSingletonRW&lt;NetworkStreamDriver>().ValueRW.Listen(ep);
}
else
{
    using var drvQuery = client.EntityManager.CreateEntityQuery(ComponentType.ReadWrite&lt;NetworkStreamDriver>());
    drvQuery.GetSingletonRW&lt;NetworkStreamDriver>().ValueRW.RequireConnectionApproval = true;
    drvQuery.GetSingletonRW&lt;NetworkStreamDriver>().ValueRW.Connect(client.EntityManager, ep);
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>연결 승인 처리도 다음과 같이 설정할 수 있습니다 : </p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// The approval RPC, here it contains a hypothetical payload the server will validate
public struct ApprovalFlow : IApprovalRpcCommand
{
    public FixedString512Bytes Payload;
}

// This is used to indicate we've already sent an approval RPC and don't need to do so again
public struct ApprovalStarted : IComponentData
{
}

[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation | WorldSystemFilterFlags.ThinClientSimulation)]
public partial struct ClientConnectionApprovalSystem : ISystem
{
    public void OnCreate(ref SystemState state)
    {
        state.RequireForUpdate&lt;RpcCollection>();
    }

    public void OnUpdate(ref SystemState state)
    {
        var ecb = new EntityCommandBuffer(Allocator.Temp);
        // Check connections which have not yet fully connected and send connection approval message
        foreach (var (connection, entity) in SystemAPI.Query&lt;RefRW&lt;NetworkStreamConnection>>().WithNone&lt;NetworkId>().WithNone&lt;ApprovalStarted>().WithEntityAccess())
        {
            var sendApprovalMsg = ecb.CreateEntity();
            ecb.AddComponent(sendApprovalMsg, new ApprovalFlow { Payload = "ABC" });
            ecb.AddComponent&lt;SendRpcCommandRequest>(sendApprovalMsg);

            ecb.AddComponent&lt;ApprovalStarted>(entity);
        }
        ecb.Playback(state.EntityManager);
    }
}

[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]
public partial struct ServerConnectionApprovalSystem : ISystem
{
    public void OnUpdate(ref SystemState state)
    {
        var ecb = new EntityCommandBuffer(Allocator.Temp);
        // Check connections which have not yet fully connected and send connection approval message
        foreach (var (receiveRpc, approvalMsg, entity) in SystemAPI.Query&lt;RefRO&lt;ReceiveRpcCommandRequest>,RefRW&lt;ApprovalFlow>>().WithEntityAccess())
        {
            var connectionEntity = receiveRpc.ValueRO.SourceConnection;
            if (approvalMsg.ValueRO.Payload.Equals("ABC"))
            {
                ecb.AddComponent&lt;ConnectionApproved>(connectionEntity);

                // Destroy RPC message
                ecb.DestroyEntity(entity);
            }
            else
            {
                // Failed approval messages should be disconnected
                ecb.AddComponent&lt;NetworkStreamRequestDisconnect>(connectionEntity);
            }
        }
        ecb.Playback(state.EntityManager);
    }
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 연결 확인 Sample 코드</h2>



<p><a href="https://discussions.unity.com/t/lobby-relay-and-netcode-for-entities/1538817/8" target="_blank" rel="noreferrer noopener">https://discussions.unity.com/t/lobby-relay-and-netcode-for-entities/1538817/8</a></p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p><strong>WorldManager.cs</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using System.Diagnostics.CodeAnalysis;
using Unity.Entities;

namespace Managers 
{
    public static class WorldManager 
    {
        private static World _clientWorld, _serverWorld;
		
        [SuppressMessage("ReSharper", "ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator")]
        public static void DestroyLocalSimulationWorld() {
            foreach (var world in World.All) {
                if (world.Flags != WorldFlags.Game) continue;
                world.Dispose();
                break;
            }
        }
		
        public static void RegisterServerWorld(World world) => _serverWorld = world;
        public static void RegisterClientWorld(World world) => _clientWorld = world;

        public static World GetServerWorld() => _serverWorld;
        public static World GetClientWorld() => _clientWorld;
    }
}</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p><strong>RelayServerDataHelper.cs</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using System;
using System.Collections.Generic;
using System.Linq;
using Unity.Networking.Transport;
using Unity.Networking.Transport.Relay;
using Unity.Services.Relay.Models;

namespace Extension 
{
    public static class RelayServerDataHelper 
    {
        private static RelayServerData GetRelayData(List&lt;RelayServerEndpoint> endpoints, byte[] allocationIdBytes, byte[] connectionDataBytes, byte[] hostConnectionDataBytes, byte[] keyBytes) 
        {
            
            var endpoint = endpoints.FirstOrDefault(e => e.ConnectionType == "dtls") ?? throw new InvalidOperationException($"Endpoint for connectionType dtls not found");
            
            var server = NetworkEndpoint.Parse(endpoint.Host, (ushort)endpoint.Port);
    
            var allocationId = RelayAllocationId.FromByteArray(allocationIdBytes);
            var connData = RelayConnectionData.FromByteArray(connectionDataBytes);
            var hostData = RelayConnectionData.FromByteArray(hostConnectionDataBytes);
            var key = RelayHMACKey.FromByteArray(keyBytes);

            return new RelayServerData(ref server, 0, ref allocationId, ref connData, ref hostData, ref key, true); 
        }

        public static RelayServerData RelayData(JoinAllocation a) => GetRelayData(a.ServerEndpoints, a.AllocationIdBytes, a.ConnectionData, a.HostConnectionData, a.Key);

        public static RelayServerData RelayData(Allocation a) => GetRelayData(a.ServerEndpoints, a.AllocationIdBytes, a.ConnectionData, a.ConnectionData, a.Key);
    }
}</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p><strong>RelayInitializer.cs</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using System;
using System.Collections;
using System.Threading.Tasks;
using Unity.Entities;
using Unity.NetCode;
using Unity.Networking.Transport;
using Unity.Networking.Transport.Relay;
using Unity.Services.Authentication;
using Unity.Services.Core;
using Unity.Services.Relay;
using UnityEngine;
using Extension;

namespace Managers 
{
    public class RelayInitializer : MonoBehaviour 
    {
        private static RelayServerData? _relayServerData, _relayClientData;
        private static Action OnConnectionComplete;
        public static string _joinCode;
    
        // Singleton (without duplicate destroy logic) for access to the class instance from within the static methods
        private static RelayInitializer Instance { get; set; }
        protected void Awake() => Instance = this;
        
        // HOSTING

        public static void StartHost() => Instance.StartCoroutine(InitializeHost());

        private static IEnumerator InitializeHost() 
        {
            var initializeTask = UnityServices.InitializeAsync();
            while (!initializeTask.IsCompleted)
                yield return null;
            if (ProcessTaskFail(initializeTask, nameof(initializeTask)))
                yield break;

            var signInTask = Task.CompletedTask;
            if (!AuthenticationService.Instance.IsSignedIn) {
                signInTask = AuthenticationService.Instance.SignInAnonymouslyAsync();
                while (!signInTask.IsCompleted)
                    yield return null; 
            }
            
            if (ProcessTaskFail(signInTask, nameof(signInTask)))
                yield break;

            var allocationTask = RelayService.Instance.CreateAllocationAsync(5);
            
            while (!allocationTask.IsCompleted)
                yield return null;
            
            if (ProcessTaskFail(allocationTask, nameof(allocationTask)))
                yield break;

            var joinCodeTask = RelayService.Instance.GetJoinCodeAsync(allocationTask.Result.AllocationId);
            
            while (!joinCodeTask.IsCompleted)
                yield return null;
            
            if (ProcessTaskFail(joinCodeTask, nameof(joinCodeTask)))
                yield break;

            _joinCode = joinCodeTask.Result;

            try 
            {
                Debug.Log("Hosting relay data");
                _relayServerData = RelayServerDataHelper.RelayData(allocationTask.Result);
            } catch (Exception e) {
                Debug.LogException(e);
                _relayServerData = null;
                yield break;
            }

            Debug.Log("Success, players may now connect");
            while (_relayServerData == null || (!_relayServerData?.Endpoint.IsValid ?? false))
                yield return null;
                
            yield return JoinUsingCode(_joinCode);
            yield return WaitRelayConnection();
            SetupRelayHostedServerAndConnect();
        }

        private static void SetupRelayHostedServerAndConnect() 
        {
            if (ClientServerBootstrap.RequestedPlayType != ClientServerBootstrap.PlayType.ClientAndServer) 
            {
                UnityEngine.Debug.LogError($"Creating client/server worlds is not allowed if playmode is set to {ClientServerBootstrap.RequestedPlayType}");
                return;
            }

            var relayServerData = _relayServerData.GetValueOrDefault();
            var relayClientData = _relayClientData.GetValueOrDefault();

            var oldConstructor = NetworkStreamReceiveSystem.DriverConstructor;
            NetworkStreamReceiveSystem.DriverConstructor = new RelayDriverConstructor(relayServerData, relayClientData);
            var server = ClientServerBootstrap.CreateServerWorld("ServerWorld");
            WorldManager.RegisterServerWorld(server);
            var client = ClientServerBootstrap.CreateClientWorld("ClientWorld");
            WorldManager.RegisterClientWorld(client);
            NetworkStreamReceiveSystem.DriverConstructor = oldConstructor;

            

            WorldManager.DestroyLocalSimulationWorld();
            World.DefaultGameObjectInjectionWorld ??= server;

            // Load scene here if you want to.
            
            Debug.Log(_joinCode);

            var networkStreamEntity = server.EntityManager.CreateEntity(ComponentType.ReadWrite&lt;NetworkStreamRequestListen>());
            server.EntityManager.SetName(networkStreamEntity, "NetworkStreamRequestListen");
            server.EntityManager.SetComponentData(networkStreamEntity,
                new NetworkStreamRequestListen { Endpoint = NetworkEndpoint.AnyIpv4 });

            networkStreamEntity =
                client.EntityManager.CreateEntity(ComponentType.ReadWrite&lt;NetworkStreamRequestConnect>());
            client.EntityManager.SetName(networkStreamEntity, "NetworkStreamRequestConnect");
            client.EntityManager.SetComponentData(networkStreamEntity,
                new NetworkStreamRequestConnect { Endpoint = relayClientData.Endpoint });
            
            ProcessConnectionComplete();
        }

        // CONNECTING
    
        public static void ConnectByCode(string joinCode) => Instance.StartCoroutine(ProcessCodeConnection(joinCode));
    
        private static IEnumerator ProcessCodeConnection(string joinCode) 
        {
            Instance.StartCoroutine(JoinExternalServer(joinCode));
            yield return WaitRelayConnection();
            ConnectToRelayServer();
        }

        private static IEnumerator WaitRelayConnection() {
            while (_relayClientData == null || (!_relayClientData?.Endpoint.IsValid ?? false))
                yield return null;
        }
        
        private static IEnumerator JoinExternalServer(string joinCode) {
            Debug.Log("Waiting for relay response");
            var setupTask = UnityServices.InitializeAsync();

            while (!setupTask.IsCompleted)
                yield return null;
            
            var signInTask = Task.CompletedTask;
            if (!AuthenticationService.Instance.IsSignedIn) {
                signInTask = AuthenticationService.Instance.SignInAnonymouslyAsync();
                while (!signInTask.IsCompleted)
                    yield return null;
            }
            if (ProcessTaskFail(signInTask, nameof(signInTask)))
                yield break;

            yield return JoinUsingCode(joinCode);
        }

        private static IEnumerator JoinUsingCode(string joinCode) 
        {
            // Send the join request to the Relay service
            var joinTask = RelayService.Instance.JoinAllocationAsync(joinCode);
            while (!joinTask.IsCompleted)
                yield return null;
            
            if (ProcessTaskFail(joinTask, nameof(joinTask)))
                yield break;
            
            // Format the server data, based on desired connectionType
            try {
                _relayClientData = RelayServerDataHelper.RelayData(joinTask.Result);
            } catch (Exception e) 
            {
                Debug.LogException(e);
                _relayClientData = null;
            }

            _joinCode = joinCode;
        }
    
        private static void ConnectToRelayServer() 
        {
            var relayClientData = _relayClientData.GetValueOrDefault();
            
            var oldConstructor = NetworkStreamReceiveSystem.DriverConstructor;
            NetworkStreamReceiveSystem.DriverConstructor = new RelayDriverConstructor(new RelayServerData(), relayClientData);
            var client = ClientServerBootstrap.CreateClientWorld("ClientWorld");
            WorldManager.RegisterClientWorld(client);
            NetworkStreamReceiveSystem.DriverConstructor = oldConstructor;

            WorldManager.DestroyLocalSimulationWorld();
            World.DefaultGameObjectInjectionWorld ??= client;
        
            var networkStreamEntity =
                client.EntityManager.CreateEntity(ComponentType.ReadWrite&lt;NetworkStreamRequestConnect>());
            client.EntityManager.SetName(networkStreamEntity, "NetworkStreamRequestConnect");
            client.EntityManager.SetComponentData(networkStreamEntity,
                new NetworkStreamRequestConnect { Endpoint = relayClientData.Endpoint });
            ProcessConnectionComplete();
        }

        // COMMON
    
        private static bool ProcessTaskFail(Task task, string taskName) {
            if (!task.IsFaulted) return false;
            Debug.LogError($"Task {taskName} failed.");
            Debug.LogException(task.Exception);
            return true;
        }

        public static void SubscribeToConnectionComplete(Action handler) => OnConnectionComplete += handler;

        public static void ProcessConnectionComplete() {
            if (OnConnectionComplete == null)
                return;
            OnConnectionComplete?.Invoke();
            foreach (var handler in OnConnectionComplete?.GetInvocationList()!)
                OnConnectionComplete -= (Action)handler;
        }
    }

    public class RelayDriverConstructor : INetworkStreamDriverConstructor 
    {
        private RelayServerData _relayServerData, _relayClientData;
    
        public RelayDriverConstructor(RelayServerData serverData, RelayServerData clientData) {
            _relayServerData = serverData;
            _relayClientData = clientData;
        }

        public void CreateClientDriver(World world, ref NetworkDriverStore driverStore, NetDebug netDebug) {
            var settings = DefaultDriverBuilder.GetNetworkSettings();
            settings.WithRelayParameters(ref _relayClientData);
            DefaultDriverBuilder.RegisterClientDriver(world, ref driverStore, netDebug, settings);
        }

        public void CreateServerDriver(World world, ref NetworkDriverStore driverStore, NetDebug netDebug) =>
            DefaultDriverBuilder.RegisterServerDriver(world, ref driverStore, netDebug, ref _relayServerData);
    }
}</pre>
<p>The post <a href="https://lycos7560.com/c/unity-netcode-for-entities-creating-multiplayer-gameplay/39997/">Unity Netcode for Entities – Connecting server and clients</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/c/unity-netcode-for-entities-creating-multiplayer-gameplay/39997/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Unity Netcode for Entities &#8211; Client / Server worlds</title>
		<link>https://lycos7560.com/unity/unity-netcode-for-entities-client-server-worlds/39993/</link>
					<comments>https://lycos7560.com/unity/unity-netcode-for-entities-client-server-worlds/39993/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Thu, 01 May 2025 00:50:19 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Unity]]></category>
		<category><![CDATA[client]]></category>
		<category><![CDATA[Client / Server worlds]]></category>
		<category><![CDATA[dtls]]></category>
		<category><![CDATA[IP]]></category>
		<category><![CDATA[multiplayer]]></category>
		<category><![CDATA[Netcode]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[study]]></category>
		<category><![CDATA[TCP]]></category>
		<category><![CDATA[UDP]]></category>
		<category><![CDATA[WSS]]></category>
		<category><![CDATA[공부]]></category>
		<category><![CDATA[기초]]></category>
		<category><![CDATA[유니티]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=39993</guid>

					<description><![CDATA[<p>🔥 Client / Server worlds Setting Netcode for Entities 1.5.0v https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/set-up-client-server-worlds.html Netcode for Entities의 네트워킹 모델을 사용하여client 와 server를 설정합니다. ✅ 클라이언트 / 서버 World 네트워크 모델 https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/client-server-worlds.html Netcode for Entities는 Client와 Server의 로직을 각각 Client world와 Server world로 분리하여 처리합니다. 월드(World)는 Unity의 ECS(Entity Component System) 개념으로, 엔티티와 시스템을 시스템 그룹(SystemGroup)으로 구성한 단위입니다. 기본적인 Client [&#8230;]</p>
<p>The post <a href="https://lycos7560.com/unity/unity-netcode-for-entities-client-server-worlds/39993/">Unity Netcode for Entities &#8211; Client / Server worlds</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-cbe7176c      "
					data-scroll= "1"
					data-offset= "30"
					style=""
				>
				<div class="uagb-toc__wrap">
						<div class="uagb-toc__title">
							목차						</div>
																						<div class="uagb-toc__list-wrap ">
						<ol class="uagb-toc__list"><li class="uagb-toc__list"><a href="#client-server-worlds-setting" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Client / Server worlds Setting</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#클라이언트-서버-world-네트워크-모델" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 클라이언트 / 서버 World 네트워크 모델</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#시스템-생성-및-업데이트-구성" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 시스템 생성 및 업데이트 구성</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-특정-시스템-그룹에-할당하기" class="uagb-toc-link__trigger">1&#x20e3; 특정 시스템 그룹에 할당하기</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#2-worldsystemfilter-사용" class="uagb-toc-link__trigger">2&#x20e3; WorldSystemFilter 사용</a></li></ul><li class="uagb-toc__list"><a href="#client-server-worlds-with-bootstrapping" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Client / Server worlds with bootstrapping</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#0-bootstrapping-커스터-마이징" class="uagb-toc-link__trigger">0&#x20e3; Bootstrapping 커스터 마이징</a></li></ul><li class="uagb-toc__list"><a href="#client-server-업데이트-주기" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Client / Server 업데이트 주기</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#성능-문제-방지" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 성능 문제 방지</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#프레임-속도-유지-방식-설정" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 프레임 속도 유지 방식 설정</a></li></ul><li class="uagb-toc__list"><a href="#월드-마이그레이션-world-migration" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 월드 마이그레이션 (World Migration)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#additional-resources" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2795.png" alt="➕" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Additional resources</a></li></ul><li class="uagb-toc__list"><a href="#네트워크-프로토콜-검사" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 네트워크 프로토콜 검사</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#개발-중-발생할-수-있는-문제" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 개발 중 발생할 수 있는 문제</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#프로토콜-검사-해제" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 프로토콜 검사 해제</a></li></ul><li class="uagb-toc__list"><a href="#additional-resources" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2795.png" alt="➕" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Additional resources</a></ul></ul></ol>					</div>
									</div>
				</div>
			


<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Client / Server worlds Setting</h2>



<p><strong>Netcode for Entities 1.5.0v</strong></p>



<p><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/set-up-client-server-worlds.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/set-up-client-server-worlds.html</a></p>



<p>Netcode for Entities의 네트워킹 모델을 사용하여client 와 server를 설정합니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 클라이언트 / 서버 World 네트워크 모델</h3>



<p><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/client-server-worlds.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/client-server-worlds.html</a></p>



<p><strong>Netcode for Entities</strong>는 <strong>Client</strong>와 Server의 로직을 각각 <strong>Client world</strong>와 <strong>Server world</strong>로 분리하여 처리합니다.</p>



<p>월드(World)는 Unity의 <strong>ECS(Entity Component System)</strong> 개념으로, <strong>엔티티와 시스템을 시스템 그룹(SystemGroup)으로 구성한 단위</strong>입니다.</p>



<p>기본적인 Client / Server 월드 외에도, 개발 중에 게임을 테스트할 수 있도록 <strong>씬 클라이언트(Thin Client)</strong> 기능도 지원합니다.</p>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 시스템 생성 및 업데이트 구성</h4>



<p>기본적으로, 모든 시스템은 클라이언트/서버 월드의 <code><a href="https://docs.unity3d.com/Packages/com.unity.entities@latest?subfolder=/api/Unity.Entities.SimulationSystemGroup.html" target="_blank" rel="noreferrer noopener"><code>SimulationSystemGroup</code></a></code>에서 생성되고 업데이트됩니다. </p>



<p>하지만 특정 시스템을 <strong>클라이언트에만</strong>, 또는 <strong>서버에만</strong> 작동하게 만들고 싶을 때는 다음 두 가지 방법을 사용할 수 있습니다</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading">1&#x20e3; 특정 시스템 그룹에 할당하기</h5>



<p>시스템이 속할 시스템 그룹을 지정하면, <strong>그 시스템 그룹이 존재하지 않는 월드에서는 자동으로 필터링</strong>됩니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">[UpdateInGroup(typeof(GhostInputSystemGroup))]
public class MyInputSystem : SystemBase
{
  ...
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4cc.png" alt="📌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 참고: </p>



<p><code><a href="https://docs.unity3d.com/Packages/com.unity.entities@latest?subfolder=/api/Unity.Entities.PresentationSystemGroup.html" target="_blank" rel="noreferrer noopener"><code>PresentationSystemGroup</code></a></code>에 속한 시스템은 클라이언트 월드에서만 작동합니다. </p>



<p>Server / Thin client worlds에는 이 시스템 그룹이 생성되지 않기 때문입니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading">2&#x20e3; WorldSystemFilter 사용</h5>



<p>시스템이 어떤 월드에서 작동할지 더 세부적으로 설정하고 싶다면 <strong><code>WorldSystemFilter</code> </strong>속성을 사용하세요.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// WorldSystemFilterFlags 옵션 
// - LocalSimulation: 오프라인 로컬 시뮬레이션 (Netcode 시스템 없음)
// - ServerSimulation: 서버 시뮬레이션
// - ClientSimulation: 클라이언트 시뮬레이션
// - ThinClientSimulation: 씬 클라이언트
// 속성을 지정하지 않으면, 기본적으로 시스템은 상위 그룹의 필터링 규칙을 따릅니다 (WorldSystemFilterFlags.Default)

[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)]
public class MySystem : SystemBase
{
  ...
}</pre>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Client / Server worlds with bootstrapping</h4>



<p><strong>Netcode for Entities</strong>를 프로젝트에 추가하면, 기본 <code><a href="https://docs.unity3d.com/Packages/com.unity.netcode@latest/index.html?subfolder=/api/Unity.NetCode.ClientServerBootstrap.html" target="_blank" rel="noreferrer noopener"><code>ClientServerBootstrap</code></a></code> 클래스가 제공됩니다. </p>



<p>이 클래스는 <strong>게임 시작 시 클라이언트 및 서버 월드를 자동 생성</strong>합니다</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">public virtual bool Initialize(string defaultWorldName)
{
    CreateDefaultClientServerWorlds();
    return true;
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>자동 부트스트래핑은 <strong>에디터에서 Play 모드 진입 시 매우 유용</strong>합니다. </p>



<p>하지만, <strong>실제 게임에서는 메인 메뉴와 같은 전처리 과정이 필요</strong>하므로 <strong>월드 생성을 지연</strong>시키거나 수동 제어할 필요가 있습니다.</p>



<p>예를 들어</p>



<ul class="wp-block-list">
<li>&#8220;클라이언트-호스트 서버 실행&#8221; → <strong>서버</strong>와 <strong>클라이언트</strong> 모두 생성</li>



<li>&#8220;전용 서버에 접속&#8221; → <strong>클라이언트</strong>만 생성</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading">0&#x20e3; Bootstrapping 커스터 마이징</h5>



<p>기본 <code>ClientServerBootstrap</code>을 상속하여 원하는 방식으로 월드 생성을 제어할 수 있습니다</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">public class MyGameSpecificBootstrap : ClientServerBootstrap
{
    public override bool Initialize(string defaultWorldName)
    {
        // Netcode 없이 로컬 시뮬레이션 월드만 생성
        CreateLocalWorld(defaultWorldName);
        return true;
    }
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>버튼 클릭 등의 타이밍에 다음을 호출하여 월드 생성:</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">var clientWorld = ClientServerBootstrap.CreateClientWorld();
var serverWorld = ClientServerBootstrap.CreateServerWorld();

AutomaticThinClientWorldsUtility.NumThinClientsRequested = 10;
AutomaticThinClientWorldsUtility.BootstrapThinClientWorlds();

ClientServerBootstrap.CreateDefaultClientServerWorlds();
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>Netcode Sample  <a href="https://github.com/Unity-Technologies/EntityComponentSystemSamples/blob/master/NetcodeSamples/README.md" target="_blank" rel="noreferrer noopener">https://github.com/Unity-Technologies/EntityComponentSystemSamples/blob/master/NetcodeSamples/README.md</a></p>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Client / Server 업데이트 주기</h4>



<p>Netcode for Entities를 사용할 때, 서버는 항상 <strong>Fixed Timestep</strong>으로 업데이트됩니다.</p>



<p>이는 클라이언트 예측을 위한 기본적인 결정론 수준을 보장하고(엄격한 결정론은 아니지만), 물리 시스템의 안정성과 프레임 레이트 독립성을 보장하기 위함입니다.</p>



<p>또한 이 패키지는 프레임당 최대 Fixed Step 반복 횟수를 제한하여 서버가 단일 프레임을 시뮬레이션하는 데 몇 초가 걸리는 상태에 빠지지 않도록 합니다.</p>



<p>중요한 점은 서버의 고정 업데이트가 <a href="https://docs.unity3d.com/Manual/class-TimeManager.html"><strong>표준 Unity 업데이트 빈도</strong></a>&nbsp;또 <strong>Unity 물리 시스템의 Fixed Timestep</strong>를 사용하지 않는다는 것입니다. </p>



<p><strong>대신 자체적인 <code>ClientServerTickRate.SimulationTickRate</code> 를 사용합니다. </strong>&#8211; 고정된 틱(tick) 간격</p>



<p>(이것은 <code>Unity.Physics</code>가 사용 중이라면 정수 배수여야 합니다. <code>ClientServerTickRate.PredictedFixedStepSimulationTickRatio</code>를 참조하세요)</p>



<p>그러나 클라이언트는 동적 타임스텝으로 업데이트됩니다. </p>



<p><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/intro-to-prediction.html" target="_blank" rel="noreferrer noopener">예측 코드만 예외</a>로, 이는 항상 서버와 동일한 고정 타임스텝으로 실행되어 두 시뮬레이션 간의 결정론적 관계를 유지하려고 합니다.</p>



<p>전체 틱과 동기화되지 않은 리프레시 레이트에 대한 예측 처리 방법을 이해하려면 <a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/intro-to-prediction.html#partial-ticks" target="_blank" rel="noreferrer noopener">부분 틱</a>을 참조하세요.</p>



<p>설정 예시:</p>



<p><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/api/Unity.NetCode.ClientServerTickRate.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.netcode@1.5/api/Unity.NetCode.ClientServerTickRate.html</a></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class MyCustomClientServerBootstrap : ClientServerBootstrap
{
   override public void Initialize(string defaultWorld)
   {
       base.Initialise(defaultWorld);
       var customTickRate = new ClientServerTickRate();
       //run at 30hz
       customTickRate.simulationTickRate = 30;
       customTickRate.ResolveDefault();
       foreach(var world in World.All)
       {
           if(world.IsServer())
           {
              // 이 경우 서버에서만 생성되지만 클라이언트 세계에서도 동일한 작업을 수행할 수 있습니다
              var tickRateEntity = world.EntityManager.CreateSingleton(new ClientServerTickRate
              {
                  SimulationTickRate = 30;
              });
           }
       }
   }
}


// SimulationTickRate = 초당 몇 번의 시뮬레이션 틱을 실행할지 설정합니다. 기본값은 초당 60 틱입니다.
// NetworkTickRate = 서버가 클라이언트에게 스냅샷(snapshot)을 전송하는 빈도를 설정합니다. 기본값은 SimulationTickRate와 동일합니다.</pre>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 성능 문제 방지</h5>



<p>서버가 설정된 시뮬레이션 틱 레이트보다 <strong>느린 속도로 업데이트될 경우</strong>, 한 프레임에서 여러 개의 시뮬레이션 틱을 처리하려고 시도합니다.</p>



<p>예를 들어, 서버의 마지막 업데이트가 16ms가 아닌 50ms가 걸렸다면, 서버는 다음 프레임에서 이를 따라잡기 위해 약 <strong>3번의 시뮬레이션 스텝</strong>을 실행합니다 (16ms × 3 ≈ 50ms).</p>



<p>이러한 동작은 <strong>성능 저하를 악화시키는 악순환</strong>을 유발할 수 있습니다:</p>



<p>서버는 더 많은 시뮬레이션 스텝을 처리해야 하므로 점점 더 느려지고, 그 결과 틱 간격을 더 많이 놓치게 됩니다.</p>



<p>위와 같은 상황을 방지하기 위해 <code>ClientServerTickRate</code>에서는 다음과 같은 설정을 제공합니다</p>



<ul class="wp-block-list">
<li><code>MaxSimulationStepsPerFrame</code><br>서버가 한 프레임 내에 수행할 수 있는 <strong>최대 시뮬레이션 스텝 수</strong>를 제한합니다.</li>



<li><code>MaxSimulationStepBatchSize</code><br>여러 틱을 <strong>하나의 배치(batch)</strong> 로 묶어 처리하도록 지시합니다. <br>이때는 <strong>델타 타임(delta time)을 곱한 값</strong>으로 단일 스텝을 실행합니다.<br>예: 2개의 스텝을 실행하는 대신, <strong>1개의 스텝</strong>만 실행하되 <strong>델타 타임을 2배</strong>로 설정하여 처리합니다.</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f6ab.png" alt="🚫" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>주의</strong>: <br><code>MaxSimulationStepBatchSize</code> 에 의한 배칭 처리는 특정 조건에서만 작동하며, 자체적인 제한 사항이 있습니다.<br>게임 로직에서 &#8220;<strong>한 시뮬레이션 스텝 = 하나의 틱</strong>&#8220;이라고 가정하지 않도록 하며, <code>TimeData.DeltaTime</code> 값을 <strong>하드코딩하지 마십시오</strong>.<br>배칭이 발생하면 <strong>서버와 클라이언트 간의 시뮬레이션 정밀도가 달라져 예측 오류</strong>가 발생할 수 있습니다.</p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270f.png" alt="✏" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 프레임 속도 유지 방식 설정</h5>



<p>서버가 유휴 상태일 때 <strong>프레임 속도를 어떻게 유지할지</strong>도 설정할 수 있습니다. </p>



<p><code>TargetFrameRateMode</code>는 서버가 틱 레이트를 유지하기 위한 <strong>유휴 시간 소비 방식</strong>을 제어합니다.</p>



<ul class="wp-block-list">
<li><strong><code>BusyWait</code></strong><br>가능한 한 빠른 속도로 계속 실행 (CPU 사용량 높음)</li>



<li><strong><code>Sleep</code></strong><br><code>Application.targetFrameRate</code>에 맞춰 대기하여 CPU 부하를 줄임</li>



<li><strong><code>Auto</code></strong><br>헤드리스(콘솔 없는) 서버에서는 <code>Sleep</code>을 사용하고, 그 외에는 <code>BusyWait</code>을 사용</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 월드 마이그레이션 (World Migration)</h4>



<p>현재 사용 중인 월드를 <strong>파괴(destroy)</strong> 하고, <strong>연결 상태를 유지한 채로 새로운 월드로 전환</strong>하고자 할 경우, <code>DriverMigrationSystem</code>을 사용할 수 있습니다.</p>



<p>이 시스템은 네트워크 전송(transport) 관련 정보를 저장 및 불러올 수 있게 해주며, <strong>매끄러운 월드 전환</strong>을 가능하게 합니다.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">public World MigrateWorld(World sourceWorld)
{
    DriverMigrationSystem migrationSystem = default;
    foreach (var world in World.All)
    {
        if ((migrationSystem = world.GetExistingSystem&lt;DriverMigrationSystem>()) != null)
            break;
    }

    var ticket = migrationSystem.StoreWorld(sourceWorld);
    sourceWorld.Dispose();

    var newWorld = migrationSystem.LoadWorld(ticket);

    // NOTE: LoadWorld는 반드시 새 월드에 필요한 시스템을 추가하기 전에 호출해야 합니다!
    // 이유: LoadWorld는 NetworkStreamReceiveSystem이 올바른 드라이버를 불러오기 위해 필요한 
    // `MigrationTicket` 컴포넌트를 생성하기 때문입니다.

    return ClientServerBootstrap.CreateServerWorld(DefaultWorld, newWorld.Name, newWorld);
}
</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p>이 기능은 예를 들어 <strong>로비에서 인게임으로 넘어가거나</strong>, <strong>씬을 바꾸면서도 연결을 유지해야 하는 경우</strong>에 매우 유용합니다.</p>



<h4 class="wp-block-heading" id="additional-resources"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2795.png" alt="➕" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Additional resources</h4>



<ul class="wp-block-list">
<li><a href="https://docs.unity3d.com/Packages/com.unity.entities@latest?subfolder=/manual/index.html" target="_blank" rel="noreferrer noopener">Entities overview</a></li>



<li><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/thin-clients.html" target="_blank" rel="noreferrer noopener">Thin clients</a></li>



<li><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/intro-to-prediction.html" target="_blank" rel="noreferrer noopener">Introduction to prediction</a></li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 네트워크 프로토콜 검사</h3>



<p><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/network-protocol-checks.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/network-protocol-checks.html</a></p>



<p>클라이언트가 서버에 연결할 때, <strong>Netcode 프로토콜 버전(NetworkProtocolVersion)</strong> 을 주고받습니다. </p>



<p>이 프로토콜에는 다음과 같은 정보가 포함되어 있습니다:</p>



<ul class="wp-block-list">
<li>Netcode 버전 (netcode version)</li>



<li>게임 버전 (game version)</li>



<li>RPC 컬렉션 (RPC collection)</li>



<li>직렬화된 컴포넌트 컬렉션 (erialized component collections)</li>
</ul>



<p>서로 호환되지 않는 게임 버전 간의 연결을 <strong>사전에 차단</strong>하여 예측할 수 없는 동작을 방지합니다.</p>



<p> <strong>RPC 컬렉션</strong>은 모든 로드된 어셈블리에서 컴파일된 RPC들의 <strong>타입과 멤버</strong>를 기반으로 해시를 계산합니다.</p>



<p><strong>Serialized Component 컬렉션</strong> 역시 Netcode for Entities가 수집한 고스트(Ghost) 컴포넌트를 기반으로 해시를 계산합니다.</p>



<p>이러한 타입 정보와 멤버들을 기반으로 계산된 <strong>해시값</strong>이 프로토콜의 일부로 사용됩니다.</p>



<p>Netcode for Entities는 기본적으로 이 해시값이 <strong>완전히 동일해야</strong> 통신이 가능하도록 설정되어 있습니다.</p>



<p>이렇게 하면 중간에 <strong>예외가 발생하는 것을 방지</strong>하고, <strong>대역폭 최적화</strong>가 가능합니다.</p>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)"/>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2728.png" alt="✨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 개발 중 발생할 수 있는 문제</h4>



<p>개발 중에는 <strong>호환 가능한 빌드조차도</strong> 이 검사 때문에 <strong>부적합한 버전으로 잘못 판단되는</strong> 경우가 있습니다.</p>



<p>예를 들어:</p>



<ul class="wp-block-list">
<li>독립 실행형 빌드와 Unity Editor에서 실행 중인 월드를 연결하려는 경우</li>



<li>Editor는 테스트용 어셈블리를 포함하고 있는데, 빌드에는 포함되어 있지 않을 경우</li>



<li>이로 인해 해시가 일치하지 않아 연결이 끊어짐</li>
</ul>



<p>이러한 <strong>엄격한 프로토콜 검사</strong>는 개발 중 테스트에 방해가 될 수 있으므로, <strong><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/manual/network-protocol-checks.html#disabling-the-check" target="_blank" rel="noreferrer noopener">비활성화</a>할 수 있습니다.</strong></p>



<p>이 프로토콜 버전 오류가 발생하면 각 피어는 사용자 코드가 읽을 수 있는 를 통해 원격 피어와의 연결을 끊고&nbsp;</p>



<p><code>NetworkStreamDisconnectReason.BadProtocolVersion</code>, 이를 사용하여 플레이어에게 해당 빌드가 대상 원격 피어와 호환되지 않음을 알립니다. </p>



<p>개발 빌드에서는 패키지가 로컬 피어에 로드된 RPC 및 고스트 유형의 전체 목록과 정렬된 목록을 나타내는 오류 로그도 출력합니다. </p>



<p>유형 불일치 문제를 해결하려면 이러한 로그를 원격 피어에서 발생한 로그와 상호 참조하세요.</p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>프로토콜 검사</strong> 해제</h5>



<p>검사를 비활성화하려면, 다음과 같이 <code>RpcCollection.DynamicAssemblyList</code>를 <code>true</code>로 설정합니다:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">[BurstCompile] // 선택 사항
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation | WorldSystemFilterFlags.ServerSimulation | WorldSystemFilterFlags.ThinClientSimulation)]
[UpdateInGroup(typeof(InitializationSystemGroup))]
[CreateAfter(typeof(RpcSystem))]
public partial struct SetRpcSystemDynamicAssemblyListSystem : ISystem
{
    public void OnCreate(ref SystemState state)
    {
        SystemAPI.GetSingletonRW&lt;RpcCollection>().ValueRW.DynamicAssemblyList = true;
        state.Enabled = false;
    }
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f6ab.png" alt="🚫" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>주의</strong>: </p>



<p>이 설정은 <code>RpcSystem.OnUpdate</code>가 실행되기 전에 적용되어야 하며,</p>



<p><code>RpcSystem.OnCreate</code> 이후에 설정되어야 합니다.</p>



<p><strong>클라이언트와 서버 모두 이 플래그 값을 동일하게 설정해야</strong> 연결이 가능합니다. (값이 다르면 프로토콜 해석 방식이 달라지기 때문)</p>



<p>이 기능을 활성화하면 다음과 같은 단점이 있습니다:</p>



<ul class="wp-block-list">
<li>각 RPC마다 <strong>6바이트의 오버헤드</strong>가 발생합니다 (ushort 인덱스 대신 해시값 전체를 전송)</li>



<li>게임 도중, 클라이언트가 <strong>알 수 없는 RPC나 고스트 타입을 수신</strong>하게 되면<br>→ 런타임 오류 발생 후 <strong>즉시 연결이 끊어짐</strong><br>→ 즉, 연결 시점이 아닌 게임 중간에 강제 종료될 수 있습니다</li>
</ul>



<p>따라서 이 설정은 <strong>개발 중 테스트 목적</strong>으로 사용하는 것이 좋으며, <strong>출시용 빌드에서는 권장되지 않습니다.</strong></p>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2795.png" alt="➕" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Additional resources</h4>



<ul class="wp-block-list">
<li><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/api/Unity.NetCode.NetworkProtocolVersion.html" target="_blank" rel="noreferrer noopener">NetworkProtocolVersion API</a></li>
</ul>



<p></p>
<p>The post <a href="https://lycos7560.com/unity/unity-netcode-for-entities-client-server-worlds/39993/">Unity Netcode for Entities &#8211; Client / Server worlds</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/unity/unity-netcode-for-entities-client-server-worlds/39993/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Unity Transport 2.5.1 Docs</title>
		<link>https://lycos7560.com/unity/unity-transport-2-5-1/39976/</link>
					<comments>https://lycos7560.com/unity/unity-transport-2-5-1/39976/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Wed, 30 Apr 2025 21:19:50 +0000</pubDate>
				<category><![CDATA[Unity]]></category>
		<category><![CDATA[개인 공부 저장용]]></category>
		<category><![CDATA[study]]></category>
		<category><![CDATA[Transport]]></category>
		<category><![CDATA[Unity Transport]]></category>
		<category><![CDATA[공부]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=39976</guid>

					<description><![CDATA[<p>API https://docs.unity3d.com/Packages/com.unity.transport@2.5/api/index.html 🔥Unity Transport? Unity Transport 2.5.1 https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/index.html Unity Transport는 멀티플레이어 게임 개발을 위한 저수준 네트워킹 라이브러리입니다. Unity의 두 가지 Netcode 솔루션인 Netcode for GameObjects(NFG)와 Netcode for Entities(NFE)의 기반으로 사용됩니다. 또한 사용자가 직접 만든 커스텀 네트워크 솔루션과 함께 사용할 수 있습니다. Unity 엔진에서 지원하는 모든 플랫폼은 UDP 소켓 또는 WebSocket을 통해 제공되는 연결 기반 추상화 [&#8230;]</p>
<p>The post <a href="https://lycos7560.com/unity/unity-transport-2-5-1/39976/">Unity Transport 2.5.1 Docs</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-f2bee75e      "
					data-scroll= "1"
					data-offset= "30"
					style=""
				>
				<div class="uagb-toc__wrap">
						<div class="uagb-toc__title">
							목차 테이블						</div>
																						<div class="uagb-toc__list-wrap ">
						<ol class="uagb-toc__list"><li class="uagb-toc__list"><a href="#unity-transport" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" />Unity Transport?</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#요구-사항" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f34e.png" alt="🍎" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 요구 사항</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#참고사항" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 참고사항</a></li></ul></li><li class="uagb-toc__list"><a href="#sample-project" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" />Sample Project</a><li class="uagb-toc__list"><a href="#간단한-클라이언트-서버" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" />간단한 클라이언트 서버</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-서버-생성" class="uagb-toc-link__trigger">1&#x20e3; 서버 생성</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#2-보일러플레이트-코드-boilerplate-code" class="uagb-toc-link__trigger">2&#x20e3; 보일러플레이트 코드 (Boilerplate Code)</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-networkdriver-선언-server" class="uagb-toc-link__trigger">1. NetworkDriver 선언  &#8211; Server</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#2-서버-초기화-start-server" class="uagb-toc-link__trigger">2. 서버 초기화 (Start) &#8211; Server</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#3-리소스-정리-ondestroy-server" class="uagb-toc-link__trigger">3. 리소스 정리 (OnDestroy)  &#8211; Server</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#4-서버-업데이트-루프-update-server" class="uagb-toc-link__trigger">4. 서버 업데이트 루프 (Update)  &#8211; Server</a></li></ul><li class="uagb-toc__list"><a href="#3-클라이언트-구현-차이점-중심-client" class="uagb-toc-link__trigger">3&#x20e3; 클라이언트 구현 (차이점 중심) &#8211; Client</a></li></ul></li></ul></li><li class="uagb-toc__list"><a href="#사용-모범-사례" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" />사용 모범 사례</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-파이프라인-사용-using-pipelines" class="uagb-toc-link__trigger">1&#x20e3; 파이프라인 사용 (Using pipelines)</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#작동-원리-how-it-works" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2753.png" alt="❓" class="wp-smiley" style="height: 1em; max-height: 1em;" />작동 원리 (How it Works)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#fragmentation-파이프라인-단계" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Fragmentation 파이프라인 단계</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#the-reliable-파이프라인-단계" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> The reliable 파이프라인 단계</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#동시-전송-가능한-패킷-수-제한" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26d4.png" alt="⛔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 동시 전송 가능한 패킷 수 제한</a></li></ul><li class="uagb-toc__list"><a href="#the-reliable-파이프라인-단계" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> The reliable 파이프라인 단계</a></li></ul><li class="uagb-toc__list"><a href="#2-jobified-클라이언트-및-서버" class="uagb-toc-link__trigger">2&#x20e3; Jobified 클라이언트 및 서버</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#3-암호화된-통신-encrypted-communications" class="uagb-toc-link__trigger">3&#x20e3; 암호화된 통신 Encrypted communications</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#4-unitylogging와-통합" class="uagb-toc-link__trigger">4&#x20e3; Unity.Logging와 통합</a></li></ul></li></ul></li></ul></li><li class="uagb-toc__list"><a href="#cross-play-support" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" />Cross-play support</a><li class="uagb-toc__list"><a href="#webgl-support" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" />WebGL support</a><li class="uagb-toc__list"><a href="#faq" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" />FAQ</a><li class="uagb-toc__list"><a href="#cross-play-support" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" />Cross-play support</a></ul></ul></ul></ol>					</div>
									</div>
				</div>
			


<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<p>API</p>



<p><a href="https://docs.unity3d.com/Packages/com.unity.transport@2.5/api/index.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.transport@2.5/api/index.html</a></p>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" />Unity Transport?</h2>



<p>Unity Transport 2.5.1 </p>



<p><a href="https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/index.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/index.html</a> </p>



<p>Unity Transport는 멀티플레이어 <strong>게임 개발을 위한 저수준 네트워킹 라이브러리</strong>입니다.</p>



<p>Unity의 두 가지 Netcode 솔루션인<strong> Netcode for GameObjects(NFG)</strong>와 <strong>Netcode for Entities(NFE)</strong>의 기반으로 사용됩니다.</p>



<p>또한 사용자가 직접 만든<strong> 커스텀 네트워크 솔루션과 함께 사용</strong>할 수 있습니다.</p>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="654" height="678" src="https://lycos7560.com/wp-content/uploads/2025/05/image.png" alt="" class="wp-image-39977" srcset="https://lycos7560.com/wp-content/uploads/2025/05/image.png 654w, https://lycos7560.com/wp-content/uploads/2025/05/image-289x300.png 289w" sizes="(max-width: 654px) 100vw, 654px" /><figcaption class="wp-element-caption"><a href="https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/index.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/index.html</a></figcaption></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>Unity 엔진에서 지원하는 모든 플랫폼은 <strong>UDP 소켓</strong> 또는 <strong>WebSocket</strong>을 통해 제공되는 <strong>연결 기반 추상화 계층(내장 네트워크 드라이버)</strong> 덕분에 Unity Transport에서 원활하게 지원됩니다. </p>



<p>둘 다 암호화 유무에 따라 설정할 수 있으며, 위 블록 다이어그램에서 닫힌 자물쇠와 열린 자물쇠로 표시됩니다.</p>



<p>특히 <strong>파이프라인</strong>은 안정성, 패킷 순서 지정 및 패킷 조각화와 같은 추가적인 선택적 기능들을 제공합니다.</p>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f34e.png" alt="🍎" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 요구 사항</h3>



<p>Unity Transport는 Unity 엔진이 지원하는 모든 플랫폼을 지원합니다.</p>



<p><strong>WebGL의 경우, 클라이언트 모드에서 WebSocket 연결만 지원</strong>되며, <a href="https://unity.com/products/relay" target="_blank" rel="noreferrer noopener">Unity Relay</a>를 사용하는 경우에는 호스팅도 가능합니다.</p>



<p>현재 문서는 <strong>Unity Transport 2.X</strong> 버전에 대한 설명이며, 이는 <strong>Unity Editor 2022.3 이상</strong>에서만 호환됩니다.</p>



<p>구 버전의 에디터는 <strong>Transport 1.X</strong>에서 지원됩니다. 아래는 호환성 표를 참고하세요.</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Editor Version</th><th>2021 LTS</th><th>2022 LTS</th><th>2023.1 and later</th></tr></thead><tbody><tr><td>Transport 1.X</td><td><strong>Yes</strong></td><td><strong>Yes</strong></td><td>No</td></tr><tr><td>Transport 2.X</td><td>No</td><td><strong>Yes</strong></td><td><strong>Yes</strong></td></tr></tbody></table></figure>



<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 참고사항</h3>



<p>이 패키지는 <strong>Netcode for GameObjects</strong>의 <strong><code>NetworkTransport</code> 추상화 계층</strong>과 혼동하면 안됩니다.</p>



<p>더 자세한 내용은 해당 &nbsp;<a href="https://docs-multiplayer.unity3d.com/netcode/current/advanced-topics/transports" target="_blank" rel="noreferrer noopener">transports section of its documentation</a>을 참고하세요.</p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" />Sample Project</h2>



<p><a href="https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/samples-usage.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/samples-usage.html</a></p>



<p>Unity Transport 패키지에는 <strong>Samples 폴더</strong>가 포함되어 있으며, 이 폴더에는 라이브러리의 기본적인 개념을 설명하는 간단한 어셈블리 정의와 관련된 씬들이 들어 있습니다.</p>



<p>이 샘플들은 <strong>패키지 매니저 창</strong>에서 Unity Transport 패키지를 선택했을 때 가져올 수 있습니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="885" height="536" src="https://lycos7560.com/wp-content/uploads/2025/05/image-1.png" alt="" class="wp-image-39978" srcset="https://lycos7560.com/wp-content/uploads/2025/05/image-1.png 885w, https://lycos7560.com/wp-content/uploads/2025/05/image-1-300x182.png 300w, https://lycos7560.com/wp-content/uploads/2025/05/image-1-768x465.png 768w" sizes="(max-width: 885px) 100vw, 885px" /><figcaption class="wp-element-caption">Unity Transport Sample</figcaption></figure>



<ul class="wp-block-list">
<li><strong>Cross-play Example</strong> : MultiNetworkDriver를 사용하여 UDP와 WebSocket 연결을 모두 허용하는 서버를 만드는 방법의 예입니다.</li>



<li><strong>Jobified Client and Server</strong> : 작업을 사용하는 매우 간단한 클라이언트 및 서버 구현. 패키지 문서와 연계되도록 설계되었습니다.</li>



<li><strong>Ping</strong> <strong>Sample</strong> : 클라이언트와 서버 간 왕복 시간(핑)을 계산하는 소규모 애플리케이션입니다.</li>



<li><strong>Relay Sample(with Relay)</strong> : 유니티 릴레이를 사용하여 클라이언트와 호스트 간의 왕복 시간(핑)을 계산하는 작은 애플리케이션</li>



<li><strong>SimpleClientServer</strong> : 가장 간단한 클라이언트 및 서버 구현. 패키지 문서와 연계되도록 설계되었습니다.</li>
</ul>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" />간단한 클라이언트 서버</h2>



<p><a href="https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/client-server-simple.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/client-server-simple.html</a></p>



<p>이 예제는 Unity Transport 패키지의 모든 주요 기능을 다루며, 다음과 같은 API 사용법을 보여주는 샘플 프로젝트를 만드는 데 도움을 줍니다:</p>



<ul class="wp-block-list">
<li>전송 구성 (Configure the transport)</li>



<li>연결 수립 (Establish a connection)</li>



<li>데이터 전송 (Send data)</li>



<li>데이터 수신 (Receive data)</li>



<li>연결 종료 (Close a connection)</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="647" height="940" src="https://lycos7560.com/wp-content/uploads/2025/05/image-2.png" alt="" class="wp-image-39980" srcset="https://lycos7560.com/wp-content/uploads/2025/05/image-2.png 647w, https://lycos7560.com/wp-content/uploads/2025/05/image-2-206x300.png 206w" sizes="(max-width: 647px) 100vw, 647px" /><figcaption class="wp-element-caption">원격 &#8220;덧셈(add)&#8221; 기능을 구현</figcaption></figure>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">1&#x20e3; 서버 생성</h3>



<p>서버는 들어오는 연결 요청을 듣고 메시지를 주고받는 엔드포인트를 생성합니다.</p>



<p><strong>ServerBehaviour.cs</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ServerBehaviour : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">2&#x20e3; 보일러플레이트 코드 (Boilerplate Code)</h3>



<p>반복되는 작업이나 패턴에 대한 일종의 표준화된 코드인 Boilerplate를 생성합니다.</p>



<p>이 패키지는 <strong>완전한 제어권</strong>을 가지도록 선택한 아키텍처 설계로 저수준 API만 제공합니다. </p>



<p>따라서 약간의 Boilerplate 코드를 설정해야합니다.</p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading">1. <strong><strong>NetworkDriver 선언</strong></strong>  &#8211; Server</h4>



<p><strong>ServerBehaviour.cs</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using UnityEngine;
using Unity.Collections;
using Unity.Networking.Transport;

public class ServerBehaviour : MonoBehaviour 
{
    NetworkDriver m_Driver;
    NativeList&lt;NetworkConnection> m_Connections;
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<ul class="wp-block-list">
<li><strong>NetworkDriver</strong>: Unity Transport 패키지의 핵심 API로, 네트워크 통신을 제어합니다.</li>



<li><strong>NativeList</strong>: 서버에 연결된 클라이언트들의 연결 정보를 저장하는 컨테이너 (Unmanaged Memory 사용).</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading">2. <strong>서버 초기화</strong> (Start) &#8211; Server</h4>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">void Start()
{
    m_Driver = NetworkDriver.Create();
    m_Connections = new NativeList&lt;NetworkConnection>(16, Allocator.Persistent);

    var endpoint = NetworkEndpoint.AnyIpv4.WithPort(7777);
    if (m_Driver.Bind(endpoint) != 0)
    {
        Debug.LogError("Failed to bind to port 7777.");
        return;
    }
    m_Driver.Listen();
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<ol class="wp-block-list">
<li>드라이버 생성 → 연결 리스트 초기화 (최대 16개 연결 수용)</li>



<li>모든 IPv4 주소(<code>AnyIpv4</code>)에서 7777 포트로 바인딩 시도</li>



<li>성공 시&nbsp;<code>Listen()</code>으로 클라이언트 연결 대기 시작.</li>
</ol>



<ol class="wp-block-list">
<li></li>
</ol>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading">3. <strong>리소스 정리 (OnDestroy)</strong>  &#8211; Server</h4>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">void OnDestroy() 
{
    if (m_Driver.IsCreated) {
        m_Driver.Dispose();
        m_Connections.Dispose();
    }
}</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<ul class="wp-block-list">
<li><strong>Unmanaged Memory</strong>를 직접 해제해야 <strong>메모리 누수 방지</strong></li>



<li><code>IsCreated</code>로 할당 여부 확인 후 해제</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading">4. <strong><strong>서버 업데이트 루프 (Update)</strong></strong>  &#8211; Server</h4>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">void Update() 
{
    m_Driver.ScheduleUpdate().Complete();

    // 1. 오래된 연결 정리
    for (int i = 0; i &lt; m_Connections.Length; i++) {
        if (!m_Connections[i].IsCreated) {
            m_Connections.RemoveAtSwapBack(i);
            i--;
        }
    }

    // 2. 새 연결 수락
    NetworkConnection c;
    while ((c = m_Driver.Accept()) != default) {
        m_Connections.Add(c);
        Debug.Log("클라이언트 연결 수락");
    }

    // 3. 연결별 이벤트 처리
    for (int i = 0; i &lt; m_Connections.Length; i++) {
        DataStreamReader stream;
        NetworkEvent.Type cmd;
        while ((cmd = m_Driver.PopEventForConnection(m_Connections[i], out stream)) 
               != NetworkEvent.Type.Empty) {
            
            if (cmd == NetworkEvent.Type.Data) {
                uint number = stream.ReadUInt();
                Debug.Log($"클라이언트로부터 {number} 수신, +2 처리");

                number += 2;
                m_Driver.BeginSend(NetworkPipeline.Null, m_Connections[i], out var writer);
                writer.WriteUInt(number);
                m_Driver.EndSend(writer);
            }
            else if (cmd == NetworkEvent.Type.Disconnect) {
                Debug.Log("클라이언트 연결 종료");
                m_Connections[i] = default;
            }
        }
    }
}</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<ul class="wp-block-list">
<li><strong>데이터 수신</strong>: 클라이언트가 보낸 숫자를 읽어 +2 후 재전송.</li>



<li><strong>연결 종료</strong>:&nbsp;<code>Disconnect</code>&nbsp;이벤트 시 연결 리셋.</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">3&#x20e3; <strong>클라이언트 구현 (차이점 중심)</strong> &#8211; Client</h3>



<p><strong>ClientBehaviour.cs</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">public class ClientBehaviour : MonoBehaviour {
    NetworkDriver m_Driver;
    NetworkConnection m_Connection; // 단일 연결만 관리

    void Start() {
        m_Driver = NetworkDriver.Create();
        m_Connection = m_Driver.Connect(NetworkEndpoint.LoopbackIpv4.WithPort(7777));
    }

    void Update() {
        m_Driver.ScheduleUpdate().Complete();

        if (!m_Connection.IsCreated) return;

        DataStreamReader stream;
        NetworkEvent.Type cmd;
        while ((cmd = m_Connection.PopEvent(m_Driver, out stream)) 
               != NetworkEvent.Type.Empty) {
            
            if (cmd == NetworkEvent.Type.Connect) {
                Debug.Log("서버 연결 성공");
                uint value = 1;
                m_Driver.BeginSend(m_Connection, out var writer);
                writer.WriteUInt(value);
                m_Driver.EndSend(writer);
            }
            else if (cmd == NetworkEvent.Type.Data) {
                uint value = stream.ReadUInt();
                Debug.Log($"서버로부터 값 수신: {value}");
                m_Connection.Disconnect(m_Driver);
                m_Connection = default;
            }
            else if (cmd == NetworkEvent.Type.Disconnect) {
                Debug.Log("서버와 연결 종료");
                m_Connection = default;
            }
        }
    }
}</pre>



<p><strong>클라이언트 특이사항</strong>:</p>



<ul class="wp-block-list">
<li><strong>단일 연결</strong>:&nbsp;<code>NetworkConnection</code>&nbsp;하나만 관리.</li>



<li><strong>Connect 이벤트</strong>: 연결 성공 시 서버로 숫자&nbsp;<code>1</code>&nbsp;전송.</li>



<li><strong>데이터 처리</strong>: 서버 응답 후 즉시 연결 종료.</li>
</ul>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" />&nbsp;<strong>중요</strong>: </p>



<p>모든 네트워크 작업은&nbsp;<strong>비동기 Job 시스템</strong>&nbsp;기반으로 동작하지만, 이 예제에서는&nbsp;<code>Complete()</code>로 강제 동기화하여 간단히 구현했습니다.</p>



<p>실제 프로젝트에서는 Job 체인을 활용한 최적화가 필요합니다.</p>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<p><strong>ServerBehaviour.cs</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using Unity.Collections;
using Unity.Networking.Transport;
using UnityEngine;

namespace UnityNetworkingTransportSimpleTest
{
    public class ServerBehaviour : MonoBehaviour
    {

        NetworkDriver m_Driver;
        NativeList&lt;NetworkConnection> m_Connections; // 연결된 클라이언트 목록

        private void Start()
        {
            m_Driver = NetworkDriver.Create(); // NetworkDriver 생성
            m_Connections = new NativeList&lt;NetworkConnection>(16, Allocator.Persistent); // 최대 16개의 연결을 허용하는 NativeList 생성 (영구 할당)

            var endpoint = NetworkEndpoint.AnyIpv4.WithPort(7777); // 모든 IPv4 주소의 7777 포트에서 수신 대기
            if (m_Driver.Bind(endpoint) != 0)
            {
                Debug.LogError("포트 7777 바인딩 실패"); // 포트 바인딩 실패 시 에러 로그 출력
                return;
            }
            m_Driver.Listen(); // 들어오는 연결 요청 수신 시작
        }

        private void Update()
        {
            m_Driver.ScheduleUpdate().Complete(); // 네트워크 업데이트 스케줄링 및 완료

            // 1. 오래된 연결 정리
            for (int i = 0; i &lt; m_Connections.Length; i++)
            {
                if (!m_Connections[i].IsCreated) { // 연결이 끊어진 클라이언트 정리
                    m_Connections.RemoveAtSwapBack(i); // 연결 리스트에서 제거
                    i--; // 인덱스 조정
                }
            }

            // 2. 새 연결 수락
            NetworkConnection newNetworkConnection;
            while ((newNetworkConnection = m_Driver.Accept()) != default)
            {
                m_Connections.Add(newNetworkConnection); // 새로운 연결을 연결 리스트에 추가
                Debug.Log("클라이언트 연결 수락"); // 클라이언트 연결 수락 시 로그 출력
            }

            // 3. 연결별 이벤트 처리
            for (int i = 0; i &lt; m_Connections.Length; i++)
            {
                DataStreamReader stream;
                NetworkEvent.Type cmd;
                while ((cmd = m_Driver.PopEventForConnection(m_Connections[i], out stream)) != NetworkEvent.Type.Empty)
                {

                    if (cmd == NetworkEvent.Type.Data)
                    {
                        uint number = stream.ReadUInt(); // 수신된 데이터에서 unsigned integer 값 읽기
                        Debug.Log($"클라이언트로부터 {number} 수신, +2 처리"); // 클라이언트로부터 받은 값 로그 출력 및 처리 내용 설명

                        number += 2; // 받은 값에 2를 더함
                        m_Driver.BeginSend(NetworkPipeline.Null, m_Connections[i], out var writer); // 클라이언트에게 메시지 전송 시작 (신뢰성 없는 파이프라인 사용)
                        writer.WriteUInt(number); // 처리된 unsigned integer 값 쓰기
                        m_Driver.EndSend(writer); // 메시지 전송 완료
                    }
                    else if (cmd == NetworkEvent.Type.Disconnect)
                    {
                        Debug.Log("클라이언트 연결 종료"); // 클라이언트 연결이 종료되었을 때 로그 출력
                        m_Connections[i] = default; // 연결 상태 초기화
                    }
                }
            }
        }

        private void OnDestroy()
        {
            if (m_Driver.IsCreated)
            {
                m_Driver.Dispose(); // NetworkDriver 자원 해제
                m_Connections.Dispose(); // 연결 리스트 자원 해제
            }
        }
    }
}</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p>ClientBehaviour.cs</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using Unity.Collections;
using Unity.Networking.Transport;
using UnityEngine;

namespace UnityNetworkingTransportSimpleTest
{
    public class ClientBehaviour : MonoBehaviour
    {
        NetworkDriver m_Driver;
        NetworkConnection m_Connection; // 클라이언트는 단일 연결만 관리

        private void Start()
        {
            m_Driver = NetworkDriver.Create(); // NetworkDriver 생성
            m_Connection = m_Driver.Connect(NetworkEndpoint.LoopbackIpv4.WithPort(7777)); // 루프백 주소의 7777 포트로 서버에 연결 시도
        }

        private void Update()
        {
            m_Driver.ScheduleUpdate().Complete(); // 네트워크 업데이트 스케줄링 및 완료

            if (!m_Connection.IsCreated) return; // 연결이 생성되지 않았으면 더 이상 진행하지 않음

            DataStreamReader stream;
            NetworkEvent.Type cmd;
            while ((cmd = m_Connection.PopEvent(m_Driver, out stream)) != NetworkEvent.Type.Empty) { // 연결에서 발생한 네트워크 이벤트 처리

                if (cmd == NetworkEvent.Type.Connect)
                {
                    Debug.Log("서버 연결 성공"); // 서버 연결 성공 시 로그 출력
                    uint value = 1;
                    m_Driver.BeginSend(m_Connection, out var writer); // 메시지 전송 시작
                    writer.WriteUInt(value); // unsigned integer 값 쓰기
                    m_Driver.EndSend(writer); // 메시지 전송 완료
                }
                else if (cmd == NetworkEvent.Type.Data)
                {
                    uint value = stream.ReadUInt(); // 수신된 데이터에서 unsigned integer 값 읽기
                    Debug.Log($"서버로부터 값 수신: {value}"); // 서버로부터 받은 값 로그 출력
                    m_Connection.Disconnect(m_Driver); // 서버와 연결 종료
                    m_Connection = default; // 연결 상태 초기화
                }
                else if (cmd == NetworkEvent.Type.Disconnect)
                {
                    Debug.Log("서버와 연결 종료"); // 서버와 연결이 종료되었을 때 로그 출력
                    m_Connection = default; // 연결 상태 초기화
                }
            }
        }
    }
}</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="1246" height="199" src="https://lycos7560.com/wp-content/uploads/2025/05/image-3.png" alt="" class="wp-image-39981" srcset="https://lycos7560.com/wp-content/uploads/2025/05/image-3.png 1246w, https://lycos7560.com/wp-content/uploads/2025/05/image-3-300x48.png 300w, https://lycos7560.com/wp-content/uploads/2025/05/image-3-768x123.png 768w" sizes="(max-width: 1246px) 100vw, 1246px" /></figure>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" />사용 모범 사례</h2>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">1&#x20e3; 파이프라인 사용 (Using pipelines)</h3>



<p><a href="https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/pipelines-usage.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/pipelines-usage.html</a></p>



<p>파이프라인(Pipelines)은 Unity Transport의 핵심 기능으로, 기본 제공되는&nbsp;<strong>비신뢰성 데이터그램(unreliable datagrams)</strong>&nbsp;위에 선택적 기능 계층을 추가할 수 있게 해줍니다.</p>



<p><strong>주요 적용 기능</strong>: 순서 보장(sequencing), 신뢰성(reliability), 패킷 분할(fragmentation) 등.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2753.png" alt="❓" class="wp-smiley" style="height: 1em; max-height: 1em;" />작동 원리 (How it Works)</h4>



<p>파이프라인은 하나 이상의 스테이지로 구성된 순서로 정의됩니다. </p>



<p>메시지가 파이프라인을 통해 전송되면 스테이지를 순서대로 거치며, 첫 번째 스테이지의 출력이 두 번째 스테이지로 파이프됩니다. </p>



<p>따라서 첫 번째 스테이지에서 패킷에 헤더를 추가하면 두 번째 스테이지는 이 헤더를 포함한 전체 패킷을 처리합니다. </p>



<p>메시지가 수신되면 스테이지 체인을 역순으로 거칩니다.</p>



<figure class="wp-block-image size-full"><img decoding="async" width="445" height="346" src="https://lycos7560.com/wp-content/uploads/2025/05/image-4.png" alt="" class="wp-image-39983" srcset="https://lycos7560.com/wp-content/uploads/2025/05/image-4.png 445w, https://lycos7560.com/wp-content/uploads/2025/05/image-4-300x233.png 300w" sizes="(max-width: 445px) 100vw, 445px" /><figcaption class="wp-element-caption"><a href="https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/pipelines-usage.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/pipelines-usage.html</a></figcaption></figure>



<p>예를 들어 <code>FragmentationPipelineStage</code>는 큰 메시지를 더 작은 조각으로 나누는 것을 가능하게 하고, </p>



<p><code>ReliableSequencedPipelineStage</code>는 메시지를 순서와 전달을 보장하며 전송하는 것을 가능하게 합니다. </p>



<p>두 기능 모두를 제공하는 파이프라인을 만들고 싶다면 다음과 같이 만들 수 있습니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// In initialization code, before any connections are made.
var myPipeline = driver.CreatePipeline(typeof(FragmentationPipelineStage), typeof(ReliableSequencedPipelineStage));</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>이렇게 하면 메시지를 먼저 패킷에 맞게 더 작은 조각으로 분할한 다음, 각 조각이 <strong>신뢰성 있게</strong> 그리고 <strong>올바른 순서대로</strong> 전달되는 파이프라인이 생성됩니다.</p>



<p>이 과정은 아래 그림과 같이 설명됩니다. 조각에 있는 작은 주황색 부분은 <strong>순서 번호</strong>와 <strong>신뢰성 단계에서 추가된 기타 정보</strong>를 나타냅니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="1654" height="885" src="https://lycos7560.com/wp-content/uploads/2025/05/image-5.png" alt="" class="wp-image-39984" style="width:1003px;height:auto" srcset="https://lycos7560.com/wp-content/uploads/2025/05/image-5.png 1654w, https://lycos7560.com/wp-content/uploads/2025/05/image-5-300x161.png 300w, https://lycos7560.com/wp-content/uploads/2025/05/image-5-768x411.png 768w, https://lycos7560.com/wp-content/uploads/2025/05/image-5-1536x822.png 1536w" sizes="(max-width: 1654px) 100vw, 1654px" /><figcaption class="wp-element-caption"><a href="https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/pipelines-usage.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/pipelines-usage.html</a></figcaption></figure>



<p><strong>단계의 순서가 중요하다는 점에 유의하세요.</strong></p>



<p>만약 단계를 거꾸로 구성했다면, 신뢰성 정보는 <strong>분할되지 않은 큰 메시지</strong>에만 추가되었을 것입니다.</p>



<p>이 경우, <strong>조각 중 하나라도 손실되면 전체 메시지를 다시 전송해야 하므로</strong> 대역폭 효율이 떨어집니다.</p>



<p>하지만 <strong>신뢰성 단계(reliable stage)를 분할 단계(fragmentation) 이후에</strong> 배치하면, <strong>조각 하나가 손실되더라도 그 조각만 다시 전송하면 되므로 더 효율적</strong>입니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>새로운 파이프라인에서 메시지를 전송하려면 </p>



<p><code>BeginSend</code>를 사용할 수 있습니다:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">driver.BeginSend(myPipeline, connection, out var writer);</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>메시지를 어느 파이프라인으로 받았는지 확인하려면 </p>



<p><code>PopEvent</code> 또는 <code>PopEventForConnection</code>의 마지막 인자를 사용하세요:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">var eventType = driver.PopEvent(out _, out _, out var receivePipeline);
if (eventType == NetworkEvent.Type.Data)
{
    // 데이터 메시지는 receivePipeline 파이프라인에서 수신되었습니다.
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f514.png" alt="🔔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>주의</strong></p>



<p>파이프라인은 서버와 클라이언트에서 항상 <strong>같은 방식으로 구성</strong>되어야 합니다.</p>



<p>즉, <code>CreatePipeline</code> 호출과 그 순서는 <strong>양쪽에서 동일</strong>해야 합니다.</p>



<p>Unity Transport는 이러한 불일치를 자동으로 막아주지 않으므로, <strong>파이프라인 생성 코드는 서버와 클라이언트 간에 공유하는 것을 권장</strong>합니다.</p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Fragmentation 파이프라인 단계</h4>



<p><a href="https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/pipelines-usage.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/pipelines-usage.html</a></p>



<p>기본적으로 Unity Transport는 <strong>MTU(약 1400바이트)</strong> 안에 들어가는 크기의 메시지만 전송할 수 있습니다.</p>



<p>더 큰 메시지를 보내기 위해서는 이를 더 작은 조각으로 분할해야 하며, 이를 <strong>메시지 분할(Fragmentation)</strong> 이라고 합니다.</p>



<p><code>FragmentationPipelineStage</code>가 포함된 파이프라인을 구성하면, 메시지를 자동으로 분할해 줍니다.</p>



<p>분할 전 최대 페이로드 크기는 <code>NetworkDriver</code>를 생성할 때 설정할 수 있습니다:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">var settings = new NetworkSettings();
settings.WithFragmentationStageParameters(payloadCapacity: 10000);

var driver = NetworkDriver.Create(settings);
var fragmentedPipeline = driver.CreatePipeline(typeof(FragmentationPipelineStage));
</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<p>설정 가능한 <strong>최대 값은 약 20MB</strong>이지만, 이 파이프라인 단계는 <strong>수 킬로바이트 크기의 페이로드</strong>에 최적화되어 있습니다.</p>



<p>기본값은 <strong>4096바이트</strong>이며, 이보다 훨씬 큰 메시지는 초기화 시점에 한 번 보내는 정도로만 사용하는 것을 권장합니다.</p>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4cc.png" alt="📌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>참고:</strong> </p>



<p>여러 파이프라인 단계를 조합할 경우, <code>FragmentationPipelineStage</code>는 <strong>일반적으로 가장 먼저 배치</strong>되어야 합니다.</p>



<p>대부분의 파이프라인 단계는 <strong>MTU보다 큰 패킷을 지원하지 않기 때문입니다.</strong></p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> The reliable 파이프라인 단계</h4>



<p><a href="https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/pipelines-usage.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/pipelines-usage.html</a></p>



<p><code>ReliableSequencedPipelineStage</code>를 사용한 파이프라인은 <strong>TCP처럼 패킷의 순서 보장과 안정적인 전송</strong>을 보장합니다.</p>



<ul class="wp-block-list">
<li>패킷은 <strong>시퀀스 번호</strong>로 태그되며, 상대는 이 번호의 수신을 확인합니다.</li>



<li>수신 확인이 되지 않으면 패킷은 <strong>재전송</strong>됩니다.</li>



<li>순서가 어긋난 패킷은 <strong>버퍼에 저장</strong>되고, 이전 패킷이 도착할 때까지 대기합니다.</li>
</ul>



<p>이 기능은 유용하지만, <strong>멀티플레이어 게임에서는 과도하게 사용하면 성능에 악영향</strong>을 줄 수 있습니다.</p>



<p>신뢰성 있는 데이터 스트림은 <strong>헤드 오브 라인 블로킹(Head-of-line blocking)</strong> 으로 인해 지연이 발생할 수 있습니다.</p>



<p>따라서 <strong>정말 중요한 데이터</strong> (예: <strong>RPC 호출, 캐릭터 동작</strong> 등)에만 이 단계를 사용하는 것을 권장합니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26d4.png" alt="⛔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 동시 전송 가능한 패킷 수 제한</h5>



<p>Reliable 단계는 <strong>동시에 전송 가능한 패킷 수가 제한</strong>됩니다.</p>



<p>기본값은 <strong>32개</strong>, 최대 <strong>64개</strong>까지 늘릴 수 있습니다.</p>



<p>이 제한은 <strong>연결별, 파이프라인별</strong>로 적용되며, 공유되지 않습니다.</p>



<p><strong>팁:</strong> 가능한 한 신뢰성 있는 메시지를 <strong>배치(Batching)</strong> 하세요. 예: 20바이트짜리 메시지 2개를 따로 보내는 대신 40바이트로 묶어 한 번에 전송.</p>



<p>만약 이미 32개의 패킷이 전송 대기 중인 상황에서 또 보내려고 하면, <code>EndSend</code>는 <code>NetworkSendQueueFull</code> (값: -5)을 반환합니다.</p>



<p>이 경우 메시지를 큐에 저장하고 나중에 재전송하세요:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">driver.BeginSend(myReliablePipeline, connection, out var writer);
// 메시지 작성
if (driver.EndSend(writer) == (int)Error.StatusCode.NetworkSendQueueFull)
{
    // 메시지를 큐에 저장 후 나중에 재전송
}</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// 제한 늘리기

var settings = new NetworkSettings();
settings.WithReliableStageParameters(windowSize: 64);


var driver = NetworkDriver.Create(settings);
var reliablePipeline = driver.CreatePipeline(typeof(ReliableSequencedPipelineStage));

// 기본값은 32, 최대는 64입니다.
// 32보다 큰 값을 사용할 경우 헤더 크기가 약간 증가(4바이트) 하며, 실제 데이터 공간은 그만큼 줄어듭니다.
</pre>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> The reliable 파이프라인 단계</h4>



<p><a href="https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/pipelines-usage.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/pipelines-usage.html</a></p>



<p><code>SimulatorPipelineStage</code>는 <strong>앱 테스트용</strong>으로 사용되며, <strong>패킷 손실, 지연, 지터</strong> 등의 다양한 네트워크 조건을 시뮬레이션할 수 있습니다.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">var settings = new NetworkSettings();
settings.WithSimulatorStageParameters(
    maxPacketCount: 100,
    mode: ApplyMode.AllPackets,
    packetDelayMs: 50);

var driver = NetworkDriver.Create(settings);
var simulatorPipeline = driver.CreatePipeline(typeof(SimulatorPipelineStage));


// maxPacketCount: 지연 가능한 최대 패킷 수. 이 수를 초과하면 지연 없이 전달됩니다.
// mode: 어떤 방향에 시뮬레이션을 적용할지 설정 (보내기, 받기, 또는 모두).
// packetDelayMs: 적용할 지연 시간 (ms). 일반 브로드밴드는 20ms, 열악한 모바일은 최대 200ms.
// packetJitterMs: 지연의 편차. 일반적으로 지연의 절반 이하가 적당합니다.
// packetDropPercentage: 손실할 패킷의 비율 (%). 나쁜 모바일 환경에서도 보통 3%를 넘지 않습니다.
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4cc.png" alt="📌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>참고:</strong> </p>



<p>여러 단계로 구성된 파이프라인에서 <code>SimulatorPipelineStage</code>는 <strong>가장 마지막에 배치</strong>해야 합니다.</p>



<p>그렇지 않으면 <strong>다른 단계에서 처리되기 전에 패킷이 손실</strong>되어 의미가 없어질 수 있습니다 (예: Reliable 단계와 함께 사용할 경우).</p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">2&#x20e3; Jobified 클라이언트 및 서버</h3>



<p><a href="https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/client-server-jobs.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/client-server-jobs.html</a></p>



<p><strong>Client 코드 (JobifiedClientBehaviour.cs)</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Networking.Transport;

namespace Unity.Networking.Transport.Samples
{
    public class JobifiedClientBehaviour : MonoBehaviour
    {
        NetworkDriver m_Driver;
        NativeArray&lt;NetworkConnection> m_Connection;

        JobHandle m_ClientJobHandle;

        void Start()
        {
            // 네트워크 드라이버 생성 및 초기화
            m_Driver = NetworkDriver.Create();
            m_Connection = new NativeArray&lt;NetworkConnection>(1, Allocator.Persistent);

            // 로컬 호스트(127.0.0.1)의 포트 7777에 연결 시도
            var endpoint = NetworkEndpoint.LoopbackIpv4.WithPort(7777);
            m_Connection[0] = m_Driver.Connect(endpoint);
        }

        void OnDestroy()
        {
            // 이전 프레임의 잡이 모두 완료되도록 대기 후, 네이티브 리소스 해제
            m_ClientJobHandle.Complete();
            m_Driver.Dispose();
            m_Connection.Dispose();
        }

        void Update()
        {
            // 이전 프레임에서 스케줄된 작업 완료 대기
            m_ClientJobHandle.Complete();

            // 클라이언트 업데이트 작업 생성 및 설정
            var job = new ClientUpdateJob
            {
                Driver = m_Driver,
                Connection = m_Connection,
            };

            // 네트워크 드라이버 업데이트 스케줄링
            m_ClientJobHandle = m_Driver.ScheduleUpdate();

            // 클라이언트 작업 스케줄링 (드라이버 업데이트 이후 실행되도록 설정)
            m_ClientJobHandle = job.Schedule(m_ClientJobHandle);
        }

        // 클라이언트 상태를 업데이트하는 IJob 기반 작업
        struct ClientUpdateJob : IJob
        {
            public NetworkDriver Driver;
            public NativeArray&lt;NetworkConnection> Connection;

            public void Execute()
            {
                // 연결이 유효하지 않으면 조기 종료
                if (!Connection[0].IsCreated)
                {
                    return;
                }

                DataStreamReader stream;
                NetworkEvent.Type cmd;

                // 이벤트 루프를 통해 네트워크 이벤트 처리
                while ((cmd = Connection[0].PopEvent(Driver, out stream)) != NetworkEvent.Type.Empty)
                {
                    if (cmd == NetworkEvent.Type.Connect)
                    {
                        Debug.Log("서버에 연결됨.");

                        // 서버에 uint 값 1을 전송
                        uint value = 1;
                        Driver.BeginSend(Connection[0], out var writer);
                        writer.WriteUInt(value);
                        Driver.EndSend(writer);
                    }
                    else if (cmd == NetworkEvent.Type.Data)
                    {
                        // 서버로부터 데이터를 수신하고 출력
                        uint value = stream.ReadUInt();
                        Debug.Log($"서버로부터 받은 값: {value}");

                        // 데이터 수신 후 연결 종료
                        Driver.Disconnect(Connection[0]);
                        Connection[0] = default;
                    }
                    else if (cmd == NetworkEvent.Type.Disconnect)
                    {
                        // 서버에서 연결이 종료되었음을 로그에 기록하고 상태 초기화
                        Debug.Log("서버와의 연결이 종료됨.");
                        Connection[0] = default;
                    }
                }
            }
        }
    }
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><strong>Server 코드 (JobifiedServerBehaviour.cs)</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Networking.Transport;

namespace Unity.Networking.Transport.Samples
{
    public class JobifiedServerBehaviour : MonoBehaviour
    {
        NetworkDriver m_Driver;
        NativeList&lt;NetworkConnection> m_Connections;

        JobHandle m_ServerJobHandle;

        void Start()
        {
            // 네트워크 드라이버 생성 및 초기화
            m_Driver = NetworkDriver.Create();
            m_Connections = new NativeList&lt;NetworkConnection>(16, Allocator.Persistent);

            // 포트 7777에 바인딩 시도
            var endpoint = NetworkEndpoint.AnyIpv4.WithPort(7777);
            if (m_Driver.Bind(endpoint) != 0)
            {
                Debug.LogError("포트 7777 바인딩 실패.");
                return;
            }

            // 클라이언트 연결 대기 시작
            m_Driver.Listen();
        }

        void OnDestroy()
        {
            if (m_Driver.IsCreated)
            {
                // 모든 잡 완료 후 리소스 해제
                m_ServerJobHandle.Complete();
                m_Driver.Dispose();
                m_Connections.Dispose();
            }
        }

        void Update()
        {
            // 이전 프레임의 잡 완료 대기
            m_ServerJobHandle.Complete();

            // 끊긴 연결 제거 및 새 연결 수락을 처리하는 잡 생성
            var connectionJob = new ServerUpdateConnectionsJob
            {
                Driver = m_Driver,
                Connections = m_Connections
            };

            // 클라이언트별로 데이터 수신 및 응답을 처리하는 병렬 잡 생성
            var serverUpdateJob = new ServerUpdateJob
            {
                Driver = m_Driver.ToConcurrent(),
                Connections = m_Connections.AsDeferredJobArray()
            };

            // 드라이버 업데이트 → 연결 처리 → 데이터 처리 순으로 잡 체인 스케줄링
            m_ServerJobHandle = m_Driver.ScheduleUpdate();
            m_ServerJobHandle = connectionJob.Schedule(m_ServerJobHandle);
            m_ServerJobHandle = serverUpdateJob.Schedule(m_Connections, 1, m_ServerJobHandle);
        }

        // 끊긴 연결을 정리하고 새 연결을 수락하는 작업
        struct ServerUpdateConnectionsJob : IJob
        {
            public NetworkDriver Driver;
            public NativeList&lt;NetworkConnection> Connections;

            public void Execute()
            {
                // 유효하지 않은 연결 제거
                for (int i = 0; i &lt; Connections.Length; i++)
                {
                    if (!Connections[i].IsCreated)
                    {
                        Connections.RemoveAtSwapBack(i);
                        i--;
                    }
                }

                // 새 클라이언트 연결 수락
                NetworkConnection c;
                while ((c = Driver.Accept()) != default)
                {
                    Connections.Add(c);
                    Debug.Log("클라이언트 연결 수락됨.");
                }
            }
        }

        // 각 연결로부터 데이터를 수신하고 처리하는 병렬 작업
        struct ServerUpdateJob : IJobParallelForDefer
        {
            public NetworkDriver.Concurrent Driver;
            public NativeArray&lt;NetworkConnection> Connections;

            public void Execute(int i)
            {
                DataStreamReader stream;
                NetworkEvent.Type cmd;

                // 클라이언트 이벤트 루프
                while ((cmd = Driver.PopEventForConnection(Connections[i], out stream)) != NetworkEvent.Type.Empty)
                {
                    if (cmd == NetworkEvent.Type.Data)
                    {
                        // 숫자 수신 후 2를 더해 응답
                        uint number = stream.ReadUInt();
                        Debug.Log($"클라이언트로부터 {number} 수신. 2를 더해 전송.");

                        number += 2;

                        Driver.BeginSend(Connections[i], out var writer);
                        writer.WriteUInt(number);
                        Driver.EndSend(writer);
                    }
                    else if (cmd == NetworkEvent.Type.Disconnect)
                    {
                        // 연결 해제 처리
                        Debug.Log("클라이언트 연결 해제됨.");
                        Connections[i] = default;
                    }
                }
            }
        }
    }
}
</pre>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">3&#x20e3; 암호화된 통신 Encrypted communications</h3>



<p><a href="https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/client-server-secure.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/client-server-secure.html</a></p>



<p>Unity Transport 패키지는 서버/클라이언트의 신뢰성을 보장하는 동시에 서버와 클라이언트 간의 연결을 암호화하도록 구성할 수 있습니다.</p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading">4&#x20e3; Unity.Logging와 통합</h3>



<p><a href="https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/logging.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/logging.html</a></p>



<p>Unity Transport는 Unity Logging 패키지( )와의 선택적 통합을 제공합니다.</p>



<p><code>com.unity.logging package</code>. 이 패키지는 기존 Unity 로깅 메커니즘에 대한 유연한 대안으로, 특히 프로덕션 서버에 유용합니다.</p>



<p>일반적으로 로그 메시지는 모두 를 거쳐 전송되지만&nbsp;<code>UnityEngine.Debug.Log</code>, 로깅 패키지가 프로젝트에 포함되면 Unity Transport는 자동으로&nbsp;<code>Unity.Logging</code>기본 로거 설정을 사용합니다.</p>



<p>특정 로그 설정을 조정하는 방법에 대한 자세한 내용은&nbsp;<a href="https://docs.unity3d.com/Packages/com.unity.logging@latest" target="_blank" rel="noreferrer noopener">로깅 패키지 설명서 사이트를</a>&nbsp;확인하세요.</p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" />Cross-play support</h2>



<p><a href="https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/cross-play.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/cross-play.html</a></p>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" />WebGL support</h2>



<p><a href="https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/websockets.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/websockets.html</a></p>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" />FAQ</h2>



<p><a href="https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/faq.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/faq.html</a></p>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" />Cross-play support</h2>



<p><a href="https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/migration.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.transport@2.5/manual/migration.html</a></p>



<p></p>
<p>The post <a href="https://lycos7560.com/unity/unity-transport-2-5-1/39976/">Unity Transport 2.5.1 Docs</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/unity/unity-transport-2-5-1/39976/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>IInputComponentData [Netcode for Entities]</title>
		<link>https://lycos7560.com/unity/iinputcomponentdata-netcode-for-entities/39970/</link>
					<comments>https://lycos7560.com/unity/iinputcomponentdata-netcode-for-entities/39970/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Sun, 27 Apr 2025 06:33:37 +0000</pubDate>
				<category><![CDATA[Unity]]></category>
		<category><![CDATA[client]]></category>
		<category><![CDATA[Client / Server worlds]]></category>
		<category><![CDATA[compress]]></category>
		<category><![CDATA[connect]]></category>
		<category><![CDATA[Data]]></category>
		<category><![CDATA[dtls]]></category>
		<category><![CDATA[ECS]]></category>
		<category><![CDATA[Entities]]></category>
		<category><![CDATA[Entity]]></category>
		<category><![CDATA[IComponentData]]></category>
		<category><![CDATA[IInputComponentData]]></category>
		<category><![CDATA[IP]]></category>
		<category><![CDATA[multiplayer]]></category>
		<category><![CDATA[Netcode]]></category>
		<category><![CDATA[network]]></category>
		<category><![CDATA[NFE]]></category>
		<category><![CDATA[online]]></category>
		<category><![CDATA[Quantization]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[study]]></category>
		<category><![CDATA[TCP]]></category>
		<category><![CDATA[UDP]]></category>
		<category><![CDATA[WSS]]></category>
		<category><![CDATA[공부]]></category>
		<category><![CDATA[기초]]></category>
		<category><![CDATA[양자]]></category>
		<category><![CDATA[양자화]]></category>
		<category><![CDATA[유니티]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=39970</guid>

					<description><![CDATA[<p>🔍 IInputComponentData https://docs.unity3d.com/Packages/com.unity.netcode@1.5/api/Unity.NetCode.IInputComponentData.html Netcode for Entities (NFE)에서 클라이언트의 입력을 서버로 전송하기 위해 특별히 설계된 인터페이스 IInputComponentData의 핵심 역할 1️⃣ 입력 데이터의 네트워크 동기화 2️⃣ 예측(Prediction) 시스템 지원 3️⃣ 입력 버퍼링 ✍🏻예시 코드 ❓[GhostField(Quantization = 100)] 양자화를 사용하는 이유 Netcode for Entities (NFE)에서&#160;네트워크 대역폭을 최적화하기 위해 사용되는 핵심 기능 1️⃣ 데이터 압축으로 대역폭 절감 2️⃣ 네트워크 [&#8230;]</p>
<p>The post <a href="https://lycos7560.com/unity/iinputcomponentdata-netcode-for-entities/39970/">IInputComponentData [Netcode for Entities]</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-ab9c0ba8      "
					data-scroll= "1"
					data-offset= "30"
					style=""
				>
				<div class="uagb-toc__wrap">
						<div class="uagb-toc__title">
							목차						</div>
																						<div class="uagb-toc__list-wrap ">
						<ol class="uagb-toc__list"><li class="uagb-toc__list"><a href="#iinputcomponentdata" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f50d.png" alt="🔍" class="wp-smiley" style="height: 1em; max-height: 1em;" /> IInputComponentData</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#iinputcomponentdata의-핵심-역할" class="uagb-toc-link__trigger">IInputComponentData의 핵심 역할</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-입력-데이터의-네트워크-동기화" class="uagb-toc-link__trigger">1&#x20e3; 입력 데이터의 네트워크 동기화</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#2-예측prediction-시스템-지원" class="uagb-toc-link__trigger">2&#x20e3; 예측(Prediction) 시스템 지원</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#3-입력-버퍼링" class="uagb-toc-link__trigger">3&#x20e3; 입력 버퍼링</a></li></ul><li class="uagb-toc__list"><a href="#예시-코드" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270d-1f3fb.png" alt="✍🏻" class="wp-smiley" style="height: 1em; max-height: 1em;" />예시 코드</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#ghostfieldquantization-100-양자화를-사용하는-이유" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2753.png" alt="❓" class="wp-smiley" style="height: 1em; max-height: 1em;" />[GhostField(Quantization = 100)] 양자화를 사용하는 이유</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-데이터-압축으로-대역폭-절감" class="uagb-toc-link__trigger">1&#x20e3; 데이터 압축으로 대역폭 절감</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#2-네트워크-지연-감소" class="uagb-toc-link__trigger">2&#x20e3; 네트워크 지연 감소</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#3-작동-원리" class="uagb-toc-link__trigger">3&#x20e3; 작동 원리</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#4-간단-적용-예시" class="uagb-toc-link__trigger">4&#x20e3; 간단 적용 예시</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#5-최적화-가이드" class="uagb-toc-link__trigger">5&#x20e3; 최적화 가이드</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#6-주의사항" class="uagb-toc-link__trigger">6&#x20e3; 주의사항</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#7-성능비교" class="uagb-toc-link__trigger">7&#x20e3; 성능비교</a></li></ul></li></ul><li class="uagb-toc__list"><a href="#iinputcomponentdata-와-icomponentdata의-차이점" class="uagb-toc-link__trigger">IInputComponentData 와 IComponentData의 차이점</a></ul></ol>					</div>
									</div>
				</div>
			


<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f50d.png" alt="🔍" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <code>IInputComponentData</code></h2>



<p><a href="https://docs.unity3d.com/Packages/com.unity.netcode@1.5/api/Unity.NetCode.IInputComponentData.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/Packages/com.unity.netcode@1.5/api/Unity.NetCode.IInputComponentData.html</a></p>



<p><strong>Netcode for Entities (NFE)</strong>에서 클라이언트의 입력을 서버로 전송하기 위해 특별히 설계된 인터페이스</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><strong><code>IInputComponentData</code>의 핵심 역할</strong></h3>



<h4 class="wp-block-heading"><strong>1&#x20e3; 입력 데이터의 네트워크 동기화</strong></h4>



<ul class="wp-block-list">
<li><strong>클라이언트 → 서버</strong>로의 입력 전송을 최적화합니다.</li>



<li>NFE는 이 인터페이스가 붙은 컴포넌트를 자동으로 직렬화/역직렬화합니다.</li>
</ul>



<h4 class="wp-block-heading"><strong>2&#x20e3; 예측(Prediction) 시스템 지원</strong></h4>



<ul class="wp-block-list">
<li><strong>클라이언트 측 예측</strong>과&nbsp;<strong>서버 측 보정</strong>을 가능하게 합니다.</li>



<li><code>GhostPredictionSystemGroup</code>에서 특별 처리됩니다.</li>
</ul>



<h4 class="wp-block-heading"><strong>3&#x20e3; 입력 버퍼링</strong></h4>



<ul class="wp-block-list">
<li>틱(tick) 기반으로 입력을 저장해&nbsp;<strong>네트워크 지연 보정</strong>에 사용됩니다.</li>
</ul>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270d-1f3fb.png" alt="✍🏻" class="wp-smiley" style="height: 1em; max-height: 1em;" /><strong>예시 코드</strong></h3>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using Unity.Entities;
using Unity.NetCode;

// 반드시 IInputComponentData를 상속해야 함
public struct NetcodePlayerInput : IInputComponentData
{
    // 필드에 [GhostField] 속성을 추가해 직렬화 옵션 지정
    [GhostField(Quantization = 100)] // 값 범위: -1.0 ~ 1.0 → -100 ~ 100으로 압축
    public float MoveX; // 좌우 이동 입력 (-1: 왼쪽, 1: 오른쪽)

    [GhostField]
    public float MoveY; // 전후 이동 입력

    [GhostField]
    public InputEvent Jump; // 점프 입력 (버튼 상태)

    // 현재 틱 정보 (NFE가 자동으로 주입)
    public uint Tick { get; set; }
}</pre>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2753.png" alt="❓" class="wp-smiley" style="height: 1em; max-height: 1em;" />[GhostField(Quantization = 100)] 양자화를 사용하는 이유</h4>



<p>Netcode for Entities (NFE)에서&nbsp;<strong>네트워크 대역폭을 최적화</strong>하기 위해 사용되는 핵심 기능</p>



<h5 class="wp-block-heading"><strong><strong>1&#x20e3;</strong> 데이터 압축으로 대역폭 절감</strong></h5>



<ul class="wp-block-list">
<li><strong>원본 데이터</strong>:&nbsp;<code>float</code>&nbsp;(32비트)</li>



<li><strong>양자화 후</strong>:&nbsp;<code>short</code>&nbsp;(16비트) 등 작은 타입으로 변환</li>
</ul>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">[GhostField(Quantization = 100)] 
public float MoveX; // -1.0 ~ 1.0 → -100 ~ 100 정수로 압축
// 1.75f → 175 (전송) : 수신 측에서 1.75f로 복원</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><strong><strong>2&#x20e3;</strong> 네트워크 지연 감소</strong></h5>



<p>작은 데이터 패킷으로 통신하여&nbsp;<strong>전송 시간 단축</strong>하여 <strong>실시간 반응성 향상</strong> (지연 시간 감소)</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><strong><strong>3&#x20e3;</strong> <strong><strong>작동 원리</strong></strong></strong></h5>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>원본 값</th><th>양자화 계수</th><th>송신 값</th><th>복원 값</th><th>오차</th></tr></thead><tbody><tr><td>0.73f</td><td>100</td><td>73</td><td>0.73f</td><td>0%</td></tr><tr><td>1.28f</td><td>100</td><td>128</td><td>1.28f</td><td>0%</td></tr><tr><td>0.123f</td><td>100</td><td>12</td><td>0.12f</td><td>2.4%</td></tr></tbody></table></figure>



<ul class="wp-block-list">
<li><strong>적정 범위</strong>:&nbsp;<code>-1.0 ~ 1.0</code>&nbsp;(조이스틱 입력 등)
<ul class="wp-block-list">
<li><code>Quantization = 100</code>&nbsp;→&nbsp;<code>-100 ~ +100</code>&nbsp;(총 201단계)</li>



<li><strong>필요 비트</strong>:&nbsp;<code>⌈log₂(201)⌉ = 8비트</code>&nbsp;(1바이트)</li>
</ul>
</li>



<li><strong>정밀도 vs 효율 트레이드오프</strong>:
<ul class="wp-block-list">
<li><strong>100</strong>: 0.01 단위 정밀도 (대부분의 게임 입력에 충분)</li>



<li><strong>1000</strong>: 0.001 단위 (고정밀 필요 시) → 대역폭 2배 소모</li>
</ul>
</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><strong>4&#x20e3; <strong><strong>간단 적용 예시</strong></strong></strong></h5>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// 캐릭터 이동
[GhostField(Quantization = 100)]
public float Horizontal; // 좌우 이동 (-1.0 ~ 1.0)

[GhostField(Quantization = 100)]
public float Vertical;   // 전후 이동

// 캐릭터 회전
[GhostField(Quantization = 32767)] // short.MaxValue
public float RotationY; // 0 ~ 360도 → -32767 ~ 32767
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><strong> </strong>5&#x20e3; 최적화 가이드</h5>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th><strong>값 범위</strong></th><th><strong>권장 양자화 계수</strong></th><th><strong>비트 사용량</strong></th></tr></thead><tbody><tr><td>-1.0 ~ 1.0</td><td>100</td><td>8비트</td></tr><tr><td>-10.0 ~ 10.0</td><td>10</td><td>8비트</td></tr><tr><td>0 ~ 360 (각도)</td><td>32767</td><td>16비트</td></tr><tr><td>고정밀 물리 파라미터</td><td>10000+</td><td>16~32비트</td></tr></tbody></table></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><strong>6&#x20e3; 주의사항</strong></h5>



<ul class="wp-block-list">
<li><strong>오버플로우 방지</strong><br><code>Quantization</code>&nbsp;값을 너무 크게 설정하면 정수 변환 시 오버플로우 발생 가능:</li>
</ul>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// 위험 예시 (float.MaxValue → 양자화 시 오류)
[GhostField(Quantization = 1000000)] 
public float DangerValue;</pre>



<ul class="wp-block-list">
<li><strong><strong>정밀도 한계</strong></strong><br><code>0.005f</code>&nbsp;같은 미세한 값은&nbsp;<code>Quantization=100</code>에서&nbsp;<strong>반올림 오차</strong>&nbsp;발생:</li>
</ul>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">0.005f * 100 = 0.5f → 반올림 → 1 → 복원 시 0.01f (100% 오차)</pre>



<ul class="wp-block-list">
<li><strong><strong>에디터 디버깅</strong></strong><br><code>NetworkProtocol</code>&nbsp;로그에서 실제 전송 크기 확인:</li>
</ul>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// Unity 콘솔에 패킷 크기 출력
Debug.Log($"패킷 크기: {System.Runtime.InteropServices.Marshal.SizeOf(packet)}바이트");</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><strong>7&#x20e3; </strong>성능비교</h5>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// 양자화 미적용 (32비트 float)
[GhostField] 
public float Uncompressed; // 4바이트

// 양자화 적용 (8비트 압축)
[GhostField(Quantization = 100)] 
public float Compressed; // 1바이트

절감 효과: 75% 대역폭 감소 (4배 효율)
초당 60프레임 기준:
미적용: 60fps * 4B = 240B/s
적용: 60fps * 1B = 60B/s</pre>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><strong><code>IInputComponentData</code></strong> 와 <code>IComponentData</code>의 차이점</h3>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>특징</th><th><code>IInputComponentData</code></th><th><code>IComponentData</code></th></tr></thead><tbody><tr><td><strong>자동 직렬화</strong></td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b55.png" alt="⭕" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 네트워크 전송 최적화</td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 직접 구현 필요</td></tr><tr><td><strong>예측 지원</strong></td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b55.png" alt="⭕" class="wp-smiley" style="height: 1em; max-height: 1em;" />&nbsp;<code>PredictedGhost</code>와 연동</td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 별도 시스템 필요</td></tr><tr><td><strong>틱 동기화</strong></td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b55.png" alt="⭕" class="wp-smiley" style="height: 1em; max-height: 1em;" />&nbsp;<code>Tick</code>&nbsp;프로퍼티 자동 관리</td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 수동 처리</td></tr><tr><td><strong>버퍼링</strong></td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b55.png" alt="⭕" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 입력 히스토리 유지</td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 직접 구현</td></tr></tbody></table></figure>



<p></p>
<p>The post <a href="https://lycos7560.com/unity/iinputcomponentdata-netcode-for-entities/39970/">IInputComponentData [Netcode for Entities]</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/unity/iinputcomponentdata-netcode-for-entities/39970/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Unity Serialization (직렬화)</title>
		<link>https://lycos7560.com/unity/unity-serialization-%ec%a7%81%eb%a0%ac%ed%99%94/39882/</link>
					<comments>https://lycos7560.com/unity/unity-serialization-%ec%a7%81%eb%a0%ac%ed%99%94/39882/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Tue, 25 Feb 2025 09:24:30 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Unity]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Byte Stream]]></category>
		<category><![CDATA[Configuration Files]]></category>
		<category><![CDATA[Data Format]]></category>
		<category><![CDATA[Data Storage]]></category>
		<category><![CDATA[Data Structure]]></category>
		<category><![CDATA[data transfer]]></category>
		<category><![CDATA[Developer Tools]]></category>
		<category><![CDATA[Dictionary]]></category>
		<category><![CDATA[file saving]]></category>
		<category><![CDATA[Game Data]]></category>
		<category><![CDATA[Game Development]]></category>
		<category><![CDATA[Game State Saving]]></category>
		<category><![CDATA[Inspector]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[JsonUtility]]></category>
		<category><![CDATA[List]]></category>
		<category><![CDATA[Load System]]></category>
		<category><![CDATA[Memory Management]]></category>
		<category><![CDATA[Newtonsoft.Json]]></category>
		<category><![CDATA[Object Conversion]]></category>
		<category><![CDATA[parsing]]></category>
		<category><![CDATA[PlayerPrefs]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Readability]]></category>
		<category><![CDATA[Runtime]]></category>
		<category><![CDATA[Save System]]></category>
		<category><![CDATA[Scene Management]]></category>
		<category><![CDATA[ScriptableObject]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[Serialization]]></category>
		<category><![CDATA[Serialization Rules]]></category>
		<category><![CDATA[SerializeField]]></category>
		<category><![CDATA[study]]></category>
		<category><![CDATA[System.Serializable]]></category>
		<category><![CDATA[Unity Editor]]></category>
		<category><![CDATA[Variable Types]]></category>
		<category><![CDATA[WebSockets]]></category>
		<category><![CDATA[XML]]></category>
		<category><![CDATA[YAML]]></category>
		<category><![CDATA[가독성]]></category>
		<category><![CDATA[개발자도구]]></category>
		<category><![CDATA[객체변환]]></category>
		<category><![CDATA[게임개발]]></category>
		<category><![CDATA[게임데이터]]></category>
		<category><![CDATA[게임상태저장]]></category>
		<category><![CDATA[공부]]></category>
		<category><![CDATA[데이터구조]]></category>
		<category><![CDATA[데이터저장]]></category>
		<category><![CDATA[데이터전송]]></category>
		<category><![CDATA[데이터포맷]]></category>
		<category><![CDATA[런타임]]></category>
		<category><![CDATA[로드시스템]]></category>
		<category><![CDATA[메모리관리]]></category>
		<category><![CDATA[바이트스트림]]></category>
		<category><![CDATA[변수타입]]></category>
		<category><![CDATA[설정파일]]></category>
		<category><![CDATA[스크립팅]]></category>
		<category><![CDATA[씬관리]]></category>
		<category><![CDATA[웹소켓]]></category>
		<category><![CDATA[유니티에디터]]></category>
		<category><![CDATA[직렬화]]></category>
		<category><![CDATA[직렬화규칙]]></category>
		<category><![CDATA[파싱]]></category>
		<category><![CDATA[파일저장]]></category>
		<category><![CDATA[프로그래밍]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=39882</guid>

					<description><![CDATA[<p>🔥 Serialization (직렬화) 개요 Serialization이란 객체 데이터를 바이트 스트림으로 변환하여 저장하거나 전송할 수 있도록 하는 과정 주 목적은 필요할 때 다시 개체로 만들 수 있도록 개체의 상태를 저장하는 것 반대로 Deserialization은 저장된 바이트 데이터를 다시 객체로 변환하는 과정입니다. 🔥 JSON, XML, YAML 일반적으로 많이 사용하는 데이터 직렬화 포맷들 1️⃣ JSON (JavaScript Object Notation) ✔️ 특징 [&#8230;]</p>
<p>The post <a href="https://lycos7560.com/unity/unity-serialization-%ec%a7%81%eb%a0%ac%ed%99%94/39882/">Unity Serialization (직렬화)</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-571189ff      "
					data-scroll= "1"
					data-offset= "30"
					style=""
				>
				<div class="uagb-toc__wrap">
						<div class="uagb-toc__title">
							목차						</div>
																						<div class="uagb-toc__list-wrap ">
						<ol class="uagb-toc__list"><li class="uagb-toc__list"><a href="#serialization-직렬화-개요" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Serialization (직렬화) 개요</a><li class="uagb-toc__list"><a href="#json-xml-yaml" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> JSON, XML, YAML</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-json-javascript-object-notation" class="uagb-toc-link__trigger">1&#x20e3; JSON (JavaScript Object Notation)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#2-xml-extensible-markup-language" class="uagb-toc-link__trigger">2&#x20e3; XML (eXtensible Markup Language)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#3-yaml-yaml-aint-markup-language" class="uagb-toc-link__trigger">3&#x20e3; YAML (YAML Ain&#039;t Markup Language)</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#비교-정리" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f50e.png" alt="🔎" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 비교 정리</a></li></ul></li><li class="uagb-toc__list"><a href="#unity에서의-스크립트-직렬화-serialization-in-unity" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" />Unity에서의 스크립트 직렬화 (Serialization in Unity)</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#1-unity에서-직렬화가-중요한-이유" class="uagb-toc-link__trigger">1&#x20e3; Unity에서 직렬화가 중요한 이유</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#2-unity에서-직렬화-가능한-타입" class="uagb-toc-link__trigger">2&#x20e3; Unity에서 직렬화 가능한 타입</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#3-unity-직렬화-적용-방법" class="uagb-toc-link__trigger">3&#x20e3; Unity 직렬화 적용 방법</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#4-unity-직렬화와-json-활용" class="uagb-toc-link__trigger">4&#x20e3; Unity 직렬화와 JSON 활용</a></ul></ul></ol>					</div>
									</div>
				</div>
			


<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><strong><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Serialization (직렬화) 개요</strong></h2>



<p><strong>Serialization</strong>이란<strong> 객체 데이터</strong>를 <strong>바이트 스트림</strong>으로 변환하여 <strong>저장</strong>하거나 <strong>전송</strong>할 수 있도록 하는 과정</p>



<p>주 목적은 필요할 때 다시 개체로 만들 수 있도록 개체의 상태를 저장하는 것</p>



<p>반대로 <strong>Deserialization</strong>은 저장된 바이트 데이터를 다시 객체로 변환하는 과정입니다.</p>



<figure class="wp-block-image size-full"><img decoding="async" width="262" height="199" src="https://lycos7560.com/wp-content/uploads/2025/02/image-179.png" alt="" class="wp-image-39884"/><figcaption class="wp-element-caption"><a href="https://learn.microsoft.com/ko-kr/dotnet/visual-basic/programming-guide/concepts/serialization/" target="_blank" rel="noreferrer noopener">https://learn.microsoft.com/ko-kr/dotnet/visual-basic/programming-guide/concepts/serialization/</a></figcaption></figure>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h2 class="wp-block-heading"><strong><strong><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /></strong></strong> JSON, XML, YAML</h2>



<p>일반적으로 많이 사용하는 데이터 직렬화 포맷들</p>



<hr class="wp-block-separator has-alpha-channel-opacity" style="margin-top:var(--wp--preset--spacing--30);margin-bottom:var(--wp--preset--spacing--30)"/>



<h3 class="wp-block-heading">1&#x20e3; JSON (JavaScript Object Notation)</h3>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 특징</h4>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 가벼운 텍스트 기반 포맷<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 사람이 읽고 쓰기 쉬우며, 기계가 빠르게 처리 가능<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 대부분의 프로그래밍 언어에서 지원 (C#, Python, JavaScript 등)<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 키-값 쌍의 구조 (Dictionary, Object와 유사)</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 예제</h4>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{
  "name": "John",
  "age": 30,
  "skills": ["C#", "Unity", "Python"],
  "isDeveloper": true
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 장점</h4>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 가볍고 속도가 빠름<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 대부분의 언어에서 지원<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> API 및 데이터 전송에 적합 (REST API, WebSockets 등)</p>



<h4 class="wp-block-heading"><strong><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 단점</strong></h4>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 주석 지원이 안됨<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> XML이나 YAML보다 덜 유연함</p>



<hr class="wp-block-separator has-alpha-channel-opacity" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)"/>



<h3 class="wp-block-heading">2&#x20e3; XML (eXtensible Markup Language)</h3>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 특징</h4>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 데이터 구조를 계층적으로 표현 (HTML과 유사)<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 사람이 읽을 수 있지만, JSON보다 길이가 김<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 다양한 도메인에서 사용 (문서 저장, 설정 파일, 웹 서비스 등)<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> &lt;태그&gt;를 이용한 구조화된 데이터 표현</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 예제</h4>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;Person>
    &lt;Name>John&lt;/Name>
    &lt;Age>30&lt;/Age>
    &lt;Skills>
        &lt;Skill>C#&lt;/Skill>
        &lt;Skill>Unity&lt;/Skill>
        &lt;Skill>Python&lt;/Skill>
    &lt;/Skills>
    &lt;IsDeveloper>true&lt;/IsDeveloper>
&lt;/Person>
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 장점</h4>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 데이터 구조가 명확함<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 주석 사용 가능 (&lt;!&#8211; 주석 &#8211;&gt;)<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 다양한 데이터 타입을 표현하기 적합</p>



<h4 class="wp-block-heading"><strong><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 단점</strong></h4>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> JSON보다 크기가 크고, 가독성이 떨어짐<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 파싱 속도가 느림</p>



<hr class="wp-block-separator has-alpha-channel-opacity" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)"/>



<h3 class="wp-block-heading">3&#x20e3; YAML (YAML Ain&#8217;t Markup Language)</h3>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 특징</h4>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> JSON과 유사하지만 더 간결한 문법을 가짐<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 들여쓰기를 이용한 계층 구조 (Python과 유사)<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 설정 파일에서 많이 사용 (Docker, Kubernetes, Unity Config 등)</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 예제</h4>



<pre class="EnlighterJSRAW" data-enlighter-language="yaml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">name: John
age: 30
skills:
  - C#
  - Unity
  - Python
isDeveloper: true
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 장점</h4>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 사람이 읽기 쉬운 직관적인 문법<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> JSON보다 간결하여 가독성이 좋음<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 주석 (#) 사용 가능</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><strong><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 단점</strong></h4>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 들여쓰기 실수로 인한 오류 발생 가능<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 파싱 속도가 JSON보다 느림</p>



<figure class="wp-block-image size-full"><img decoding="async" width="727" height="481" src="https://lycos7560.com/wp-content/uploads/2025/02/image-180.jpg" alt="" class="wp-image-39885" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-180.jpg 727w, https://lycos7560.com/wp-content/uploads/2025/02/image-180-300x198.jpg 300w" sizes="(max-width: 727px) 100vw, 727px" /><figcaption class="wp-element-caption">Unity의 YAML<br><a href="https://unity.com/kr/blog/engine-platform/understanding-unitys-serialization-language-yaml" target="_blank" rel="noreferrer noopener">https://unity.com/kr/blog/engine-platform/understanding-unitys-serialization-language-yaml</a></figcaption></figure>



<hr class="wp-block-separator has-alpha-channel-opacity" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)"/>



<h3 class="wp-block-heading"><strong><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f50e.png" alt="🔎" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 비교 정리</strong></h3>



<p>Unity에서는 JSON (JsonUtility, Newtonsoft.Json)이 가장 많이 사용되며, YAML은 Unity의 설정 파일 (.yml)에서 많이 활용됩니다.</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>형식</th><th>문법</th><th>가독성</th><th>속도</th><th>사용 사례</th></tr></thead><tbody><tr><td><strong>JSON</strong></td><td><code>{ "key": "value" }</code></td><td>좋음</td><td>빠름 <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td>API, 데이터 저장</td></tr><tr><td><strong>XML</strong></td><td><code>&lt;tag&gt;value&lt;/tag&gt;</code></td><td>중간</td><td>느림 <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td>문서 저장, 설정 파일</td></tr><tr><td><strong>YAML</strong></td><td><code>key: value</code> (들여쓰기)</td><td>매우 좋음 <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td><td>중간</td><td>설정 파일, DevOps</td></tr></tbody></table></figure>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="1620" height="714" src="https://lycos7560.com/wp-content/uploads/2025/02/image-180.png" alt="" class="wp-image-39886" style="width:771px;height:auto" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-180.png 1620w, https://lycos7560.com/wp-content/uploads/2025/02/image-180-300x132.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-180-768x338.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-180-1536x677.png 1536w" sizes="(max-width: 1620px) 100vw, 1620px" /></figure>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h2 class="wp-block-heading"><strong><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" />Unity에서의 스크립트 직렬화 (Serialization in Unity)</strong></h2>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-default" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"/>



<h3 class="wp-block-heading">1&#x20e3; <strong>Unity에서 직렬화가 중요한 이유</strong></h3>



<p>Unity는 <strong>Inspector 창에서 데이터를 유지</strong>하거나 <strong>저장 시스템(예: PlayerPrefs, JSON, Binary 파일 등)에 데이터를 저장</strong>하기 위해 직렬화를 활용합니다.</p>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>씬(Scene) 저장 및 로드</strong>: Inspector에 입력한 값이 유지됨<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>ScriptableObject:</strong> 게임 데이터 관리<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Save/Load 시스템</strong>: JSON 또는 Binary 직렬화를 활용하여 파일 저장</p>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-default" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"/>



<h3 class="wp-block-heading">2&#x20e3; <strong>Unity에서 직렬화 가능한 타입</strong></h3>



<p><a href="https://docs.unity3d.com/6000.0/Documentation/Manual/script-serialization-rules.html" target="_blank" rel="noreferrer noopener">https://docs.unity3d.com/6000.0/Documentation/Manual/script-serialization-rules.html</a></p>



<p>Unity는 <strong>특정 데이터 타입만 직렬화할 수 있도록 제한</strong>하고 있습니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b55.png" alt="⭕" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 직렬화 가능한 타입 (Serializable)</h4>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>기본 데이터 타입</strong>: <code>int</code>, <code>float</code>, <code>bool</code>, <code>string</code> 등<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Unity 기본 타입</strong>: <strong>배열 &amp; 리스트</strong>: <code>int[]</code>, <code>List&lt;float&gt;</code> 등 (단, <code>public</code> 또는 <code>[SerializeField]</code> 필요)<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>사용자 정의 클래스</strong> (<code>[System.Serializable]</code> 필요)<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>ScriptableObject</strong></p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><strong><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /></strong> 직렬화 불가능한 타입 (Non-Serializable)</h4>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>딕셔너리(Dictionary)</strong><br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>다차원 배열 (<code>int[,]</code>)</strong><br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong><strong>속성(Property) (getter/setter)</strong></strong><br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong><strong>Static 변수 (<code>static</code>)</strong></strong><br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong><strong>추상 클래스 &amp; 인터페이스</strong></strong><br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong><strong>델리게이트(Delegate), 이벤트(Event)</strong></strong></p>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-default" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"/>



<h3 class="wp-block-heading">3&#x20e3; <strong>Unity 직렬화 적용 방법</strong></h3>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> [SerializeField]</h4>



<p><code>private</code> 변수도 Inspector에서 보이도록 만들고, 직렬화 가능하게 합니다.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using UnityEngine;

public class Player : MonoBehaviour
{
    [SerializeField] private int health = 100;  // 직렬화됨 (Inspector에서 수정 가능)
    private int score = 0;  // 직렬화되지 않음 (Inspector에서 보이지 않음)
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> [SerializeField]를 사용하면 <code>private</code> 변수도 직렬화됨<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 하지만 <code>static</code>, <code>const</code>, <code>readonly</code> 변수는 직렬화되지 않음</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> [System.Serializable]</h4>



<p>사용자 정의 클래스를 직렬화하려면 <code>[System.Serializable]</code>을 붙여야 합니다.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using UnityEngine;

[System.Serializable]  
public class Weapon
{
    public string name;
    public int damage;
}

public class Player : MonoBehaviour
{
    public Weapon myWeapon;  // Weapon 클래스가 직렬화되므로 Inspector에서 수정 가능
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 클래스를 <code>System.Serializable</code>로 만들면 Unity Inspector에서 확인 가능<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 하지만 <code>Dictionary</code>, <code>Properties</code>, <code>Static 변수</code> 등은 여전히 직렬화되지 않음</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> ScriptableObject</h4>



<p>게임 데이터를 저장 및 관리하는 특수한 직렬화 객체</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using UnityEngine;

[CreateAssetMenu(fileName = "New Weapon", menuName = "Weapon")]
public class WeaponData : ScriptableObject
{
    public string weaponName;
    public int damage;
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 씬(Scene)과 독립적으로 데이터 관리 가능<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 메모리 효율적 관리 가능 (오브젝트 풀링, 설정 저장 등)<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 런타임에서 수정된 값은 저장되지 않음 (Play 모드가 끝나면 초기화됨)</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-default" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"/>



<h3 class="wp-block-heading">4&#x20e3; <strong>Unity 직렬화와 JSON 활용</strong></h3>



<p>Unity에서 JSON 직렬화를 활용하면 <strong>데이터 저장 &amp; 로드</strong>가 가능해집니다.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> JsonUtility (빠르지만 제한적)</h4>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using UnityEngine;

[System.Serializable]
public class PlayerData
{
    public string name;
    public int level;
}

public class SaveLoadSystem : MonoBehaviour
{
    void Start()
    {
        PlayerData player = new PlayerData { name = "John", level = 10 };
        string json = JsonUtility.ToJson(player);
        Debug.Log(json);  // {"name":"John","level":10}

        PlayerData loadedPlayer = JsonUtility.FromJson&lt;PlayerData>(json);
        Debug.Log(loadedPlayer.name);  // John
    }
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 빠름 &amp; Unity 기본 지원<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Dictionary, List&lt;T&gt; 같은 복잡한 자료형 지원 X</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Newtonsoft.Json (더 강력한 JSON 직렬화)</h4>



<p><code>Newtonsoft.Json</code> 라이브러리를 사용하면 <strong>Dictionary, List, Interface 등도 직렬화 가능</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using UnityEngine;
using Newtonsoft.Json;
using System.Collections.Generic;

public class PlayerData
{
    public string name;
    public int level;
    public Dictionary&lt;string, int> inventory = new Dictionary&lt;string, int>();
}

public class SaveLoadSystem : MonoBehaviour
{
    void Start()
    {
        PlayerData player = new PlayerData { name = "John", level = 10 };
        player.inventory.Add("Sword", 1);
        player.inventory.Add("Potion", 5);

        string json = JsonConvert.SerializeObject(player, Formatting.Indented);
        Debug.Log(json);

        PlayerData loadedPlayer = JsonConvert.DeserializeObject&lt;PlayerData>(json);
        Debug.Log(loadedPlayer.inventory["Sword"]);  // 1
    }
}
</pre>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Dictionary, List&lt;T&gt; 등 복잡한 자료형 지원<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> JsonUtility보다 속도가 느림<br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 추가 라이브러리 설치 필요 (<code>Newtonsoft.Json.dll</code>)</p>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="[유니티 TIPS] 데이터 시리얼라이제이션 완전 정복하기" width="1778" height="1000" src="https://www.youtube.com/embed/kEu_AQ_Es-8?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div><figcaption class="wp-element-caption">공부 참고 영상</figcaption></figure>



<p></p>
<p>The post <a href="https://lycos7560.com/unity/unity-serialization-%ec%a7%81%eb%a0%ac%ed%99%94/39882/">Unity Serialization (직렬화)</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/unity/unity-serialization-%ec%a7%81%eb%a0%ac%ed%99%94/39882/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>URP VFX Learning Templates (2)</title>
		<link>https://lycos7560.com/unity/urp-vfx-learning-templates-2/39699/</link>
					<comments>https://lycos7560.com/unity/urp-vfx-learning-templates-2/39699/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Sun, 23 Feb 2025 00:40:02 +0000</pubDate>
				<category><![CDATA[Unity]]></category>
		<category><![CDATA[Alpha Blending]]></category>
		<category><![CDATA[Compute Shader]]></category>
		<category><![CDATA[Flipbook Animation]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Motion Vectors]]></category>
		<category><![CDATA[Noise Texture]]></category>
		<category><![CDATA[Particle System]]></category>
		<category><![CDATA[Real-time FX]]></category>
		<category><![CDATA[Rendering Tricks]]></category>
		<category><![CDATA[Templates]]></category>
		<category><![CDATA[TUTORIAL]]></category>
		<category><![CDATA[Unity Docs]]></category>
		<category><![CDATA[Unity Shader]]></category>
		<category><![CDATA[Unity VFX Graph]]></category>
		<category><![CDATA[URP]]></category>
		<category><![CDATA[URP (Universal Render Pipeline)]]></category>
		<category><![CDATA[VFX]]></category>
		<category><![CDATA[VFX (Visual Effects)]]></category>
		<category><![CDATA[VFX Techniques]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=39699</guid>

					<description><![CDATA[<p>URP_VFX_Learning_Templates (2) 11. TexIndex Attribute VFX 아티스트들은 스프라이트 시트(Sprite Sheet) 를 자주 사용합니다. 이 VFX 예제는 출력(Output) 에서 UV 옵션 을 사용하여 스프라이트 시트 를 활용하는 방법을 보여줍니다. 또한 Flipbook 설정 을 구성하는 방법과 texIndex 속성 과의 관계를 설명합니다. Covered Aspects: 12. Flipbook Mode 이 VFX는 Output(출력)의 UV 모드를 Flipbook으로 설정하여 스프라이트 시트를 사용하는 방법을 [&#8230;]</p>
<p>The post <a href="https://lycos7560.com/unity/urp-vfx-learning-templates-2/39699/">URP VFX Learning Templates (2)</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-embed is-type-wp-embed"><div class="wp-block-embed__wrapper">
<blockquote class="wp-embedded-content" data-secret="f27cY38Nml"><a href="https://lycos7560.com/unity/urp-vfx-learning-templates-1/39596/">URP VFX Learning Templates (1)</a></blockquote><iframe loading="lazy" class="wp-embedded-content" sandbox="allow-scripts" security="restricted"  title="&#8220;URP VFX Learning Templates (1)&#8221; &#8212; 어제와 내일의 나 그 사이의 이야기" src="https://lycos7560.com/unity/urp-vfx-learning-templates-1/39596/embed/#?secret=j2C2b3DaWr#?secret=f27cY38Nml" data-secret="f27cY38Nml" width="600" height="338" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
</div></figure>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>


				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-303fb734      "
					data-scroll= "1"
					data-offset= "30"
					style=""
				>
				<div class="uagb-toc__wrap">
						<div class="uagb-toc__title">
							목차						</div>
																						<div class="uagb-toc__list-wrap ">
						<ol class="uagb-toc__list"><li class="uagb-toc__list"><a href="#urp-vfx-learning-templates-2" class="uagb-toc-link__trigger">URP_VFX_Learning_Templates (2)</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#11-texindex-attribute" class="uagb-toc-link__trigger">11. TexIndex Attribute</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#12-flipbook-mode" class="uagb-toc-link__trigger">12. Flipbook Mode</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#13-flipbook-blending" class="uagb-toc-link__trigger">13. Flipbook Blending</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#14-texindex-advanced" class="uagb-toc-link__trigger">14. TexIndex Advanced</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#15-pivot-attribute" class="uagb-toc-link__trigger">15. Pivot Attribute</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#16-pivot-advanced" class="uagb-toc-link__trigger">16. Pivot Advanced</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#17-sample-mesh" class="uagb-toc-link__trigger">17. Sample Mesh</a></ul></ol>					</div>
									</div>
				</div>
			


<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Unity 6 - 6000.0.32f1
Visual Effect Graph - 17.0.3</pre>



<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>



<h1 class="wp-block-heading">URP_VFX_Learning_Templates (2)</h1>



<h2 class="wp-block-heading">11. TexIndex Attribute</h2>



<p>VFX 아티스트들은 <strong>스프라이트 시트(Sprite Sheet)</strong> 를 자주 사용합니다.</p>



<p>이 VFX 예제는 <strong>출력(Output)</strong> 에서 <strong>UV 옵션</strong> 을 사용하여 <strong>스프라이트 시트</strong> 를 활용하는 방법을 보여줍니다. </p>



<p>또한 <strong>Flipbook 설정</strong> 을 구성하는 방법과 <strong>texIndex 속성</strong> 과의 관계를 설명합니다.</p>



<h3 class="wp-block-heading"><strong><strong>Covered Aspects:</strong></strong></h3>



<ul class="wp-block-list">
<li>TexIndex Attribute</li>



<li>UVs Mode</li>



<li>Flipbook</li>
</ul>



<figure class="wp-block-video"><video height="1056" style="aspect-ratio: 1704 / 1056;" width="1704" controls muted src="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_07_35_03_551.mp4"></video><figcaption class="wp-element-caption">TexIndex Attribute Video (1)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1439" height="943" src="https://lycos7560.com/wp-content/uploads/2025/02/image-78.png" alt="" class="wp-image-39713" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-78.png 1439w, https://lycos7560.com/wp-content/uploads/2025/02/image-78-300x197.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-78-768x503.png 768w" sizes="(max-width: 1439px) 100vw, 1439px" /><figcaption class="wp-element-caption">TexIndex Attribute Graph Entire</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1762" height="1789" src="https://lycos7560.com/wp-content/uploads/2025/02/image-74-1.jpg" alt="" class="wp-image-39700" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-74-1.jpg 1762w, https://lycos7560.com/wp-content/uploads/2025/02/image-74-1-295x300.jpg 295w, https://lycos7560.com/wp-content/uploads/2025/02/image-74-1-768x780.jpg 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-74-1-1513x1536.jpg 1513w" sizes="(max-width: 1762px) 100vw, 1762px" /><figcaption class="wp-element-caption">Sprite Debug Graph</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1271" height="1780" src="https://lycos7560.com/wp-content/uploads/2025/02/image-74.png" alt="" class="wp-image-39701" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-74.png 1271w, https://lycos7560.com/wp-content/uploads/2025/02/image-74-214x300.png 214w, https://lycos7560.com/wp-content/uploads/2025/02/image-74-768x1076.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-74-1097x1536.png 1097w" sizes="(max-width: 1271px) 100vw, 1271px" /><figcaption class="wp-element-caption">Leaf Fliebook Graph</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1387" height="1088" src="https://lycos7560.com/wp-content/uploads/2025/02/image-77-1.jpg" alt="" class="wp-image-39708" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-77-1.jpg 1387w, https://lycos7560.com/wp-content/uploads/2025/02/image-77-1-300x235.jpg 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-77-1-768x602.jpg 768w" sizes="(max-width: 1387px) 100vw, 1387px" /><figcaption class="wp-element-caption">SpriteSheet Debug (1)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1910" height="921" src="https://lycos7560.com/wp-content/uploads/2025/02/image-75.png" alt="" class="wp-image-39703" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-75.png 1910w, https://lycos7560.com/wp-content/uploads/2025/02/image-75-300x145.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-75-768x370.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-75-1536x741.png 1536w" sizes="(max-width: 1910px) 100vw, 1910px" /><figcaption class="wp-element-caption">SpriteSheet Debug (2)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1714" height="942" src="https://lycos7560.com/wp-content/uploads/2025/02/image-76.jpg" alt="" class="wp-image-39704" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-76.jpg 1714w, https://lycos7560.com/wp-content/uploads/2025/02/image-76-300x165.jpg 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-76-768x422.jpg 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-76-1536x844.jpg 1536w" sizes="(max-width: 1714px) 100vw, 1714px" /><figcaption class="wp-element-caption">SpriteSheet Debug (3)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1879" height="949" src="https://lycos7560.com/wp-content/uploads/2025/02/image-76.png" alt="" class="wp-image-39705" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-76.png 1879w, https://lycos7560.com/wp-content/uploads/2025/02/image-76-300x152.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-76-768x388.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-76-1536x776.png 1536w" sizes="(max-width: 1879px) 100vw, 1879px" /><figcaption class="wp-element-caption">Leaf Flipbook (1)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1697" height="1008" src="https://lycos7560.com/wp-content/uploads/2025/02/image-77.jpg" alt="" class="wp-image-39706" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-77.jpg 1697w, https://lycos7560.com/wp-content/uploads/2025/02/image-77-300x178.jpg 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-77-768x456.jpg 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-77-1536x912.jpg 1536w" sizes="(max-width: 1697px) 100vw, 1697px" /><figcaption class="wp-element-caption">Leaf Flipbook (2)</figcaption></figure>



<figure class="wp-block-video"><video height="1228" style="aspect-ratio: 2168 / 1228;" width="2168" controls muted src="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_07_58_26_612.mp4"></video><figcaption class="wp-element-caption">TexIndex Attribute Video (2)</figcaption></figure>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h2 class="wp-block-heading">12. Flipbook Mode</h2>



<p>이 VFX는 <strong>Output(출력)의 UV 모드를 Flipbook으로 설정하여 스프라이트 시트를 사용하는 방법</strong>을 보여줍니다.</p>



<p>또한 <strong>Flipbook Blend Frames 사용법과 Flipbook Player Block의 기본적인 활용 방법</strong>을 설명합니다.</p>



<p><strong>Flipbook Blend Frames</strong> 설정을 사용하면 프레임 간 보간(Interpolation)이 적용되어 <strong>부드러운 애니메이션 효과</strong>를 얻을 수 있습니다.</p>



<h3 class="wp-block-heading"><strong><strong>Covered Aspects:</strong></strong></h3>



<ul class="wp-block-list">
<li>Flipbook Player</li>



<li>UVs Mode</li>



<li>TexIndex Attribute</li>
</ul>



<figure class="wp-block-video"><video height="1224" style="aspect-ratio: 2344 / 1224;" width="2344" controls muted src="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_08_13_45_776.mp4"></video><figcaption class="wp-element-caption">Flipbook Mode Video</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1595" height="1006" src="https://lycos7560.com/wp-content/uploads/2025/02/image-79.jpg" alt="" class="wp-image-39714" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-79.jpg 1595w, https://lycos7560.com/wp-content/uploads/2025/02/image-79-300x189.jpg 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-79-768x484.jpg 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-79-1536x969.jpg 1536w" sizes="(max-width: 1595px) 100vw, 1595px" /><figcaption class="wp-element-caption">CandleMesh Entire</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="955" height="1011" src="https://lycos7560.com/wp-content/uploads/2025/02/image-77.png" alt="" class="wp-image-39712" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-77.png 955w, https://lycos7560.com/wp-content/uploads/2025/02/image-77-283x300.png 283w, https://lycos7560.com/wp-content/uploads/2025/02/image-77-768x813.png 768w" sizes="(max-width: 955px) 100vw, 955px" /><figcaption class="wp-element-caption">CandleMesh Graph</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1394" height="1019" src="https://lycos7560.com/wp-content/uploads/2025/02/image-79.png" alt="" class="wp-image-39715" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-79.png 1394w, https://lycos7560.com/wp-content/uploads/2025/02/image-79-300x219.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-79-768x561.png 768w" sizes="(max-width: 1394px) 100vw, 1394px" /><figcaption class="wp-element-caption">CandleMesh (1)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1843" height="1045" src="https://lycos7560.com/wp-content/uploads/2025/02/image-80-1.jpg" alt="" class="wp-image-39717" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-80-1.jpg 1843w, https://lycos7560.com/wp-content/uploads/2025/02/image-80-1-300x170.jpg 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-80-1-768x435.jpg 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-80-1-1536x871.jpg 1536w" sizes="(max-width: 1843px) 100vw, 1843px" /><figcaption class="wp-element-caption">CandleMesh (2)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="684" height="542" src="https://lycos7560.com/wp-content/uploads/2025/02/image-85.png" alt="" class="wp-image-39730" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-85.png 684w, https://lycos7560.com/wp-content/uploads/2025/02/image-85-300x238.png 300w" sizes="(max-width: 684px) 100vw, 684px" /></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1833" height="997" src="https://lycos7560.com/wp-content/uploads/2025/02/image-80.png" alt="" class="wp-image-39718" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-80.png 1833w, https://lycos7560.com/wp-content/uploads/2025/02/image-80-300x163.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-80-768x418.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-80-1536x835.png 1536w" sizes="(max-width: 1833px) 100vw, 1833px" /><figcaption class="wp-element-caption">SG Candle Shader Graph</figcaption></figure>



<div class="wp-block-file"><a id="wp-block-file--media-5df68b37-34df-4a04-8ebb-a6b2f97bb390" href="https://lycos7560.com/wp-content/uploads/2025/02/SG_Candle.unitypackage">SG_Candle</a><a href="https://lycos7560.com/wp-content/uploads/2025/02/SG_Candle.unitypackage" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-5df68b37-34df-4a04-8ebb-a6b2f97bb390">다운로드</a></div>



<figure class="wp-block-image size-full"><img decoding="async" width="765" height="984" src="https://lycos7560.com/wp-content/uploads/2025/02/image-81.png" alt="" class="wp-image-39720" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-81.png 765w, https://lycos7560.com/wp-content/uploads/2025/02/image-81-233x300.png 233w" sizes="(max-width: 765px) 100vw, 765px" /><figcaption class="wp-element-caption">Flipbook Flame Graph</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1847" height="998" src="https://lycos7560.com/wp-content/uploads/2025/02/image-82.jpg" alt="" class="wp-image-39721" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-82.jpg 1847w, https://lycos7560.com/wp-content/uploads/2025/02/image-82-300x162.jpg 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-82-768x415.jpg 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-82-1536x830.jpg 1536w" sizes="(max-width: 1847px) 100vw, 1847px" /><figcaption class="wp-element-caption">Flipbook Flame (1)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1885" height="1065" src="https://lycos7560.com/wp-content/uploads/2025/02/image-82.png" alt="" class="wp-image-39722" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-82.png 1885w, https://lycos7560.com/wp-content/uploads/2025/02/image-82-300x169.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-82-768x434.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-82-1536x868.png 1536w" sizes="(max-width: 1885px) 100vw, 1885px" /><figcaption class="wp-element-caption">Flipbook Flame (2)</figcaption></figure>



<figure class="wp-block-video"><video height="920" style="aspect-ratio: 1816 / 920;" width="1816" controls muted src="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_08_52_55_798.mp4"></video><figcaption class="wp-element-caption">Flipbook Flame Video</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="693" height="542" src="https://lycos7560.com/wp-content/uploads/2025/02/image-83.png" alt="" class="wp-image-39724" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-83.png 693w, https://lycos7560.com/wp-content/uploads/2025/02/image-83-300x235.png 300w" sizes="(max-width: 693px) 100vw, 693px" /></figure>



<div class="wp-block-file"><a id="wp-block-file--media-8e29395e-ab0b-42c2-bf45-20a8391e377c" href="https://lycos7560.com/wp-content/uploads/2025/02/TX_Flipbook_CandleFlame.unitypackage">TX_Flipbook_CandleFlame</a><a href="https://lycos7560.com/wp-content/uploads/2025/02/TX_Flipbook_CandleFlame.unitypackage" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-8e29395e-ab0b-42c2-bf45-20a8391e377c">다운로드</a></div>



<figure class="wp-block-image size-full"><img decoding="async" width="613" height="973" src="https://lycos7560.com/wp-content/uploads/2025/02/image-84.png" alt="" class="wp-image-39726" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-84.png 613w, https://lycos7560.com/wp-content/uploads/2025/02/image-84-189x300.png 189w" sizes="(max-width: 613px) 100vw, 613px" /><figcaption class="wp-element-caption">FlipBook Mode Debug Graph</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1654" height="991" src="https://lycos7560.com/wp-content/uploads/2025/02/image-86.png" alt="" class="wp-image-39728" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-86.png 1654w, https://lycos7560.com/wp-content/uploads/2025/02/image-86-300x180.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-86-768x460.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-86-1536x920.png 1536w" sizes="(max-width: 1654px) 100vw, 1654px" /><figcaption class="wp-element-caption">FlipBook Mode Debug</figcaption></figure>



<div class="wp-block-file"><a id="wp-block-file--media-4b4e556a-d996-4461-84ba-44b59b05f52e" href="https://lycos7560.com/wp-content/uploads/2025/02/TX_Flipbook_example.unitypackage">TX_Flipbook_example</a><a href="https://lycos7560.com/wp-content/uploads/2025/02/TX_Flipbook_example.unitypackage" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-4b4e556a-d996-4461-84ba-44b59b05f52e">다운로드</a></div>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h2 class="wp-block-heading">13. Flipbook Blending</h2>



<p>이 VFX는 <strong>일반적인 프레임 블렌딩(Frame Blending)과 모션 벡터(Motion Vectors)를 이용한 프레임 블렌딩</strong>의 차이를 보여줍니다.</p>



<p>모션 벡터 블렌딩(Motion Vector Blending)은 <strong>프레임 간 픽셀 이동 정보를 포함한 텍스처를 활용하여 프레임 간 부드러운 전환을 구현</strong>합니다.</p>



<p>이 방식은 <strong>플립북의 프레임 수를 줄이거나, 슬로우 모션(Slow Motion) 애니메이션을 구현할 때 유용</strong>합니다.</p>



<h3 class="wp-block-heading"><strong><strong>Covered Aspects:</strong></strong></h3>



<ul class="wp-block-list">
<li>Flipbook Player</li>



<li>UVs Mode</li>



<li>TexIndex Attribute</li>
</ul>



<figure class="wp-block-video"><video height="1196" style="aspect-ratio: 2232 / 1196;" width="2232" controls muted src="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_09_16_43_921.mp4"></video><figcaption class="wp-element-caption">Flipbook Blending Video</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1139" height="1061" src="https://lycos7560.com/wp-content/uploads/2025/02/image-87.png" alt="" class="wp-image-39732" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-87.png 1139w, https://lycos7560.com/wp-content/uploads/2025/02/image-87-300x279.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-87-768x715.png 768w" sizes="(max-width: 1139px) 100vw, 1139px" /><figcaption class="wp-element-caption">Flipbook Blending Graph Entire</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1490" height="1045" src="https://lycos7560.com/wp-content/uploads/2025/02/image-88.png" alt="" class="wp-image-39733" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-88.png 1490w, https://lycos7560.com/wp-content/uploads/2025/02/image-88-300x210.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-88-768x539.png 768w" sizes="(max-width: 1490px) 100vw, 1490px" /><figcaption class="wp-element-caption">Flipbook Blending (1)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1790" height="1039" src="https://lycos7560.com/wp-content/uploads/2025/02/image-89.jpg" alt="" class="wp-image-39734" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-89.jpg 1790w, https://lycos7560.com/wp-content/uploads/2025/02/image-89-300x174.jpg 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-89-768x446.jpg 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-89-1536x892.jpg 1536w" sizes="(max-width: 1790px) 100vw, 1790px" /><figcaption class="wp-element-caption">Flipbook Blending (2)</figcaption></figure>



<div class="wp-block-file"><a id="wp-block-file--media-4b503e0c-56b3-4777-858e-1c35a4a134ff" href="https://lycos7560.com/wp-content/uploads/2025/02/TX_Flipbook_Smoke.unitypackage">TX_Flipbook_Smoke</a><a href="https://lycos7560.com/wp-content/uploads/2025/02/TX_Flipbook_Smoke.unitypackage" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-4b503e0c-56b3-4777-858e-1c35a4a134ff">다운로드</a></div>



<figure class="wp-block-video"><video height="1360" style="aspect-ratio: 2536 / 1360;" width="2536" controls muted src="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_09_31_46_844.mp4"></video></figure>



<p>일반적인 Blend Frame은 단순한 알파 블렌딩(Alpha Blending) 방식으로, 프레임 수가 부족할 경우 끊김 현상이 발생할 수 있음.</p>



<p>Flipbook Player를 사용하면 자동으로 <code>TexIndex</code>가 증가하며 애니메이션이 진행됨.</p>



<p>Motion Vector Blending을 사용하면 픽셀 이동 정보를 활용하여 더욱 부드러운 전환을 구현할 수 있음.</p>



<ul class="wp-block-list">
<li>이 방법은 플립북 애니메이션의 프레임 수를 줄이면서도 부드러운 모션을 유지하는 데 유용함.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h2 class="wp-block-heading">14. <strong>TexIndex Advanced</strong></h2>



<p>이 고급 VFX는 <strong>texIndex 속성</strong>을 창의적으로 활용하는 여러 시스템으로 구성되어 있습니다.</p>



<p>시간(Time), 노이즈(Noise), 심지어 파티클의 위치(Position)까지 사용하여 </p>



<p><strong>texIndex 속성</strong>을 제어하며, 이를 통해 생동감 있는 VFX를 만듭니다.</p>



<h3 class="wp-block-heading"><strong><strong>Covered Aspects:</strong></strong></h3>



<ul class="wp-block-list">
<li>Flipbook UVs</li>



<li>TexIndex Attribute</li>



<li>Flipbook Player</li>
</ul>



<figure class="wp-block-image size-full"><img decoding="async" width="1781" height="589" src="https://lycos7560.com/wp-content/uploads/2025/02/image-118.jpg" alt="" class="wp-image-39787" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-118.jpg 1781w, https://lycos7560.com/wp-content/uploads/2025/02/image-118-300x99.jpg 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-118-768x254.jpg 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-118-1536x508.jpg 1536w" sizes="(max-width: 1781px) 100vw, 1781px" /><figcaption class="wp-element-caption">TexIndex Advanced Graph Entire</figcaption></figure>



<figure class="wp-block-video"><video height="1172" style="aspect-ratio: 2320 / 1172;" width="2320" controls src="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_17_52_30_504.mp4"></video><figcaption class="wp-element-caption">TexIndex Advanced Video</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="957" height="1179" src="https://lycos7560.com/wp-content/uploads/2025/02/image-89.png" alt="" class="wp-image-39739" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-89.png 957w, https://lycos7560.com/wp-content/uploads/2025/02/image-89-244x300.png 244w, https://lycos7560.com/wp-content/uploads/2025/02/image-89-768x946.png 768w" sizes="(max-width: 957px) 100vw, 957px" /><figcaption class="wp-element-caption">Brush Strokes Graph</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1892" height="706" src="https://lycos7560.com/wp-content/uploads/2025/02/image-90.png" alt="" class="wp-image-39742" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-90.png 1892w, https://lycos7560.com/wp-content/uploads/2025/02/image-90-300x112.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-90-768x287.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-90-1536x573.png 1536w" sizes="(max-width: 1892px) 100vw, 1892px" /><figcaption class="wp-element-caption">Brush Strokes (1)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1710" height="1061" src="https://lycos7560.com/wp-content/uploads/2025/02/image-91.png" alt="" class="wp-image-39743" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-91.png 1710w, https://lycos7560.com/wp-content/uploads/2025/02/image-91-300x186.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-91-768x477.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-91-1536x953.png 1536w" sizes="(max-width: 1710px) 100vw, 1710px" /><figcaption class="wp-element-caption">Brush Strokes (2)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1886" height="273" src="https://lycos7560.com/wp-content/uploads/2025/02/image-93.png" alt="" class="wp-image-39745" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-93.png 1886w, https://lycos7560.com/wp-content/uploads/2025/02/image-93-300x43.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-93-768x111.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-93-1536x222.png 1536w" sizes="(max-width: 1886px) 100vw, 1886px" /><figcaption class="wp-element-caption">Brush Strokes (3)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1534" height="979" src="https://lycos7560.com/wp-content/uploads/2025/02/image-92.png" alt="" class="wp-image-39744" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-92.png 1534w, https://lycos7560.com/wp-content/uploads/2025/02/image-92-300x191.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-92-768x490.png 768w" sizes="(max-width: 1534px) 100vw, 1534px" /><figcaption class="wp-element-caption">Brush Strokes (4)</figcaption></figure>



<div class="wp-block-file"><a id="wp-block-file--media-99b47eea-ac51-4bd0-a047-0892965818a9" href="https://lycos7560.com/wp-content/uploads/2025/02/TX_Brush.unitypackage">TX_Brush</a><a href="https://lycos7560.com/wp-content/uploads/2025/02/TX_Brush.unitypackage" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-99b47eea-ac51-4bd0-a047-0892965818a9">다운로드</a></div>



<figure class="wp-block-video"><video height="1232" style="aspect-ratio: 1944 / 1232;" width="1944" controls src="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_15_38_29_761.mp4"></video><figcaption class="wp-element-caption">Brush Strokes Video</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="773" height="1059" src="https://lycos7560.com/wp-content/uploads/2025/02/image-94.png" alt="" class="wp-image-39747" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-94.png 773w, https://lycos7560.com/wp-content/uploads/2025/02/image-94-219x300.png 219w, https://lycos7560.com/wp-content/uploads/2025/02/image-94-768x1052.png 768w" sizes="(max-width: 773px) 100vw, 773px" /><figcaption class="wp-element-caption">Background Pattern Graph</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1650" height="709" src="https://lycos7560.com/wp-content/uploads/2025/02/image-95.png" alt="" class="wp-image-39748" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-95.png 1650w, https://lycos7560.com/wp-content/uploads/2025/02/image-95-300x129.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-95-768x330.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-95-1536x660.png 1536w" sizes="(max-width: 1650px) 100vw, 1650px" /><figcaption class="wp-element-caption">Background Pattern (1)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1622" height="991" src="https://lycos7560.com/wp-content/uploads/2025/02/image-96.png" alt="" class="wp-image-39749" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-96.png 1622w, https://lycos7560.com/wp-content/uploads/2025/02/image-96-300x183.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-96-768x469.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-96-1536x938.png 1536w" sizes="(max-width: 1622px) 100vw, 1622px" /><figcaption class="wp-element-caption">Background Pattern (2)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1920" height="1283" src="https://lycos7560.com/wp-content/uploads/2025/02/image-97.jpg" alt="" class="wp-image-39750" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-97.jpg 1920w, https://lycos7560.com/wp-content/uploads/2025/02/image-97-300x200.jpg 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-97-768x513.jpg 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-97-1536x1026.jpg 1536w" sizes="(max-width: 1920px) 100vw, 1920px" /><figcaption class="wp-element-caption">Background Pattern (3)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="874" height="443" src="https://lycos7560.com/wp-content/uploads/2025/02/image-97.png" alt="" class="wp-image-39753" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-97.png 874w, https://lycos7560.com/wp-content/uploads/2025/02/image-97-300x152.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-97-768x389.png 768w" sizes="(max-width: 874px) 100vw, 874px" /><figcaption class="wp-element-caption">TX_Flipbook_Cross / TX_UnityLogo_Pack</figcaption></figure>



<div class="wp-block-file"><a id="wp-block-file--media-ce705eb8-08bf-44f0-a9e7-25222dbae62f" href="https://lycos7560.com/wp-content/uploads/2025/02/TX_Flipbook_CrossTX_UnityLogo_Pack.unitypackage">TX_Flipbook_Cross&amp;TX_UnityLogo_Pack</a><a href="https://lycos7560.com/wp-content/uploads/2025/02/TX_Flipbook_CrossTX_UnityLogo_Pack.unitypackage" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-ce705eb8-08bf-44f0-a9e7-25222dbae62f">다운로드</a></div>



<figure class="wp-block-video"><video height="1192" style="aspect-ratio: 2344 / 1192;" width="2344" controls muted src="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_16_29_35_748.mp4"></video><figcaption class="wp-element-caption">Background Pattern Video</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="802" height="1066" src="https://lycos7560.com/wp-content/uploads/2025/02/image-102.png" alt="" class="wp-image-39763" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-102.png 802w, https://lycos7560.com/wp-content/uploads/2025/02/image-102-226x300.png 226w, https://lycos7560.com/wp-content/uploads/2025/02/image-102-768x1021.png 768w" sizes="(max-width: 802px) 100vw, 802px" /><figcaption class="wp-element-caption">Unity Font Graph</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1538" height="1030" src="https://lycos7560.com/wp-content/uploads/2025/02/image-98.png" alt="" class="wp-image-39757" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-98.png 1538w, https://lycos7560.com/wp-content/uploads/2025/02/image-98-300x201.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-98-768x514.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-98-1536x1029.png 1536w" sizes="(max-width: 1538px) 100vw, 1538px" /><figcaption class="wp-element-caption">Unity Font (1)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1685" height="1071" src="https://lycos7560.com/wp-content/uploads/2025/02/image-99.png" alt="" class="wp-image-39758" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-99.png 1685w, https://lycos7560.com/wp-content/uploads/2025/02/image-99-300x191.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-99-768x488.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-99-1536x976.png 1536w" sizes="(max-width: 1685px) 100vw, 1685px" /><figcaption class="wp-element-caption">Unity Font (2)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1736" height="698" src="https://lycos7560.com/wp-content/uploads/2025/02/image-100.png" alt="" class="wp-image-39759" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-100.png 1736w, https://lycos7560.com/wp-content/uploads/2025/02/image-100-300x121.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-100-768x309.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-100-1536x618.png 1536w" sizes="(max-width: 1736px) 100vw, 1736px" /><figcaption class="wp-element-caption">Unity Font (3)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1066" height="444" src="https://lycos7560.com/wp-content/uploads/2025/02/image-101.png" alt="" class="wp-image-39761" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-101.png 1066w, https://lycos7560.com/wp-content/uploads/2025/02/image-101-300x125.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-101-768x320.png 768w" sizes="(max-width: 1066px) 100vw, 1066px" /><figcaption class="wp-element-caption">TX_Flipbook_Unity</figcaption></figure>



<div class="wp-block-file"><a id="wp-block-file--media-bfe388c7-2813-44c0-b804-a8ea95c651be" href="https://lycos7560.com/wp-content/uploads/2025/02/TX_Flipbook_Unity_Text.unitypackage">TX_Flipbook_Unity_Text</a><a href="https://lycos7560.com/wp-content/uploads/2025/02/TX_Flipbook_Unity_Text.unitypackage" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-bfe388c7-2813-44c0-b804-a8ea95c651be">다운로드</a></div>



<figure class="wp-block-video"><video height="1192" style="aspect-ratio: 2344 / 1192;" width="2344" controls muted src="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_16_48_06_307.mp4"></video><figcaption class="wp-element-caption">Unity Font Viedo</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="956" height="1002" src="https://lycos7560.com/wp-content/uploads/2025/02/image-103.png" alt="" class="wp-image-39764" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-103.png 956w, https://lycos7560.com/wp-content/uploads/2025/02/image-103-286x300.png 286w, https://lycos7560.com/wp-content/uploads/2025/02/image-103-768x805.png 768w" sizes="(max-width: 956px) 100vw, 956px" /><figcaption class="wp-element-caption">Cubes Graph</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="853" height="1068" src="https://lycos7560.com/wp-content/uploads/2025/02/image-104.png" alt="" class="wp-image-39765" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-104.png 853w, https://lycos7560.com/wp-content/uploads/2025/02/image-104-240x300.png 240w, https://lycos7560.com/wp-content/uploads/2025/02/image-104-768x962.png 768w" sizes="(max-width: 853px) 100vw, 853px" /><figcaption class="wp-element-caption">Cubes (1)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1782" height="915" src="https://lycos7560.com/wp-content/uploads/2025/02/image-105.png" alt="" class="wp-image-39766" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-105.png 1782w, https://lycos7560.com/wp-content/uploads/2025/02/image-105-300x154.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-105-768x394.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-105-1536x789.png 1536w" sizes="(max-width: 1782px) 100vw, 1782px" /><figcaption class="wp-element-caption">Cubes (2)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="2517" height="748" src="https://lycos7560.com/wp-content/uploads/2025/02/image-106.png" alt="" class="wp-image-39767" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-106.png 2517w, https://lycos7560.com/wp-content/uploads/2025/02/image-106-300x89.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-106-768x228.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-106-1536x456.png 1536w, https://lycos7560.com/wp-content/uploads/2025/02/image-106-2048x609.png 2048w" sizes="(max-width: 2517px) 100vw, 2517px" /><figcaption class="wp-element-caption">Cubes (3)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="531" height="463" src="https://lycos7560.com/wp-content/uploads/2025/02/image-107.png" alt="" class="wp-image-39768" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-107.png 531w, https://lycos7560.com/wp-content/uploads/2025/02/image-107-300x262.png 300w" sizes="(max-width: 531px) 100vw, 531px" /><figcaption class="wp-element-caption">ST_Unity_Cube</figcaption></figure>



<div class="wp-block-file"><a id="wp-block-file--media-7172feb2-4cdd-4a20-b97c-7c1830fcb96c" href="https://lycos7560.com/wp-content/uploads/2025/02/ST_Unity_Cube.unitypackage">ST_Unity_Cube</a><a href="https://lycos7560.com/wp-content/uploads/2025/02/ST_Unity_Cube.unitypackage" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-7172feb2-4cdd-4a20-b97c-7c1830fcb96c">다운로드</a></div>



<figure class="wp-block-image size-full"><img decoding="async" width="1692" height="1073" src="https://lycos7560.com/wp-content/uploads/2025/02/image-108.png" alt="" class="wp-image-39770" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-108.png 1692w, https://lycos7560.com/wp-content/uploads/2025/02/image-108-300x190.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-108-768x487.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-108-1536x974.png 1536w" sizes="(max-width: 1692px) 100vw, 1692px" /><figcaption class="wp-element-caption">SG_Unity_Sketch</figcaption></figure>



<div class="wp-block-file"><a id="wp-block-file--media-0ca3e3fb-502c-42d4-9555-ff36d271c883" href="https://lycos7560.com/wp-content/uploads/2025/02/SG_Unity_Sketch.unitypackage">SG_Unity_Sketch</a><a href="https://lycos7560.com/wp-content/uploads/2025/02/SG_Unity_Sketch.unitypackage" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-0ca3e3fb-502c-42d4-9555-ff36d271c883">다운로드</a></div>



<figure class="wp-block-video"><video height="1172" style="aspect-ratio: 2320 / 1172;" width="2320" controls muted src="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_17_13_12_773.mp4"></video><figcaption class="wp-element-caption">Cubes Video</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="814" height="1074" src="https://lycos7560.com/wp-content/uploads/2025/02/image-109.png" alt="" class="wp-image-39773" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-109.png 814w, https://lycos7560.com/wp-content/uploads/2025/02/image-109-227x300.png 227w, https://lycos7560.com/wp-content/uploads/2025/02/image-109-768x1013.png 768w" sizes="(max-width: 814px) 100vw, 814px" /><figcaption class="wp-element-caption">Lightning Graph</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1155" height="1013" src="https://lycos7560.com/wp-content/uploads/2025/02/image-110.png" alt="" class="wp-image-39774" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-110.png 1155w, https://lycos7560.com/wp-content/uploads/2025/02/image-110-300x263.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-110-768x674.png 768w" sizes="(max-width: 1155px) 100vw, 1155px" /><figcaption class="wp-element-caption">Lightning (1)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1552" height="1070" src="https://lycos7560.com/wp-content/uploads/2025/02/image-111.png" alt="" class="wp-image-39775" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-111.png 1552w, https://lycos7560.com/wp-content/uploads/2025/02/image-111-300x207.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-111-768x529.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-111-1536x1059.png 1536w" sizes="(max-width: 1552px) 100vw, 1552px" /><figcaption class="wp-element-caption">Lightning (2)</figcaption></figure>



<div class="wp-block-file"><a id="wp-block-file--media-d1dd35b8-2d8b-43b6-a530-f86ce11dc694" href="https://lycos7560.com/wp-content/uploads/2025/02/TX_Lighting.unitypackage">TX_Lighting</a><a href="https://lycos7560.com/wp-content/uploads/2025/02/TX_Lighting.unitypackage" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-d1dd35b8-2d8b-43b6-a530-f86ce11dc694">다운로드</a></div>



<figure class="wp-block-video"><video height="1172" style="aspect-ratio: 2320 / 1172;" width="2320" controls muted src="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_17_23_47_199.mp4"></video><figcaption class="wp-element-caption">Lightning Video</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="952" height="1026" src="https://lycos7560.com/wp-content/uploads/2025/02/image-112.png" alt="" class="wp-image-39778" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-112.png 952w, https://lycos7560.com/wp-content/uploads/2025/02/image-112-278x300.png 278w, https://lycos7560.com/wp-content/uploads/2025/02/image-112-768x828.png 768w" sizes="(max-width: 952px) 100vw, 952px" /><figcaption class="wp-element-caption">I Dot Graph</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1254" height="1058" src="https://lycos7560.com/wp-content/uploads/2025/02/image-113.png" alt="" class="wp-image-39779" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-113.png 1254w, https://lycos7560.com/wp-content/uploads/2025/02/image-113-300x253.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-113-768x648.png 768w" sizes="(max-width: 1254px) 100vw, 1254px" /><figcaption class="wp-element-caption">I Dot (1)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1478" height="624" src="https://lycos7560.com/wp-content/uploads/2025/02/image-114.png" alt="" class="wp-image-39780" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-114.png 1478w, https://lycos7560.com/wp-content/uploads/2025/02/image-114-300x127.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-114-768x324.png 768w" sizes="(max-width: 1478px) 100vw, 1478px" /><figcaption class="wp-element-caption">I Dot (2)</figcaption></figure>



<figure class="wp-block-video"><video height="1172" style="aspect-ratio: 2320 / 1172;" width="2320" controls muted src="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_17_32_30_64.mp4"></video><figcaption class="wp-element-caption">I Dot Video</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="527" height="971" src="https://lycos7560.com/wp-content/uploads/2025/02/image-115.png" alt="" class="wp-image-39782" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-115.png 527w, https://lycos7560.com/wp-content/uploads/2025/02/image-115-163x300.png 163w" sizes="(max-width: 527px) 100vw, 527px" /><figcaption class="wp-element-caption">Floating Shapes Graph</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="938" height="1039" src="https://lycos7560.com/wp-content/uploads/2025/02/image-116.jpg" alt="" class="wp-image-39783" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-116.jpg 938w, https://lycos7560.com/wp-content/uploads/2025/02/image-116-271x300.jpg 271w, https://lycos7560.com/wp-content/uploads/2025/02/image-116-768x851.jpg 768w" sizes="(max-width: 938px) 100vw, 938px" /><figcaption class="wp-element-caption">Floating Shapes (1)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1611" height="927" src="https://lycos7560.com/wp-content/uploads/2025/02/image-116.png" alt="" class="wp-image-39784" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-116.png 1611w, https://lycos7560.com/wp-content/uploads/2025/02/image-116-300x173.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-116-768x442.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-116-1536x884.png 1536w" sizes="(max-width: 1611px) 100vw, 1611px" /><figcaption class="wp-element-caption">Floating Shapes (2)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1609" height="918" src="https://lycos7560.com/wp-content/uploads/2025/02/image-117.png" alt="" class="wp-image-39785" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-117.png 1609w, https://lycos7560.com/wp-content/uploads/2025/02/image-117-300x171.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-117-768x438.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-117-1536x876.png 1536w" sizes="(max-width: 1609px) 100vw, 1609px" /><figcaption class="wp-element-caption">Floating Shapes (3)</figcaption></figure>



<figure class="wp-block-video"><video height="1172" style="aspect-ratio: 2320 / 1172;" width="2320" controls src="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_17_45_58_212.mp4"></video></figure>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h2 class="wp-block-heading">15. <strong>Pivot Attribute</strong></h2>



<p><strong>피벗 속성(Pivot Attribute)</strong> 은 <strong>출력 렌더(output render)</strong> 가 <strong>파티클 위치를 기준으로 어디에서 생성되는지</strong> 를 제어합니다.</p>



<p>기본적으로 <strong>피벗은 파티클의 중심(Position)에 위치</strong>하지만, <strong>X, Y, Z 축을 따라 이동(offset)</strong> 시킬 수 있습니다.</p>



<p>피벗을 오프셋하면 <strong>스케일(크기) 조정 및 회전(rotation) 시 보다 매력적인 움직임을 만들 수 있습니다</strong>.</p>



<h3 class="wp-block-heading"><strong><strong>Covered Aspects:</strong></strong></h3>



<ul class="wp-block-list">
<li>Pivot Attribute</li>



<li>Angle Attribute</li>
</ul>



<figure class="wp-block-video"><video height="1172" style="aspect-ratio: 2320 / 1172;" width="2320" controls muted src="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_18_15_21_603.mp4"></video></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="840" height="1302" src="https://lycos7560.com/wp-content/uploads/2025/02/image-118.png" alt="" class="wp-image-39790" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-118.png 840w, https://lycos7560.com/wp-content/uploads/2025/02/image-118-194x300.png 194w, https://lycos7560.com/wp-content/uploads/2025/02/image-118-768x1190.png 768w" sizes="(max-width: 840px) 100vw, 840px" /><figcaption class="wp-element-caption">Pivot Attribute Graph Entire</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1684" height="1159" src="https://lycos7560.com/wp-content/uploads/2025/02/image-119.png" alt="" class="wp-image-39792" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-119.png 1684w, https://lycos7560.com/wp-content/uploads/2025/02/image-119-300x206.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-119-768x529.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-119-1536x1057.png 1536w" sizes="(max-width: 1684px) 100vw, 1684px" /><figcaption class="wp-element-caption">Pivot Attribute (1)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1595" height="1291" src="https://lycos7560.com/wp-content/uploads/2025/02/image-120.png" alt="" class="wp-image-39793" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-120.png 1595w, https://lycos7560.com/wp-content/uploads/2025/02/image-120-300x243.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-120-768x622.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-120-1536x1243.png 1536w" sizes="(max-width: 1595px) 100vw, 1595px" /><figcaption class="wp-element-caption">Pivot Attribute (2)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1340" height="406" src="https://lycos7560.com/wp-content/uploads/2025/02/image-121.png" alt="" class="wp-image-39794" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-121.png 1340w, https://lycos7560.com/wp-content/uploads/2025/02/image-121-300x91.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-121-768x233.png 768w" sizes="(max-width: 1340px) 100vw, 1340px" /></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="883" height="410" src="https://lycos7560.com/wp-content/uploads/2025/02/image-122.png" alt="" class="wp-image-39795" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-122.png 883w, https://lycos7560.com/wp-content/uploads/2025/02/image-122-300x139.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-122-768x357.png 768w" sizes="(max-width: 883px) 100vw, 883px" /></figure>



<div class="wp-block-file"><a id="wp-block-file--media-1f95656c-d925-4b94-b321-88cbace793da" href="https://lycos7560.com/wp-content/uploads/2025/02/Pivot-Leaf.unitypackage">Pivot Leaf</a><a href="https://lycos7560.com/wp-content/uploads/2025/02/Pivot-Leaf.unitypackage" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-1f95656c-d925-4b94-b321-88cbace793da">다운로드</a></div>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h2 class="wp-block-heading">16. <strong>Pivot Advanced</strong></h2>



<p>파티클의 <strong>피벗(Pivot)</strong> 을 제어하는 것은 <strong>자연스럽고 흥미로운 움직임을 구현하는 핵심 요소</strong>입니다.</p>



<p>이 VFX에서는 <strong>피벗을 조작하여 꽃잎, 잎사귀, 가시 등이 자연스럽게 배치 및 애니메이션되는 과정</strong>을 보여줍니다.</p>



<p>또한, <strong>Shader Graph와 VFX Graph의 연동을 통해 셰이더를 제어하는 방법</strong>도 시연합니다.</p>



<h3 class="wp-block-heading"><strong><strong>Covered Aspects:</strong></strong></h3>



<ul class="wp-block-list">
<li>Pivot Attribute</li>



<li>Shader Graph integration</li>



<li>Activation Port</li>
</ul>



<figure class="wp-block-video"><video height="1176" style="aspect-ratio: 2336 / 1176;" width="2336" controls muted src="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_24_11_02_22_851.mp4"></video></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1528" height="1014" src="https://lycos7560.com/wp-content/uploads/2025/02/image-125.jpg" alt="" class="wp-image-39805" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-125.jpg 1528w, https://lycos7560.com/wp-content/uploads/2025/02/image-125-300x199.jpg 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-125-768x510.jpg 768w" sizes="(max-width: 1528px) 100vw, 1528px" /><figcaption class="wp-element-caption">Pivot Advanced Graph Entire</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1249" height="1920" src="https://lycos7560.com/wp-content/uploads/2025/02/image-123.jpg" alt="" class="wp-image-39802" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-123.jpg 1249w, https://lycos7560.com/wp-content/uploads/2025/02/image-123-195x300.jpg 195w, https://lycos7560.com/wp-content/uploads/2025/02/image-123-768x1181.jpg 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-123-999x1536.jpg 999w" sizes="(max-width: 1249px) 100vw, 1249px" /><figcaption class="wp-element-caption">Flower Blossom Graph</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1741" height="1032" src="https://lycos7560.com/wp-content/uploads/2025/02/image-125.png" alt="" class="wp-image-39807" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-125.png 1741w, https://lycos7560.com/wp-content/uploads/2025/02/image-125-300x178.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-125-768x455.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-125-1536x910.png 1536w" sizes="(max-width: 1741px) 100vw, 1741px" /><figcaption class="wp-element-caption">Flower Blossom (1)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1243" height="986" src="https://lycos7560.com/wp-content/uploads/2025/02/image-126.png" alt="" class="wp-image-39810" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-126.png 1243w, https://lycos7560.com/wp-content/uploads/2025/02/image-126-300x238.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-126-768x609.png 768w" sizes="(max-width: 1243px) 100vw, 1243px" /><figcaption class="wp-element-caption">Flower Blossom (2)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1106" height="673" src="https://lycos7560.com/wp-content/uploads/2025/02/image-126.jpg" alt="" class="wp-image-39808" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-126.jpg 1106w, https://lycos7560.com/wp-content/uploads/2025/02/image-126-300x183.jpg 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-126-768x467.jpg 768w" sizes="(max-width: 1106px) 100vw, 1106px" /><figcaption class="wp-element-caption">Flower Blossom (3)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1507" height="1024" src="https://lycos7560.com/wp-content/uploads/2025/02/image-127.png" alt="" class="wp-image-39811" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-127.png 1507w, https://lycos7560.com/wp-content/uploads/2025/02/image-127-300x204.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-127-768x522.png 768w" sizes="(max-width: 1507px) 100vw, 1507px" /><figcaption class="wp-element-caption">Flower Blossom (4)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1174" height="1063" src="https://lycos7560.com/wp-content/uploads/2025/02/image-128.png" alt="" class="wp-image-39812" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-128.png 1174w, https://lycos7560.com/wp-content/uploads/2025/02/image-128-300x272.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-128-768x695.png 768w" sizes="(max-width: 1174px) 100vw, 1174px" /><figcaption class="wp-element-caption">SG_PetalBend</figcaption></figure>



<div class="wp-block-file"><a id="wp-block-file--media-92470543-5aa6-4761-8b34-400c76614df8" href="https://lycos7560.com/wp-content/uploads/2025/02/SG_PetalBend.unitypackage">SG_PetalBend</a><a href="https://lycos7560.com/wp-content/uploads/2025/02/SG_PetalBend.unitypackage" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-92470543-5aa6-4761-8b34-400c76614df8">다운로드</a></div>



<figure class="wp-block-image size-full"><img decoding="async" width="1727" height="1536" src="https://lycos7560.com/wp-content/uploads/2025/02/image-123.png" alt="" class="wp-image-39803" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-123.png 1727w, https://lycos7560.com/wp-content/uploads/2025/02/image-123-300x267.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-123-768x683.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-123-1536x1366.png 1536w" sizes="(max-width: 1727px) 100vw, 1727px" /><figcaption class="wp-element-caption">Green Leaf Graph</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="954" height="1044" src="https://lycos7560.com/wp-content/uploads/2025/02/image-129.png" alt="" class="wp-image-39814" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-129.png 954w, https://lycos7560.com/wp-content/uploads/2025/02/image-129-274x300.png 274w, https://lycos7560.com/wp-content/uploads/2025/02/image-129-768x840.png 768w" sizes="(max-width: 954px) 100vw, 954px" /><figcaption class="wp-element-caption">Green Leaf (1)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="2254" height="1039" src="https://lycos7560.com/wp-content/uploads/2025/02/image-130.png" alt="" class="wp-image-39815" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-130.png 2254w, https://lycos7560.com/wp-content/uploads/2025/02/image-130-300x138.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-130-768x354.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-130-1536x708.png 1536w, https://lycos7560.com/wp-content/uploads/2025/02/image-130-2048x944.png 2048w" sizes="(max-width: 2254px) 100vw, 2254px" /><figcaption class="wp-element-caption">Green Leaf (2)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="855" height="1573" src="https://lycos7560.com/wp-content/uploads/2025/02/image-124.png" alt="" class="wp-image-39804" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-124.png 855w, https://lycos7560.com/wp-content/uploads/2025/02/image-124-163x300.png 163w, https://lycos7560.com/wp-content/uploads/2025/02/image-124-768x1413.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-124-835x1536.png 835w" sizes="(max-width: 855px) 100vw, 855px" /><figcaption class="wp-element-caption">Spines Graph</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="965" height="1067" src="https://lycos7560.com/wp-content/uploads/2025/02/image-131.png" alt="" class="wp-image-39816" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-131.png 965w, https://lycos7560.com/wp-content/uploads/2025/02/image-131-271x300.png 271w, https://lycos7560.com/wp-content/uploads/2025/02/image-131-768x849.png 768w" sizes="(max-width: 965px) 100vw, 965px" /><figcaption class="wp-element-caption">Spines (1)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="607" height="689" src="https://lycos7560.com/wp-content/uploads/2025/02/image-132.png" alt="" class="wp-image-39817" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-132.png 607w, https://lycos7560.com/wp-content/uploads/2025/02/image-132-264x300.png 264w" sizes="(max-width: 607px) 100vw, 607px" /><figcaption class="wp-element-caption">Spines (2)</figcaption></figure>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h2 class="wp-block-heading">17. <strong>Sample Mesh</strong></h2>



<p>이 VFX는 <strong>메시 샘플링(Sample Mesh)</strong> 을 활용하여 <strong>파티클을 메시 표면에 생성</strong> 하고, 메시의 <strong>버텍스 색상(Vertex Color)</strong> 을 <strong>상속</strong> 하는 방법을 보여줍니다.</p>



<p>또한, 메시의 버텍스 색상에 <strong>앰비언트 오클루전(Ambient Occlusion, AO)</strong> 값을 미리 베이크(Bake) 해두었으며, 이를 이용해 <strong>파티클의 색상을 설정</strong> 합니다.</p>



<h3 class="wp-block-heading"><strong><strong>Covered Aspects:</strong></strong></h3>



<ul class="wp-block-list">
<li>Mesh Sampling</li>



<li>Sample Mesh Operator</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-video"><video height="1120" style="aspect-ratio: 1984 / 1120;" width="1984" controls muted src="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_03_05_01_58_06_887.mp4"></video><figcaption class="wp-element-caption">Sample Mesh Video</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1436" height="1920" src="https://lycos7560.com/wp-content/uploads/2025/02/image-181.jpg" alt="" class="wp-image-39896" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-181.jpg 1436w, https://lycos7560.com/wp-content/uploads/2025/02/image-181-224x300.jpg 224w, https://lycos7560.com/wp-content/uploads/2025/02/image-181-768x1027.jpg 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-181-1149x1536.jpg 1149w" sizes="(max-width: 1436px) 100vw, 1436px" /><figcaption class="wp-element-caption">Sample Mesh Graph Entire</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1920" height="1042" src="https://lycos7560.com/wp-content/uploads/2025/02/image-181-1.jpg" alt="" class="wp-image-39897" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-181-1.jpg 1920w, https://lycos7560.com/wp-content/uploads/2025/02/image-181-1-300x163.jpg 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-181-1-768x417.jpg 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-181-1-1536x834.jpg 1536w" sizes="(max-width: 1920px) 100vw, 1920px" /><figcaption class="wp-element-caption">Sample Mesh (1)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1198" height="868" src="https://lycos7560.com/wp-content/uploads/2025/02/image-182-1.jpg" alt="" class="wp-image-39904" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-182-1.jpg 1198w, https://lycos7560.com/wp-content/uploads/2025/02/image-182-1-300x217.jpg 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-182-1-768x556.jpg 768w" sizes="(max-width: 1198px) 100vw, 1198px" /><figcaption class="wp-element-caption">Sample Mesh Plane</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1920" height="1045" src="https://lycos7560.com/wp-content/uploads/2025/02/image-181-2.jpg" alt="" class="wp-image-39898" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-181-2.jpg 1920w, https://lycos7560.com/wp-content/uploads/2025/02/image-181-2-300x163.jpg 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-181-2-768x418.jpg 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-181-2-1536x836.jpg 1536w" sizes="(max-width: 1920px) 100vw, 1920px" /><figcaption class="wp-element-caption">Sample Mesh (2)</figcaption></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="1859" height="498" src="https://lycos7560.com/wp-content/uploads/2025/02/image-181.png" alt="" class="wp-image-39899" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-181.png 1859w, https://lycos7560.com/wp-content/uploads/2025/02/image-181-300x80.png 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-181-768x206.png 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-181-1536x411.png 1536w" sizes="(max-width: 1859px) 100vw, 1859px" /><figcaption class="wp-element-caption">Lion Mesh</figcaption></figure>



<div class="wp-block-file"><a id="wp-block-file--media-1e450586-94e2-4d98-9d7a-0cf1b5b87dc3" href="https://lycos7560.com/wp-content/uploads/2025/02/Lion.unitypackage">Lion</a><a href="https://lycos7560.com/wp-content/uploads/2025/02/Lion.unitypackage" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-1e450586-94e2-4d98-9d7a-0cf1b5b87dc3">다운로드</a></div>



<figure class="wp-block-image size-full"><img decoding="async" width="1920" height="1763" src="https://lycos7560.com/wp-content/uploads/2025/02/image-182.jpg" alt="" class="wp-image-39902" srcset="https://lycos7560.com/wp-content/uploads/2025/02/image-182.jpg 1920w, https://lycos7560.com/wp-content/uploads/2025/02/image-182-300x275.jpg 300w, https://lycos7560.com/wp-content/uploads/2025/02/image-182-768x705.jpg 768w, https://lycos7560.com/wp-content/uploads/2025/02/image-182-1536x1410.jpg 1536w" sizes="(max-width: 1920px) 100vw, 1920px" /><figcaption class="wp-element-caption">Sample Mesh (3)</figcaption></figure>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>
<p>The post <a href="https://lycos7560.com/unity/urp-vfx-learning-templates-2/39699/">URP VFX Learning Templates (2)</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/unity/urp-vfx-learning-templates-2/39699/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		<enclosure url="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_07_35_03_551.mp4" length="7021778" type="video/mp4" />
<enclosure url="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_07_58_26_612.mp4" length="11089805" type="video/mp4" />
<enclosure url="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_08_13_45_776.mp4" length="7364224" type="video/mp4" />
<enclosure url="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_08_52_55_798.mp4" length="12897827" type="video/mp4" />
<enclosure url="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_09_16_43_921.mp4" length="21185407" type="video/mp4" />
<enclosure url="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_09_31_46_844.mp4" length="4690749" type="video/mp4" />
<enclosure url="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_15_38_29_761.mp4" length="15542810" type="video/mp4" />
<enclosure url="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_17_52_30_504.mp4" length="229371564" type="video/mp4" />
<enclosure url="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_16_29_35_748.mp4" length="44215272" type="video/mp4" />
<enclosure url="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_16_48_06_307.mp4" length="27463485" type="video/mp4" />
<enclosure url="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_17_13_12_773.mp4" length="71870864" type="video/mp4" />
<enclosure url="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_17_23_47_199.mp4" length="36961851" type="video/mp4" />
<enclosure url="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_17_32_30_64.mp4" length="9428918" type="video/mp4" />
<enclosure url="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_17_45_58_212.mp4" length="18471538" type="video/mp4" />
<enclosure url="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_23_18_15_21_603.mp4" length="12531473" type="video/mp4" />
<enclosure url="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_02_24_11_02_22_851.mp4" length="27680510" type="video/mp4" />
<enclosure url="https://lycos7560.com/wp-content/uploads/2025/02/녹화_2025_03_05_01_58_06_887.mp4" length="14078818" type="video/mp4" />

			</item>
		<item>
		<title>ECS의 World와 SubScene의 관계</title>
		<link>https://lycos7560.com/unity/ecs%ec%9d%98-world%ec%99%80-subscene%ec%9d%98-%ea%b4%80%ea%b3%84/39668/</link>
					<comments>https://lycos7560.com/unity/ecs%ec%9d%98-world%ec%99%80-subscene%ec%9d%98-%ea%b4%80%ea%b3%84/39668/#respond</comments>
		
		<dc:creator><![CDATA[lycos7560]]></dc:creator>
		<pubDate>Wed, 19 Feb 2025 04:52:42 +0000</pubDate>
				<category><![CDATA[Unity]]></category>
		<category><![CDATA[Archetype]]></category>
		<category><![CDATA[Archetypes]]></category>
		<category><![CDATA[architecture]]></category>
		<category><![CDATA[Component]]></category>
		<category><![CDATA[ComponentBased]]></category>
		<category><![CDATA[ComponentData]]></category>
		<category><![CDATA[Container]]></category>
		<category><![CDATA[DataContainer]]></category>
		<category><![CDATA[DataManagement]]></category>
		<category><![CDATA[DataOriented]]></category>
		<category><![CDATA[DataStructure]]></category>
		<category><![CDATA[DOTS]]></category>
		<category><![CDATA[ECS]]></category>
		<category><![CDATA[Entity]]></category>
		<category><![CDATA[EntityManager]]></category>
		<category><![CDATA[EntityQuery]]></category>
		<category><![CDATA[EntityState]]></category>
		<category><![CDATA[EntitySystem]]></category>
		<category><![CDATA[GameEngine]]></category>
		<category><![CDATA[GameObject]]></category>
		<category><![CDATA[Query]]></category>
		<category><![CDATA[QuerySystem]]></category>
		<category><![CDATA[Scene]]></category>
		<category><![CDATA[SceneManagement]]></category>
		<category><![CDATA[SceneSystem]]></category>
		<category><![CDATA[StateManagement]]></category>
		<category><![CDATA[study]]></category>
		<category><![CDATA[SubScene]]></category>
		<category><![CDATA[System]]></category>
		<category><![CDATA[SystemBase]]></category>
		<category><![CDATA[World]]></category>
		<category><![CDATA[WorldState]]></category>
		<category><![CDATA[WorldSystem]]></category>
		<category><![CDATA[공부]]></category>
		<guid isPermaLink="false">https://lycos7560.com/?p=39668</guid>

					<description><![CDATA[<p>⭐ 개념 정리 ✅ World ECS에서 World는 Entity와 System 등을 관리하는 Container 역할 World는 특정 씬(Scene)에 종속되지 않고, 모든 ECS 데이터를 포함하여 관리한다. World가 관리하는 핵심 구성 요소 4가지 ✅ SubScene SubScene은 씬(Scene) 내부에서 특정 ECS 데이터(Entity)를 포함하는 컨테이너 역할을 한다. SubScene이 로드되면, 그 안의 GameObject들이 자동으로 Entity로 변환(Entity Conversion)되어 World에 등록 ➡️ SubScene의 로드 [&#8230;]</p>
<p>The post <a href="https://lycos7560.com/unity/ecs%ec%9d%98-world%ec%99%80-subscene%ec%9d%98-%ea%b4%80%ea%b3%84/39668/">ECS의 World와 SubScene의 관계</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></description>
										<content:encoded><![CDATA[				<div class="wp-block-uagb-table-of-contents uagb-toc__align-left uagb-toc__columns-1  uagb-block-4370eae9      "
					data-scroll= "1"
					data-offset= "30"
					style=""
				>
				<div class="uagb-toc__wrap">
						<div class="uagb-toc__title">
							ECS의 World와 SubScene의 관계						</div>
																						<div class="uagb-toc__list-wrap ">
						<ol class="uagb-toc__list"><li class="uagb-toc__list"><a href="#개념-정리" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b50.png" alt="⭐" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 개념 정리</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#world" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> World</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#subscene" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> SubScene</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#subscene의-로드-과정" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/27a1.png" alt="➡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> SubScene의 로드 과정</a></li></ul><li class="uagb-toc__list"><a href="#world와-subscene의-관계" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> World와 SubScene의 관계</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#world는-subscene을-포함하는-상위-컨테이너인가" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2753.png" alt="❓" class="wp-smiley" style="height: 1em; max-height: 1em;" /> World는 SubScene을 포함하는 상위 컨테이너인가?</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#서로-다른-world에서-같은-subscene을-공유할-수-있을까" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2753.png" alt="❓" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 서로 다른 World에서 같은 SubScene을 공유할 수 있을까?</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#서로-다른-world에서-같은-subscene을-공유하는-방법" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/27a1.png" alt="➡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 서로 다른 World에서 같은 SubScene을 공유하는 방법</a></li></ul><li class="uagb-toc__list"><a href="#subscene-내의-entity들이-서로-다른-world에-포함될-수-있을까" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2753.png" alt="❓" class="wp-smiley" style="height: 1em; max-height: 1em;" />SubScene 내의 Entity들이 서로 다른 World에 포함될 수 있을까?</a><ul class="uagb-toc__list"><li class="uagb-toc__list"><a href="#일반적인-subscene의-world-포함-방식" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/27a1.png" alt="➡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 일반적인 SubScene의 World 포함 방식</a><li class="uagb-toc__list"><li class="uagb-toc__list"><a href="#특정-entity만-다른-world에-포함시키는-방법" class="uagb-toc-link__trigger"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/27a1.png" alt="➡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 특정 Entity만 다른 World에 포함시키는 방법</a></ul></ul></ol>					</div>
									</div>
				</div>
			


<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b50.png" alt="⭐" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 개념 정리</h2>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> World</h3>



<p><code><strong>ECS</strong></code>에서<code> <strong>World</strong></code>는 <code><strong>Entity</strong></code>와 <code><strong>System</strong></code> 등을 관리하는 Container 역할</p>



<p><code><strong>World</strong></code>는 <strong>특정 씬(Scene)에 종속되지 않고</strong>, 모든 ECS 데이터를 포함하여 관리한다.</p>



<p><code><strong>World</strong></code>가 관리하는 핵심 구성 요소 4가지</p>



<ul class="wp-block-list">
<li><strong><code>EntityManager</code></strong> → <code><strong>Entity</strong></code>와 <strong><code>Component</code></strong>관리</li>



<li><strong><code>Systems</code></strong> → ECS 시스템 실행 및 업데이트</li>



<li><strong><code>Archetypes</code></strong> → <code><strong>Entity</strong></code> 구조 저장 및 관리</li>



<li><strong><code>Queries</code></strong> → 특정 조건을 만족하는 <code><strong>Entity</strong></code> 검색</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> SubScene</h3>



<p><code><strong>SubScene</strong></code>은 씬(Scene) 내부에서 특정 ECS 데이터(<code><strong>Entity</strong></code>)를 포함하는 컨테이너 역할을 한다.</p>



<p><code><strong>SubScene</strong></code>이 로드되면, 그 안의 GameObject들이 자동으로 <code><strong>Entity</strong></code>로 변환(Entity Conversion)되어 <code><code><strong>World</strong></code></code>에 등록</p>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/27a1.png" alt="➡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> SubScene의 로드 과정</h4>



<ol class="wp-block-list">
<li> <strong><code><strong>SubScene</strong></code></strong> <strong>로드</strong> → <code><strong>SceneSystem</strong></code>이 <code><strong>SubScene</strong></code>을 <code><code><strong>World</strong></code></code>에 추가</li>



<li>GameObject <strong>→ <code><strong>Entity</strong></code> </strong>변환</li>



<li>EntityManager가 모든 <strong><code>Entity</code> </strong>관리</li>



<li>ECS 시스템이 해당 <strong><code>Entity</code> </strong>를 처리</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> World와 SubScene의 관계</h3>



<p><code><code><strong>World</strong></code></code>는 <strong><code><strong>MainScene</strong></code></strong>과 <strong><code><strong>SubScene</strong></code></strong>을 구분하지 않고, 모든 ECS 데이터를 포함하여 관리</p>



<p><strong><code><strong>SubScene</strong></code></strong>이 로드되면 해당 오브젝트들이 ECS <strong><code>Entity</code></strong>로 변환되어 <code><code><code><code><code><strong>World</strong></code></code></code></code></code>에 등록됨</p>



<p><strong><code><code>World</code></code> </strong>자체는 <strong>씬(Scene)</strong>을 직접적으로 관리하지 않지만, <strong><code><code>World</code></code></strong>가 관리하는 <code><strong>SceneSystem</strong></code>을 사용해 <strong><code><strong>SubScene</strong></code></strong>을 동적으로 로드/언로드할 수는 있음</p>



<p><strong>즉, <code><code>World</code></code> 는 씬(Scene) 개념과 독립적이지만, <code>SubScene</code>과는 밀접한 관계를 가짐</strong></p>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2753.png" alt="❓" class="wp-smiley" style="height: 1em; max-height: 1em;" /> World는 SubScene을 포함하는 상위 컨테이너인가?</h3>



<p>Yes, 하지만 직접적인 포함 관계는 아님</p>



<p><strong><code><code>World</code></code></strong>는 <strong>ECS 데이터를 관리하는 컨테이너</strong>이므로, <strong><code><strong>SubScene</strong></code></strong>에서 생성된 ECS 데이터(<code><strong>Entity</strong></code>, <code><strong>Component</strong></code>, <code><strong>System </strong></code>등)는 <strong>결국 <strong><code><code>World</code></code></strong>에 포함됨</strong>.</p>



<p>하지만, <strong>Unity의 <strong><code><strong>SubScene</strong></code></strong>자체가 World의 일부는 아니다</strong>. (<strong><code><strong>SubScene</strong></code></strong>은 <strong><strong>씬(Scene)</strong>의 일부</strong>, World는 <strong>ECS의 컨테이너</strong>)</p>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2753.png" alt="❓" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 서로 다른 World에서 같은 SubScene을 공유할 수 있을까?</h3>



<p>일반적으로 Unity ECS에서는 <strong><strong><strong><code>SubScene</code></strong></strong>은 하나의 <strong><code><strong>World</strong></code></strong>에 속하는 것이 원칙</strong></p>



<p>특정한 방식으로 <strong>다른 <code><strong>World</strong></code>에서 동일한 <strong><code>SubScene</code></strong>을 공유하는 것</strong>도 가능할 수 있음</p>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/27a1.png" alt="➡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 서로 다른 World에서 같은 SubScene을 공유하는 방법</h4>



<h5 class="wp-block-heading">1. 각 World에서 같은 SubScene을 개별적으로 로드</h5>



<ul class="wp-block-list">
<li>각 <code><strong>World</strong></code>가 동일한 <strong><code>SubScene</code></strong>을 독립적으로 로드하여 각각의 ECS 데이터를 가질 수 있음</li>



<li>서로 다른 <code><strong>World</strong></code>에 있지만, 동일한 형태의 ECS 데이터가 생성</li>
</ul>



<h5 class="wp-block-heading">2. Persistent Scene을 활용해 한 World에서 로드한 데이터를 다른 World가 참조</h5>



<ul class="wp-block-list">
<li>한 <code><strong>World</strong></code>에서 <strong><code>SubScene</code></strong>을 로드하고, 다른 <code><strong>World</strong></code>는 해당 데이터를 복사하거나 참조하도록 설계</li>



<li>예를 들어, 멀티플레이어 게임에서 서버 <code><strong>World</strong></code>와 클라이언트 <code><strong>World</strong></code>가 동일한 맵 데이터(<strong><code>SubScene</code></strong>)를 참조하는 방식</li>



<li>하지만, Unity ECS가 기본적으로 제공하는 기능은 아니므로 별도의 데이터 동기화 로직이 필요함.</li>
</ul>



<h5 class="wp-block-heading">3. Bake 시점에 SubScene의 ECS 데이터를 여러 World로 복사</h5>



<ul class="wp-block-list">
<li><strong><code>SubScene</code></strong>이 변환될 때(<code><strong>Bake</strong></code>), ECS 데이터를 특정 World가 아니라 <strong>여러 <code><strong>World</strong></code>에 분산해서 배치하는 방식</strong>도 가능</li>



<li><code><strong>EntityManager.CopyEntitiesFrom()</strong></code> 등을 사용하여 <strong><strong><code>SubScene</code></strong>의 데이터를 한 <strong><code><code>World</code></code></strong>에서 다른 <strong><code><code>World</code></code></strong>로 복사 가능</strong>.</li>



<li>Unity ECS가 기본적으로 지원하는 기능이 아니므로, 수동으로 구현해야 할 수도 있음.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"/>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2753.png" alt="❓" class="wp-smiley" style="height: 1em; max-height: 1em;" />SubScene 내의 Entity들이 서로 다른 World에 포함될 수 있을까?</h3>



<p>Yes, 하지만 Unity ECS에서 기본적으로 지원하는 방식은 아님</p>



<p>특정한 방법을 사용하면 일부 <code><strong>Entity</strong></code>를 다른 <code><strong>World</strong></code>로 이동시키는 것은 가능함</p>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/27a1.png" alt="➡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 일반적인 SubScene의 World 포함 방식</h4>



<p>기본적으로 <strong><code>SubScene</code></strong>이 로드되면, 그 안의 모든 GameObject가 동일한 <code><strong>World</strong></code>로 변환(<strong><code>Bake</code></strong>)됨</p>



<p>즉, <strong>SubScene </strong>내의 모든 <code><strong>Entity</strong></code>들은 한 개의 <code><strong>World</strong></code>에 속하는 것이 원칙</p>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4cc.png" alt="📌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 예제: 일반적인 <strong><code>SubScene</code></strong> 로드 과정</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">SceneSystem.LoadSceneAsync(world, subSceneEntity, loadParameters);</pre>



<p>특정 <strong><code><strong>World</strong></code></strong>에서 <strong><code>SubScene</code></strong>을 로드함 → <strong><code>SubScene</code></strong> 내부의 <code><strong>Entity</strong></code>들이 해당 <code><strong>World</strong></code>에 포함됨</p>



<p>결과적으로 <strong><code>SubScene</code></strong>의 모든 <code><strong>Entity</strong></code>들은 동일한 <code><strong>World</strong></code>에 속하게 됨</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h4 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/27a1.png" alt="➡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 특정 Entity만 다른 World에 포함시키는 방법</h4>



<p>하지만, 특정한 방식으로 <strong><code>SubScene</code></strong> 내부의 <code><strong>Entity</strong></code>를 다른 World로 이동시키는 것도 가능</p>



<h5 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f539.png" alt="🔹" class="wp-smiley" style="height: 1em; max-height: 1em;" />방법 1: 특정 Entity를 다른 World로 복사하기</h5>



<p><strong><code>SubScene</code></strong>이 로드된 후, 특정 <code><strong>Entity</strong></code>를 <strong>다른 <code><strong>World</strong></code>로 복사</strong>하는 방식</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// 현재 World에서 Entity 가져오기
EntityManager entityManager = sourceWorld.EntityManager;
EntityQuery query = entityManager.CreateEntityQuery(ComponentType.ReadOnly&lt;MyComponent>());

// 대상 World로 Entity 복사
EntityManager destinationManager = targetWorld.EntityManager;
NativeArray&lt;Entity> entities = query.ToEntityArray(Allocator.Temp);
foreach (var entity in entities)
{
    Entity newEntity = destinationManager.Instantiate(entity);
}
entities.Dispose();
</pre>



<ul class="wp-block-list">
<li>원본 <code><strong>Entity</strong></code>를 삭제하지 않으면 동일한 <code><strong>Entity</strong></code>가 두 개의 <strong><code><strong>World</strong></code></strong>에 존재할 수도 있음! → 원본을 삭제할지 여부를 잘 결정해야 함</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h5 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f539.png" alt="🔹" class="wp-smiley" style="height: 1em; max-height: 1em;" />방법 2: SubScene을 특정 World에서 로드한 후 일부 Entity만 다른 World에서 활용</h5>



<ul class="wp-block-list">
<li><strong><code>SubScene</code></strong>을 <strong><code>World A</code>에서 로드</strong></li>



<li>특정 <code><strong>Entity</strong></code>를 <code><strong>World</strong></code><strong><code> B</code></strong>에서 참조할 수 있도록 설계</li>



<li><strong><code>EntityCommandBuffer</code> </strong>또는 <code><strong>CopyEntitiesFrom</strong></code>을 활용하여 데이터 이동 가능</li>
</ul>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">targetWorld.EntityManager.CopyEntitiesFrom(sourceWorld.EntityManager, query);
</pre>



<ul class="wp-block-list">
<li>하지만, 시스템(System)과 동작 방식이 달라질 수 있으므로 주의해야 함</li>
</ul>



<p></p>
<p>The post <a href="https://lycos7560.com/unity/ecs%ec%9d%98-world%ec%99%80-subscene%ec%9d%98-%ea%b4%80%ea%b3%84/39668/">ECS의 World와 SubScene의 관계</a> appeared first on <a href="https://lycos7560.com">어제와 내일의 나 그 사이의 이야기</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://lycos7560.com/unity/ecs%ec%9d%98-world%ec%99%80-subscene%ec%9d%98-%ea%b4%80%ea%b3%84/39668/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
