<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>I am fucking NOOB</title>
    <link>https://iamfuckingnoob.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sat, 4 Apr 2026 14:43:18 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>I am fucking NOOB</managingEditor>
    <item>
      <title>[유니티] 게임의 화면에 프레임 레이트를 출력해 보자!</title>
      <link>https://iamfuckingnoob.tistory.com/entry/%EC%9C%A0%EB%8B%88%ED%8B%B0-%EA%B2%8C%EC%9E%84%EC%9D%98-%ED%99%94%EB%A9%B4%EC%97%90-%ED%94%84%EB%A0%88%EC%9E%84-%EB%A0%88%EC%9D%B4%ED%8A%B8%EB%A5%BC-%EC%B6%9C%EB%A0%A5%ED%95%B4-%EB%B3%B4%EC%9E%90</link>
      <description>&lt;pre id=&quot;code_1725804797134&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using System.Collections;
using TMPro;
using UnityEngine;

// A Class for Indicating Current FPS(Frame Per Second).
public class ScreenFrameRateIndicator : MonoBehaviour
{
	#region Fields
	
	// [SerializeField] User Interfaces
	[SerializeField] private TextMeshProUGUI text; // Text Indicator of FPS
	
	// [SerializeField] Interval time to Update an Indicator
	[SerializeField, Range(0.01f, 1.0f)] private float updateInterval;

	// [Field] Enables/Disables the Indicator.
	private bool _isEnabled = false;
	
	#endregion Fields
	
	#region Methods
	
	// [Method] Start()
	private void Start()
	{
		// Check [SerializeField]s.
		CheckSerializationError();
		
		// Enables the Indicator.
		_isEnabled = true;
		
		// Starts a Coroutine to Update the Indicator.
		StartCoroutine(UpdateIndicator());
	}

	// [Method] Check if SerializeFields are Serialized.
	private void CheckSerializationError()
	{
		if (!text)
		{
			Debug.LogError(&quot;[TextMeshProUGUI] 'text' Component is not Serialized!&quot;);
		}
	}

	// [Coroutine] Updates the Indicator.
	private IEnumerator UpdateIndicator()
	{
		while (_isEnabled)
		{
			// Updates the Text of the Indicator.
			text.SetText($&quot;{(1.0f / Time.unscaledDeltaTime):F1} FPS&quot;);

			// Waits for a while.
			yield return new WaitForSecondsRealtime(updateInterval);
		}
	}
	
	#endregion Methods
}&lt;/code&gt;&lt;/pre&gt;</description>
      <author>I am fucking NOOB</author>
      <guid isPermaLink="true">https://iamfuckingnoob.tistory.com/44</guid>
      <comments>https://iamfuckingnoob.tistory.com/entry/%EC%9C%A0%EB%8B%88%ED%8B%B0-%EA%B2%8C%EC%9E%84%EC%9D%98-%ED%99%94%EB%A9%B4%EC%97%90-%ED%94%84%EB%A0%88%EC%9E%84-%EB%A0%88%EC%9D%B4%ED%8A%B8%EB%A5%BC-%EC%B6%9C%EB%A0%A5%ED%95%B4-%EB%B3%B4%EC%9E%90#entry44comment</comments>
      <pubDate>Sun, 8 Sep 2024 23:13:35 +0900</pubDate>
    </item>
    <item>
      <title>[유니티] 게임의 수직 동기화를 바꿔 보자!</title>
      <link>https://iamfuckingnoob.tistory.com/entry/%EC%9C%A0%EB%8B%88%ED%8B%B0-%EA%B2%8C%EC%9E%84%EC%9D%98-%EC%88%98%EC%A7%81-%EB%8F%99%EA%B8%B0%ED%99%94%EB%A5%BC-%EB%B0%94%EA%BF%94-%EB%B3%B4%EC%9E%90</link>
      <description>&lt;pre id=&quot;code_1725804758742&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using UnityEngine;
using UnityEngine.UI;

// A Class for Managing VSync Mode
public class VSyncModeManager : MonoBehaviour
{
	#region Fields

	// [SerializeField] User Interfaces
	[SerializeField] private Toggle toggle; // Toggle for VSync

	#endregion Fields

	#region Methods

	// [Method] Awake()
	private void Awake()
	{
		// Check [SerializeField]s.
		CheckSerializationError();
		
		InitializeToggle();
	}

	// [Method] Check if SerializeFields are Serialized.
	private void CheckSerializationError()
	{
		if (!toggle)
		{
			Debug.LogError(&quot;[Toggle] 'toggle' Component is not Serialized!&quot;);
		}
	}
	
	// [Method] Initializes the Default Value of Toggle.
	private void InitializeToggle()
	{
		// Gets if the VSync is Enabled.
		bool isVSyncMode = (QualitySettings.vSyncCount &amp;gt; 0);
		
		// Initializes the Default Value of Toggle.
		toggle.isOn = isVSyncMode;
	}
	
	// [Method] OnValueChanged() Event for Toggle.
	public void OnToggleValueChanged(bool value)
	{
		// Sets the VSync Enabled if true, else Disabled.
		QualitySettings.vSyncCount = (value) ? 1 : 0;
	}
	
	#endregion Methods
}&lt;/code&gt;&lt;/pre&gt;</description>
      <author>I am fucking NOOB</author>
      <guid isPermaLink="true">https://iamfuckingnoob.tistory.com/43</guid>
      <comments>https://iamfuckingnoob.tistory.com/entry/%EC%9C%A0%EB%8B%88%ED%8B%B0-%EA%B2%8C%EC%9E%84%EC%9D%98-%EC%88%98%EC%A7%81-%EB%8F%99%EA%B8%B0%ED%99%94%EB%A5%BC-%EB%B0%94%EA%BF%94-%EB%B3%B4%EC%9E%90#entry43comment</comments>
      <pubDate>Sun, 8 Sep 2024 23:12:47 +0900</pubDate>
    </item>
    <item>
      <title>[유니티] 게임을 창 화면 / 전체 화면으로 바꿔 보자!</title>
      <link>https://iamfuckingnoob.tistory.com/entry/%EC%9C%A0%EB%8B%88%ED%8B%B0-%EA%B2%8C%EC%9E%84%EC%9D%84-%EC%B0%BD-%ED%99%94%EB%A9%B4-%EC%A0%84%EC%B2%B4-%ED%99%94%EB%A9%B4%EC%9C%BC%EB%A1%9C-%EB%B0%94%EA%BF%94-%EB%B3%B4%EC%9E%90</link>
      <description>&lt;pre id=&quot;code_1725804717358&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using UnityEngine;
using UnityEngine.UI;

// A Class for Managing Full Screen Mode
public class FullScreenModeManager : MonoBehaviour
{
	#region Fields

	// [SerializeField] User Interfaces
	[SerializeField] private Toggle toggle; // Toggle for Full Screen

	#endregion Fields

	#region Methods

	// [Method] Awake()
	private void Awake()
	{
		// Check [SerializeField]s.
		CheckSerializationError();
		
		InitializeToggle();
	}
	
	// [Method] Check if SerializeFields are Serialized.
	private void CheckSerializationError()
	{
		if (!toggle)
		{
			Debug.LogError(&quot;[Toggle] 'toggle' Component is not Serialized!&quot;);
		}
	}
	
	// [Method] Initializes the Default Value of Toggle.
	private void InitializeToggle()
	{
		// Gets if the Screen is Full Screen Mode.
		bool isFullScreenMode = (Screen.fullScreenMode == FullScreenMode.FullScreenWindow);
		
		// Initializes the Default Value of Toggle.
		toggle.isOn = isFullScreenMode;
	}
	
	// [Method] OnValueChanged() Event for Toggle.
	public void OnToggleValueChanged(bool value)
	{
		// Sets the Screen to Full if true, else Window.
		Screen.fullScreenMode = (value) ? FullScreenMode.FullScreenWindow : FullScreenMode.Windowed;
	}
	
	#endregion Methods
}&lt;/code&gt;&lt;/pre&gt;</description>
      <author>I am fucking NOOB</author>
      <guid isPermaLink="true">https://iamfuckingnoob.tistory.com/42</guid>
      <comments>https://iamfuckingnoob.tistory.com/entry/%EC%9C%A0%EB%8B%88%ED%8B%B0-%EA%B2%8C%EC%9E%84%EC%9D%84-%EC%B0%BD-%ED%99%94%EB%A9%B4-%EC%A0%84%EC%B2%B4-%ED%99%94%EB%A9%B4%EC%9C%BC%EB%A1%9C-%EB%B0%94%EA%BF%94-%EB%B3%B4%EC%9E%90#entry42comment</comments>
      <pubDate>Sun, 8 Sep 2024 23:12:00 +0900</pubDate>
    </item>
    <item>
      <title>[유니티] 게임의 프레임 레이트를 바꿔 보자!</title>
      <link>https://iamfuckingnoob.tistory.com/entry/%EC%9C%A0%EB%8B%88%ED%8B%B0-%EA%B2%8C%EC%9E%84%EC%9D%98-%ED%94%84%EB%A0%88%EC%9E%84-%EB%A0%88%EC%9D%B4%ED%8A%B8%EB%A5%BC-%EB%B0%94%EA%BF%94-%EB%B3%B4%EC%9E%90</link>
      <description>&lt;pre id=&quot;code_1725804650091&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using System;
using System.Collections.Generic;
using System.Linq;
using TMPro;
using UnityEngine;

// A Class for Managing Frame Rate of Screen
public class ScreenFrameRateManager : MonoBehaviour
{
	#region Fields

	// [SerializeField] User Interfaces
	[SerializeField] private TMP_Dropdown dropdown; // Dropdown for Refresh Rates(Hz)

	// [Field] List of Supported Refresh Rates
	private int[] _supportedRefreshRates = default;

	#endregion Fields

	#region Methods

	// [Method] Awake()
	private void Awake()
	{
		// Check [SerializeField]s.
		CheckSerializationError();
		
		GetSupportedRefreshRates();
		AddOptionsToDropdown();
	}
	
	// [Method] Check if SerializeFields are Serialized.
	private void CheckSerializationError()
	{
		if (!dropdown)
		{
			Debug.LogError(&quot;[Dropdown] 'dropdown' Component is not Serialized!&quot;);
		}
	}

	// [Method] Gets All Resolutions that the Monitor Supports.
	private void GetSupportedRefreshRates()
	{
		// Gets All Full-Screen Resolutions that the Monitor Supports.
		Resolution[] supported = Screen.resolutions;

		// Filters by Refresh Rate (Hz)
		_supportedRefreshRates = supported
			.Select(resolution =&amp;gt; (int)Math.Round(resolution.refreshRateRatio.value))
			.Distinct()
			.OrderBy(refreshRate =&amp;gt; refreshRate)
			.ToArray();
	}

	// [Method] Add Options of Refresh Rate to a Dropdown.
	private void AddOptionsToDropdown()
	{
		// Clears All Options of the Dropdown.
		dropdown.ClearOptions();

		// Creates a List of OptionData, Adds All Resolutions to the List.
		List&amp;lt;TMP_Dropdown.OptionData&amp;gt; options = _supportedRefreshRates
			.Select(refreshRate =&amp;gt; new TMP_Dropdown.OptionData { text = $&quot;{refreshRate}Hz&quot; })
			.ToList();

		// Add the List to the Dropdown.
		dropdown.AddOptions(options);
		
		// Initialize the Default Value of Dropdown.
		InitializeDropdown();
	}
	
	// [Method] Initializes the Value of Dropdown.
	private void InitializeDropdown()
	{
		// Get the Current Frame Rate of Screen.
		int currentFrameRate = Application.targetFrameRate;

		// Get an Index with the Current Frame Rate.
		int currentValue = Array.FindIndex(_supportedRefreshRates, refreshRate =&amp;gt; refreshRate == currentFrameRate);

		// Initialize the Default Value of Dropdown.
		dropdown.value = currentValue;
	}

	// [Method] OnValueChanged() Event for Dropdown.
	public void OnDropdownValueChanged(int value)
	{
		// Gets Refresh Rate Values of Selected Option from Refresh Rate List.
		int refreshRate = _supportedRefreshRates[value];

		// Sets the Frame Rate with the Selected Option.
		Application.targetFrameRate = refreshRate;
	}

	#endregion Methods
}&lt;/code&gt;&lt;/pre&gt;</description>
      <author>I am fucking NOOB</author>
      <guid isPermaLink="true">https://iamfuckingnoob.tistory.com/41</guid>
      <comments>https://iamfuckingnoob.tistory.com/entry/%EC%9C%A0%EB%8B%88%ED%8B%B0-%EA%B2%8C%EC%9E%84%EC%9D%98-%ED%94%84%EB%A0%88%EC%9E%84-%EB%A0%88%EC%9D%B4%ED%8A%B8%EB%A5%BC-%EB%B0%94%EA%BF%94-%EB%B3%B4%EC%9E%90#entry41comment</comments>
      <pubDate>Sun, 8 Sep 2024 23:11:04 +0900</pubDate>
    </item>
    <item>
      <title>[유니티] 게임의 해상도를 바꿔 보자!</title>
      <link>https://iamfuckingnoob.tistory.com/entry/%EC%9C%A0%EB%8B%88%ED%8B%B0-%EA%B2%8C%EC%9E%84%EC%9D%98-%ED%95%B4%EC%83%81%EB%8F%84%EB%A5%BC-%EB%B0%94%EA%BF%94-%EB%B3%B4%EC%9E%90</link>
      <description>&lt;pre id=&quot;code_1725804373536&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using System;
using System.Collections.Generic;
using System.Linq;
using TMPro;
using UnityEngine;

// A Class for Managing Resolution of Screen
public class ScreenResolutionManager : MonoBehaviour
{
	#region Fields

	// [SerializeField] User Interfaces
	[SerializeField] private TMP_Dropdown dropdown; // Dropdown for Resolutions(Width, Height)

	// [Field] List of Supported Resolutions
	private Vector2Int[] _supportedResolutions = default; // Width, Height

	#endregion Fields

	#region Methods

	// [Method] Awake()
	private void Awake()
	{
		// Check [SerializeField]s.
		CheckSerializationError();
		
		GetSupportedResolutions();
		AddOptionsToDropdown();
	}
	
	// [Method] Check if SerializeFields are Serialized.
	private void CheckSerializationError()
	{
		if (!dropdown)
		{
			Debug.LogError(&quot;[Dropdown] 'dropdown' Component is not Serialized!&quot;);
		}
	}

	// [Method] Gets All Resolutions that the Monitor Supports.
	private void GetSupportedResolutions()
	{
		// Gets All Full-Screen Resolutions that the Monitor Supports.
		Resolution[] supported = Screen.resolutions;

		// Filters by Resolution (Width &amp;times; Height)
		_supportedResolutions = supported
			.Select(resolution =&amp;gt; new Vector2Int(resolution.width, resolution.height))
			.Distinct()
			.OrderBy(size =&amp;gt; size.x)
			.ToArray();
	}

	// [Method] Add Options of Resolution to a Dropdown.
	private void AddOptionsToDropdown()
	{
		// Clears All Options of the Dropdown.
		dropdown.ClearOptions();

		// Creates a List of OptionData, Adds All Resolutions to the List.
		List&amp;lt;TMP_Dropdown.OptionData&amp;gt; options = _supportedResolutions
			.Select(resolution =&amp;gt; new TMP_Dropdown.OptionData { text = $&quot;{resolution.x} &amp;times; {resolution.y}&quot; })
			.ToList();

		// Add the List to the Dropdown.
		dropdown.AddOptions(options);

		// Initialize the Default Value of Dropdown.
		InitializeDropdown();
	}

	// [Method] Initializes the Default Value of Dropdown.
	private void InitializeDropdown()
	{
		// Get the Current Resolution of Screen.
		var currentResolution = new Vector2Int(Screen.width, Screen.height);

		// Get an Index with the Current Resolution.
		int currentValue = Array.FindIndex(_supportedResolutions, resolution =&amp;gt; resolution == currentResolution);

		// Initialize the Default Value of Dropdown.
		dropdown.value = currentValue;
	}

	// [Method] OnValueChanged() Method for Dropdown.
	public void OnDropdownValueChanged(int value)
	{
		// Gets Width/Height Values of Selected Option from Resolution List.
		int screenWidth = _supportedResolutions[value].x;
		int screenHeight = _supportedResolutions[value].y;

		// Sets the Resolution with the Selected Option.
		Screen.SetResolution(screenWidth, screenHeight, fullscreenMode: Screen.fullScreenMode);
	}

	#endregion Methods
}&lt;/code&gt;&lt;/pre&gt;</description>
      <author>I am fucking NOOB</author>
      <guid isPermaLink="true">https://iamfuckingnoob.tistory.com/40</guid>
      <comments>https://iamfuckingnoob.tistory.com/entry/%EC%9C%A0%EB%8B%88%ED%8B%B0-%EA%B2%8C%EC%9E%84%EC%9D%98-%ED%95%B4%EC%83%81%EB%8F%84%EB%A5%BC-%EB%B0%94%EA%BF%94-%EB%B3%B4%EC%9E%90#entry40comment</comments>
      <pubDate>Sun, 8 Sep 2024 23:09:52 +0900</pubDate>
    </item>
    <item>
      <title>유니티에서 MVVM 써보기</title>
      <link>https://iamfuckingnoob.tistory.com/entry/%EC%9C%A0%EB%8B%88%ED%8B%B0%EC%97%90%EC%84%9C-MVVM-%EC%8D%A8%EB%B3%B4%EA%B8%B0</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;1. 모델(Model)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;뷰(View)가 참조할 데이터를 관리하는 역할을 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;뷰와 뷰 모델(View Model)의 그 어느 쪽의 참조도 가지지 않는다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;순수한 데이터와, 그 데이터를 변경할 수 있는 함수(비지니스 로직)를 가진다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;INotifyPropertyChanged 인터페이스 (PropertyChangedEventHandler 이벤트)를 상속받는다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;데이터(프로퍼티)가 변경될 때, 이 이벤트를 호출하여 뷰 모델(View Model)에게 그 사실을 알린다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1725002630001&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using System.Collections.Generic;
using System.ComponentModel;
using UnityEngine;

public class PlayerModel : INotifyPropertyChanged // Defines the data of Player.
{
	// Model doesn't have any instances or references of View &amp;amp; View Model.
	
	#region [Fields]
	
	// [Field] Data of Player
	private readonly int _maxHealthPoint; // Max HP
	private readonly int _maxSkillPoint; // Max SP
	
	private int _currentHealthPoint; // HP
	private int _currentSkillPoint; // SP
	
	public int CurrentHealthPoint // HP Property
	{
		get =&amp;gt; _currentHealthPoint;
		set =&amp;gt; SetField(ref _currentHealthPoint, value, nameof(CurrentHealthPoint));
	}
	
	public int CurrentSkillPoint // SP Property
	{
		get =&amp;gt; _currentSkillPoint;
		set =&amp;gt; SetField(ref _currentSkillPoint, value, nameof(CurrentSkillPoint));
	}

	// [Event] Property Changed Event; will invoke when the data changes.
	public event PropertyChangedEventHandler PropertyChanged;

	#endregion [Fields]
	
	#region [Methods]

	// [Constructor] Sets values of HP &amp;amp; SP.
	public PlayerModel(int maxHealthPoint, int maxSkillPoint)
	{
		CurrentHealthPoint = _maxHealthPoint = maxHealthPoint;
		CurrentSkillPoint = _maxSkillPoint = maxSkillPoint;
	}
	
	// [Method] Invokes Property Changed Event.
	private void InvokePropertyChanged(string propertyName)
	{
		PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
	}
	
	// [Method] Sets values of a property with invoking Property Changed Event.
	private void SetField&amp;lt;T&amp;gt;(ref T field, T value, string propertyName)
	{
		// Invokes the event only when the value is changed.
		if (!EqualityComparer&amp;lt;T&amp;gt;.Default.Equals(field, value))
		{
			field = value; // Changes the value of the property.
			InvokePropertyChanged(propertyName); // Invokes the event.
		}
	}
	
	#endregion [Methods]
	
	#region [Method] Controls Fields.
	
	// [Method] Heals HP.
	public void HealHealthPoint(int amount)
	{
		CurrentHealthPoint = Mathf.Min(CurrentHealthPoint + amount, _maxHealthPoint);
	}
	
	// [Method] Damages HP.
	public void DamageHealthPoint(int amount)
	{
		CurrentHealthPoint = Mathf.Max(0, CurrentHealthPoint - amount);
	}
	
	// [Method] Heals SP.
	public void HealSkillPoint(int amount)
	{
		CurrentSkillPoint = Mathf.Min(CurrentSkillPoint + amount, _maxSkillPoint);
	}
	
	// [Method] Damages SP.
	public void DamageSkillPoint(int amount)
	{
		CurrentSkillPoint = Mathf.Max(0, CurrentSkillPoint - amount);
	}
	
	#endregion [Method] Controls Fields.
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;2. 뷰 모델(View Model)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;뷰(View)와 모델(Model)을 연결하는 중개자의 역할을 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;모델의 참조만을 가지고, 뷰의 참조를 가지지 않는다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;아래의 예시에서는, 모델의 참조를 새롭게 생성하지 않기 위해 싱글톤으로 구현한 클래스에서 모델을 관리하고, 그것을 참조하도록 하고 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;모델이 가지고 있는 데이터를 바인딩한다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;아래의 예시에서는, &lt;b&gt;&lt;i&gt;#region [Properties / Methods] Binds data from Model&lt;/i&gt;&lt;/b&gt; 영역이 이에 해당한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;INotifyPropertyChanged 인터페이스(PropertyChangedEventHandler 이벤트)를 상속받는다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;모델의 데이터(프로퍼티)가 변경될 때, 이 이벤트가 호출되어 뷰에게 이 사실을 알린다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;뷰 모델로부터 모델의 참조나 변경에 대한 요청을 받아 처리한다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;아래의 예시에서는, &lt;i&gt;&lt;b&gt;Heal(), Damage()&lt;/b&gt;&lt;/i&gt; 등의 함수가 이에 해당한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;모델의 프로퍼티 변경 이벤트에 등록하여, 이벤트가 발생할 경우 바인딩한 프로퍼티를 동기화한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1725002671729&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using System.ComponentModel;

public class PlayerViewModel : INotifyPropertyChanged // Binds PlayerView to PlayerModel.
{
	#region [Fields]
	
	// View Model has an instance or a reference of Model.
	private PlayerModel _model;

	// [Event] Property Changed Event; will invoke when data of Model changes.
	public event PropertyChangedEventHandler PropertyChanged;

	#endregion [Fields]
	
	#region [Methods]

	// [Constructor] Initializes values of the Model's data.
	public PlayerViewModel()
	{
		_model = GameManager.Instance.PlayerModel; // Gets the reference of Model from GameManager.
		_model.PropertyChanged += OnPropertyChanged; // Adds listeners to Property Changed Event.
	}
	
	// [Method] Invokes Property Changed Event.
	private void InvokePropertyChanged(string propertyName)
	{
		PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
	}
	
	// [Method] Callback of Model's Property Changed Event
	private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
	{
		BindModelProperty(e.PropertyName); // Binds Properties of Model with View Model.
	}
	
	// [Method] Binds Properties of Model with View Model.
	private void BindModelProperty(string propertyName)
	{
		switch (propertyName)
		{
			case nameof(_model.CurrentHealthPoint):
				HealthPoint = _model.CurrentHealthPoint;
				break;
			case nameof(_model.CurrentSkillPoint):
				SkillPoint = _model.CurrentSkillPoint;
				break;
		}
	}
	
	// [Method] Removes listeners of Model's Property Changed Event.
	public void RemoveListeners()
	{
		_model.PropertyChanged -= OnPropertyChanged;
	}
	
	#endregion [Methods]

	#region [Properties / Methods] Binds data from Model.
	
	// [Property] HP
	public int HealthPoint
	{
		get =&amp;gt; _model.CurrentHealthPoint;
		private set =&amp;gt; InvokePropertyChanged(nameof(HealthPoint));
	}
	
	// [Property] SP
	public int SkillPoint
	{
		get =&amp;gt; _model.CurrentSkillPoint;
		private set =&amp;gt; InvokePropertyChanged(nameof(SkillPoint));
	}
	
	// [Method] Heals HP.
	public void HealHealthPoint(int amount)
	{
		_model.HealHealthPoint(amount);
	}
	
	// [Method] Damages HP.
	public void DamageHealthPoint(int amount)
	{
		_model.DamageHealthPoint(amount);
	}
	
	// [Method] Heals SP.
	public void HealSkillPoint(int amount)
	{
		_model.HealSkillPoint(amount);
	}
	
	// [Method] Damages SP.
	public void DamageSkillPoint(int amount)
	{
		_model.DamageSkillPoint(amount);
	}
	
	#endregion [Properties / Methods] Binds data from Model.
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;3. 뷰(View)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;사용자로부터 입력 등의 상호작용을 통해 모델 뷰에게 모델의 변경을 요청하고, 그에 따라 UI를 갱신하는 등의 작업을 수행하는 역할을 한다.&lt;/span&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;단, 아래의 예시는 뷰가 뷰 모델에게 모델의 변경을 요청하는 역할은 없다. 순수하게 UI를 갱신하는 역할만 한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;뷰 모델(View Model)만의 참조를 가지고, 모델(Model)의 참조를 가지지 않는다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;뷰 모델의 프로퍼티 변경 이벤트에 등록하여, 이벤트가 발생할 경우 등록한 작업을 수행한다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;아래의 예시에서는, 변경된 프로퍼티의 값을 UI 요소들에 갱신하여 출력한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1725002692201&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using System.ComponentModel;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

// ※ This View has actions only for updating UIs, not requesting for modifying Model.
public class PlayerView : MonoBehaviour // Prints the data of Player on UI.
{
	// View has an instance of View Model.
	private PlayerViewModel _viewModel;
	
	// [SerializeField] UI Elements
	[SerializeField] private TextMeshProUGUI text_healthPoint;
	[SerializeField] private TextMeshProUGUI text_skillPoint;
	[SerializeField] private Slider slider_healthPoint;
	[SerializeField] private Slider slider_skillPoint;

	// [Method] OnEnable()
	private void OnEnable()
	{
		if (_viewModel == null)
		{
			_viewModel = new PlayerViewModel(); // Creates a View Model.
			_viewModel.PropertyChanged += OnPropertyChanged; // Adds listeners to Property Changed Event.
		}
	}
	
	// [Method] OnDisable()
	private void OnDisable()
	{
		if (_viewModel != null)
		{
			_viewModel.RemoveListeners(); // Removes listeners of View Model.
			_viewModel.PropertyChanged -= OnPropertyChanged; // Removes listeners from Property Changed Event.
			_viewModel = null; // Removes the View Model.
		}
	}

	// [Method] Callback of View Model's Property Changed Event
	private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
	{
		UpdateUI(e.PropertyName); // Updates UIs related to a property.
	}

	// [Method] Updates UIs related to a property.
	private void UpdateUI(string propertyName)
	{
		switch (propertyName)
		{
			case nameof(_viewModel.HealthPoint):
				text_healthPoint.text = $&quot;{_viewModel.HealthPoint}&quot;;
				slider_healthPoint.value = _viewModel.HealthPoint;
				break;
			case nameof(_viewModel.SkillPoint):
				text_skillPoint.text = $&quot;{_viewModel.SkillPoint}&quot;;
				slider_skillPoint.value = _viewModel.SkillPoint;
				break;
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;EX. 컨트롤러&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;플레이어가 특정 이벤트를 겪을 때 모델을 변경하는 역할을 한다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;컨트롤러는 모델에 대한 참조를 가진다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;아래의 예시에서는, 모델의 참조는 위의 뷰 모델이 참조한 모델과 같이, 싱글톤의 모델을 참조하여 같은 모델을 사용하도록 보장한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;또한, 적에게 피격했을 때 모델의 데이터 중 체력을 감소시키는 함수를 호출한다.&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1725004582961&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class PlayerController : MonoBehaviour // Controls the Player.
{
	// Controller has a reference of Model.
	private PlayerModel _model;
	
	// [Method] Awake()
	private void Awake()
	{
		// [Temp] Supposes that there is a DataManger, which has data of Player.
		_model = DataManager.Instance.GetPlayerData(&quot;PlayerName&quot;); // Gets the correct Model from DataManager.
		GameManager.Instance.PlayerModel = _model; // Set the reference of Model of GameManager.
	}
	
	// [Method] OnTriggerEnter()
	private void OnTriggerEnter(Collision other)
	{
		// [Temp] Supposes that there is a Enemy component, which has an ATK field, etcs.
		if (other.gameObject.TryGetComponent&amp;lt;Enemy&amp;gt;(out Enemy attacker))
		{
			int damage = attacker.GetATK(); // Gets the value of ATK from Enemy.
			_model.DamageHealthPoint(damage); // Changes values of Model.
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;생각해 볼 점&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;모델과 모델 뷰에 중복(복제)되는 코드가 많아서, 이것을 하나로 통합해도 되지 않을까?&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;물론 같은 모델을 쓰되 사용하는 방식에 차이가 있다면 나누는 것이 더 좋을 수도 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;모델의 수정을 컨트롤러가 따로 하는 이유는 충돌 이벤트 등의 함수를 뷰가 호출하는 것이 (특히 의미적으로) 적절하지 않다고 보기 때문이다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;뷰는 버튼의 클릭 등의 입력이 발생할 때 모델의 변경을 요청하는 것인데, 충돌 이벤트는 인게임에서 수동적으로 발생하므로 뷰가 의도적으로 호출하는 것이 적절하지 않아 보인다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;컨트롤러가 뷰의 참조를 가져서 변경을 요청하는 방법을 고려해 볼 수도 있어 보인다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;하지만 컨트롤러가 뷰의 참조를 가지는 것도 그것대로 이상한 구조가 되지 않을까 싶다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;하여튼 겁나 어렵다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>I am fucking NOOB</author>
      <guid isPermaLink="true">https://iamfuckingnoob.tistory.com/39</guid>
      <comments>https://iamfuckingnoob.tistory.com/entry/%EC%9C%A0%EB%8B%88%ED%8B%B0%EC%97%90%EC%84%9C-MVVM-%EC%8D%A8%EB%B3%B4%EA%B8%B0#entry39comment</comments>
      <pubDate>Thu, 29 Aug 2024 18:59:44 +0900</pubDate>
    </item>
    <item>
      <title>【유니티】 C# 스크립트 명명 규칙</title>
      <link>https://iamfuckingnoob.tistory.com/entry/%E3%80%90%EC%9C%A0%EB%8B%88%ED%8B%B0%E3%80%91-C-%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%AA%85%EB%AA%85-%EA%B7%9C%EC%B9%99</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 JetBrains Rider 기준.&lt;/p&gt;
&lt;pre id=&quot;code_1724832964440&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using UnityEngine;

public class UnityClass : MonoBehaviour
{
	// 1. Field: Variables which are declared at class scope.
	public int PascalField; // public field uses 'PascalCase': Every words start with Upper case.
	private int _camelField; // private field uses '_camelCase': First word start with _lower case, others start with Upper case.
	[SerializeField] private int camelField; // [SerializeField] private field uses 'camelCase': First word start with lower case, others start with Upper case.
	
	// 2. Constant: Fields whose value is set at compile time and cannot be changed.
	private int PascalConstant; // Constant field uses 'PascalCase'.
	
	// 2. Property: Methods on a class that are accessed as if they were fields on that class.
	public int PascalProperty { get; set; } // Property uses 'PascalCase'.
	
	// 3. Method: Defines the actions that a class can perform.
	public void PascalMethod() { } // Method uses 'PascalCase'.
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C#의 공식 문서 기준: &lt;a href=&quot;https://learn.microsoft.com/ko-kr/dotnet/csharp/fundamentals/coding-style/coding-conventions&quot;&gt;.NET 코딩 규칙 - C# | Microsoft Learn&lt;/a&gt;&lt;/p&gt;</description>
      <author>I am fucking NOOB</author>
      <guid isPermaLink="true">https://iamfuckingnoob.tistory.com/38</guid>
      <comments>https://iamfuckingnoob.tistory.com/entry/%E3%80%90%EC%9C%A0%EB%8B%88%ED%8B%B0%E3%80%91-C-%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%AA%85%EB%AA%85-%EA%B7%9C%EC%B9%99#entry38comment</comments>
      <pubDate>Wed, 28 Aug 2024 17:17:27 +0900</pubDate>
    </item>
    <item>
      <title>【유니티】 오브젝트 풀링(Object Pooling)</title>
      <link>https://iamfuckingnoob.tistory.com/entry/%E3%80%90%EC%9C%A0%EB%8B%88%ED%8B%B0%E3%80%91-%EC%98%A4%EB%B8%8C%EC%A0%9D%ED%8A%B8-%ED%92%80%EB%A7%81Object-Pooling</link>
      <description>&lt;pre id=&quot;code_1724735662346&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using System;
using UnityEngine;
using UnityEngine.Pool;

namespace Frameworks.ObjectPool
{
	// [인터페이스] 오브젝트 풀링에 사용할 아이템이 특정 함수를 구현하도록 제약합니다.
	internal interface IObjectPoolItem&amp;lt;T&amp;gt; where T : MonoBehaviour
	{
		// [함수] 오브젝트 풀링 매니저의 참조를 저장합니다.
		internal void GetPool(IObjectPool&amp;lt;T&amp;gt; pool);
	}

	// [일반화 클래스] 오브젝트 풀링을 관리합니다.
	internal class ObjectPoolManager&amp;lt;T&amp;gt; : MonoBehaviour where T : MonoBehaviour, IObjectPoolItem&amp;lt;T&amp;gt;
	{
		[SerializeField] private T poolPrefab; // [변수] 오브젝트 풀링에 사용할 아이템의 프리팹
		private IObjectPool&amp;lt;T&amp;gt; _pool; // [변수] 오브젝트 풀링 인터페이스 (UnityEngine.Pool)

		// [변수] IObjectPool&amp;lt;T&amp;gt;의 매개변수들
		[SerializeField] private bool collectionCheck; 
		[SerializeField] private int defaultCapacity; // 기본 용량으로, 처음에 미리 생성해 둘 아이템의 개수를 설정합니다.
		[SerializeField] private int maxSize; // 최대 용량으로, 생성한 아이템의 개수가 최대 용량을 초과하면, 초과량은 반환(Release)할 때 대신 파괴(Destroy)됩니다.

		// [유니티 생명 주기 함수] Awake()
		private void Awake()
		{
			CheckPrefabValidation(); // 프리팹의 유효성(등록 여부)을 검사합니다.
			InitPool(); // 오브젝트 풀을 초기화합니다.
		}

		// [함수] 프리팹의 유효성(등록 여부)을 검사합니다.
		private void CheckPrefabValidation()
		{
			if (!poolPrefab) // 프리팹이 등록되어 있지 않으면,
			{
				Debug.LogError(&quot;프리팹을 등록하지 않았습니다!&quot;); // 오류 로그를 출력합니다.
			}
		}

		// [함수] 오브젝트 풀을 초기화합니다.
		private void InitPool()
		{
			_pool = new ObjectPool&amp;lt;T&amp;gt;(
				createFunc: CreateItem, actionOnGet: OnGetItem,
				actionOnRelease: OnReleaseItem, actionOnDestroy: OnDestroyItem,
				collectionCheck: collectionCheck, defaultCapacity: defaultCapacity, maxSize: maxSize);
		}

		// [함수] 오브젝트 풀에 새 아이템을 생성합니다.
		private T CreateItem()
		{
			T newItem = Instantiate(poolPrefab); // 프리팹을 생성합니다.
			newItem.GetPool(_pool); // 아이템이 매니저가 가진 풀을 참조하도록 합니다.
			return newItem;
		}

		// [함수] 오브젝트 풀에서 아이템을 가져옵니다.
		private void OnGetItem(T item)
		{
			item.gameObject.SetActive(true); // 아이템을 활성화합니다.
		}

		// [함수] 오브젝트 풀에 아이템을 돌려놓습니다.
		private void OnReleaseItem(T item)
		{
			item.gameObject.SetActive(false); // 아이템을 비활성화합니다.
		}

		// [함수] 오브젝트 풀에 아이템을 돌려놓지 않고, 파괴합니다.
		private void OnDestroyItem(T item)
		{
			Destroy(item.gameObject); // 아이템을 파괴합니다.
		}
	}

	// [클래스] 오브젝트 풀링에 사용할 아이템을 정의합니다.
	internal class ObjectPoolItem : MonoBehaviour, IObjectPoolItem&amp;lt;ObjectPoolItem&amp;gt;
	{
		// [변수] 오브젝트 풀의 참조
		private IObjectPool&amp;lt;ObjectPoolItem&amp;gt; _pool;

		// [함수] 오브젝트 풀의 참조를 저장합니다. 오브젝트 풀링 매니저에서 호출합니다.
		void IObjectPoolItem&amp;lt;ObjectPoolItem&amp;gt;.GetPool(IObjectPool&amp;lt;ObjectPoolItem&amp;gt; pool)
		{
			_pool = pool;
		}

		// [함수] 테스트; 아이템을 풀에 돌려놓습니다.
		private void Test()
		{
			_pool.Release(this);
		}
	}
}&lt;/code&gt;&lt;/pre&gt;</description>
      <author>I am fucking NOOB</author>
      <guid isPermaLink="true">https://iamfuckingnoob.tistory.com/37</guid>
      <comments>https://iamfuckingnoob.tistory.com/entry/%E3%80%90%EC%9C%A0%EB%8B%88%ED%8B%B0%E3%80%91-%EC%98%A4%EB%B8%8C%EC%A0%9D%ED%8A%B8-%ED%92%80%EB%A7%81Object-Pooling#entry37comment</comments>
      <pubDate>Tue, 27 Aug 2024 14:05:32 +0900</pubDate>
    </item>
    <item>
      <title>【유니티】 스위치 문, 스위치 식</title>
      <link>https://iamfuckingnoob.tistory.com/entry/%E3%80%90%EC%9C%A0%EB%8B%88%ED%8B%B0%E3%80%91-%EC%8A%A4%EC%9C%84%EC%B9%98-%EB%AC%B8-%EC%8A%A4%EC%9C%84%EC%B9%98-%EC%8B%9D</link>
      <description>&lt;pre id=&quot;code_1724399672171&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;namespace SwitchPractice
{
	public class SwitchClass : MonoBehaviour
	{
		private int switchInt;
		
		// 스위치 문(Switch Statement)
		private int SwitchStatement()
		{
			int returnInt;
			
			switch (switchInt)
			{
				case 0:
					returnInt = 0;
					break; // break를 사용할 경우
					// return 0; // return을 사용할 경우
				case 1:
					returnInt = 2;
					break;
				default:
					returnInt = -1;
					break;
			}
			
			return returnInt;
		}
		
		// 스위치 식(Switch Expression)
		private int SwitchExpression() =&amp;gt; switchInt switch
		{
			0 =&amp;gt; 0,
			1 =&amp;gt; 2,
			_ =&amp;gt; -1,
		}
	}
}&lt;/code&gt;&lt;/pre&gt;</description>
      <author>I am fucking NOOB</author>
      <guid isPermaLink="true">https://iamfuckingnoob.tistory.com/36</guid>
      <comments>https://iamfuckingnoob.tistory.com/entry/%E3%80%90%EC%9C%A0%EB%8B%88%ED%8B%B0%E3%80%91-%EC%8A%A4%EC%9C%84%EC%B9%98-%EB%AC%B8-%EC%8A%A4%EC%9C%84%EC%B9%98-%EC%8B%9D#entry36comment</comments>
      <pubDate>Mon, 26 Aug 2024 13:50:40 +0900</pubDate>
    </item>
    <item>
      <title>【유니티】 싱글톤(Singleton)</title>
      <link>https://iamfuckingnoob.tistory.com/entry/%E3%80%90%EC%9C%A0%EB%8B%88%ED%8B%B0%E3%80%91-%EC%8B%B1%EA%B8%80%ED%86%A4Singleton</link>
      <description>&lt;pre id=&quot;code_1724399672171&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using System;
using UnityEngine;

namespace Framework.Singleton
{
    /// &amp;lt;summary&amp;gt;
    /// 싱글톤(Singleton) 일반화 클래스
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;typeparam name=&quot;T&quot;&amp;gt;상속받는 클래스&amp;lt;/typeparam&amp;gt;
    public class Singleton&amp;lt;T&amp;gt; where T : new()
    {
        // Lazy&amp;lt;T&amp;gt;를 사용하여 스레드로부터 안전한, 게으른 생성을 사용한다.
        private static readonly Lazy&amp;lt;T&amp;gt; _instance = new(new T());
        public static T Instance =&amp;gt; _instance.Value;

        // 생성자를 private/protected으로 제한하여 생성자를 통한 객체의 생성을 막는다.
        protected Singleton() { }
    }

    /// &amp;lt;summary&amp;gt;
    /// MonoBehaviour를 상속받는 싱글톤 일반화 클래스
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;typeparam name=&quot;T&quot;&amp;gt;상속받는 클래스&amp;lt;/typeparam&amp;gt;
    public class SingletonMonoBehaviour&amp;lt;T&amp;gt; : MonoBehaviour where T : MonoBehaviour
    {
        // MonoBehaviour의 특징으로, 생성자를 사용하지 않는 등의 제약이 있다.
        private static readonly Lazy&amp;lt;T&amp;gt; _instance = new(CreateInstance);
        public static T Instance =&amp;gt; _instance.Value;
        
        // Lazy&amp;lt;T&amp;gt;가 인스턴스를 생성할 때 호출하는 함수
        private static T CreateInstance()
        {
            T instance = FindAnyObjectByType&amp;lt;T&amp;gt;(); // 인스턴스가 존재하지 않을 경우, Find 함수로 씬 내에서 해당 컴포넌트가 부착된 게임 오브젝트를 찾는다.
            instance ??= new GameObject(nameof(T)).AddComponent&amp;lt;T&amp;gt;(); // 여전히 존재하지 않을 경우, 새 게임 오브젝트를 생성하고, 해당 컴포넌트를 부착한다.
            DontDestroyOnLoad(instance); // DontDestroyOnLoad()를 적용한다.
            return instance;
        }

        // Awake()
        protected virtual void Awake()
        {
            // 인스턴스가 이미 생성되었으나, 현재 객체가 그 인스턴스가 아닐 경우, 이 게임 오브젝트를 파괴한다.
            if (_instance.IsValueCreated &amp;amp;&amp;amp; _instance.Value != this)
                Destroy(gameObject);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <author>I am fucking NOOB</author>
      <guid isPermaLink="true">https://iamfuckingnoob.tistory.com/35</guid>
      <comments>https://iamfuckingnoob.tistory.com/entry/%E3%80%90%EC%9C%A0%EB%8B%88%ED%8B%B0%E3%80%91-%EC%8B%B1%EA%B8%80%ED%86%A4Singleton#entry35comment</comments>
      <pubDate>Fri, 23 Aug 2024 16:54:56 +0900</pubDate>
    </item>
  </channel>
</rss>