์ธํ”„๋Ÿฐ ๊ฐ•์˜ - Part3: ์œ ๋‹ˆํ‹ฐ ์—”์ง„ ๋‚ด์šฉ ์ •๋ฆฌ (์„น์…˜ 7 ~ 12)

2024. 1. 24. 19:09ยท๐Ÿ“‚ Unity Engine Study/๐Ÿ“„ Unity ์ธํ”„๋Ÿฐ ๊ฐ•์˜

 

 

 

 

[ ์„น์…˜ 7. UI ]

๏ผƒ UI ๊ธฐ์ดˆ

  - UI ์ถ”๊ฐ€์‹œ ์ž๋™์œผ๋กœ Canvas๊ฐ€ ์ƒ์„ฑ๋˜๋Š”๋ฐ ์ด๋Š” ๋„ํ™”์ง€ ์—ญํ• ์„ ํ•œ๋‹ค.

  - UI๋Š” Rect Transform Component๋ฅผ ํ†ตํ•ด ์ขŒํ‘œ๋ฅผ ์„ค์ •ํ•œ๋‹ค.

  - UI๋Š” ์›๊ทผ๋ฒ•์„ ์ ์šฉ๋ฐ›์ง€ ์•Š๋Š”๋‹ค.

  - Shift๋ฅผ ๋ˆ„๋ฅธ์ฑ„๋กœ UI ํฌ๊ธฐ๋ฅผ ์กฐ์ ˆํ•  ๊ฒฝ์šฐ ๋น„์œจ์„ ์œ ์ง€ํ•˜๋ฉฐ ํฌ๊ธฐ๋ฅผ ์กฐ์ ˆํ•  ์ˆ˜ ์žˆ๋‹ค.

์ขŒ : Pivot / ์šฐ: Anchor

  -   Anchor๋Š” UI์—์„œ ์ƒ๋‹นํžˆ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•œ๋‹ค.

 

๏ผƒ Rect Transform

  - ๋””๋ฐ”์ด์Šค์˜ ์ข…๋ฅ˜์— ๋”ฐ๋ผ Screen์˜ ํฌ๊ธฐ๋Š” ์ œ๊ฐ๊ฐ์ด๋‹ค. ์ด๋•Œ Anchor ๊ธฐ๋Šฅ์ด ์ค‘์š”ํ•˜๊ฒŒ ์ž‘์šฉํ•œ๋‹ค.

  - Anchor๋Š” Rect Transform์„ Component๋กœ ๊ฐ€์ง„ ๋ถ€๋ชจ๋ฅผ ๊ฐ€์ ธ์•ผ ํ™œ์„ฑํ™”๊ฐ€ ๋œ๋‹ค.

Anchor์˜ ๊ฐœ๋…

  -   ๋ถ€๋ชจ์™€ Anchor ์‚ฌ์ด์˜ ๊ฑฐ๋ฆฌ๋Š” ๋น„์œจ๋กœ, Anchor์™€ ๋ณธ์ธ ์‚ฌ์ด์˜ ๊ฑฐ๋ฆฌ๋Š” ๊ณ ์ • ๊ฑฐ๋ฆฌ๋กœ ์—ฐ์‚ฐ์„ ํ•œ๋‹ค.

Anchor Presets

  -   Rect Transform์˜ Anchor Presets์„ ํ†ตํ•ด ์‰ฝ๊ณ  ๊ฐ„๋‹จํ•˜๊ฒŒ Anchor ์„ค์ •์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

  -   Anchor Presets์—์„œ Shift๋ฅผ ๋ˆ„๋ฅธ ์ƒํƒœ๋กœ Anchor ์„ค์ •์‹œ Pivot๋„ ํ•จ๊ป˜ ์ด๋™ํ•œ๋‹ค.

  -   Anchor Presets์—์„œ Alt๋ฅผ ๋ˆ„๋ฅธ ์ƒํƒœ๋กœ Anchor ์„ค์ •์‹œ ๋ณธ์ธ์˜ ์œ„์น˜๋„ ํ•จ๊ป˜ ์ด๋™ํ•œ๋‹ค.

  -   Anchor Presets์—์„œ Shift์™€ Alt๋ฅผ ๋ˆ„๋ฅธ ์ƒํƒœ๋กœ Anchor ์„ค์ •์‹œ Pivot๊ณผ ๋ณธ์ธ์˜ ์œ„์น˜๋„ ํ•จ๊ป˜ ์ด๋™ํ•œ๋‹ค.

 

๏ผƒ Button Event

  - Canvas์— UI๋ฅผ ๋ชจ๋‘ ์ถ”๊ฐ€ํ•œ ๋’ค ์ตœ์ข…์ ์œผ๋กœ ํ•ด๋‹น Canvas๋ฅผ Prefab ํ˜•ํƒœ๋กœ ์ €์žฅํ•˜๊ณค ํ•œ๋‹ค.

  - ํ•ด๋‹น Canvas๋‚ด์˜ UI์— ๊ด€ํ•œ Event๋Š” Event ๊ด€๋ฆฌ๋ฅผ ํ•˜๋Š” ๋‹ด๋‹นํ•˜๋Š” Script๋ฅผ ์ƒ์„ฑํ•œ ๋’ค ํ•ด๋‹น Script๋ฅผ Canvas์˜

    Component๋กœ ์ถ”๊ฐ€ํ•˜๊ณ  UI์˜ On Click()์˜ ๊ฐ์ฒด๋กœ Canvas๋ฅผ ์ถ”๊ฐ€, ์‹คํ–‰ํ•˜๊ณ ์ž ํ•˜๋Š” Event ํ•จ์ˆ˜๋ฅผ ์„ ํƒํ•œ๋‹ค.

    (Event ํ•จ์ˆ˜๋ฅผ Public์œผ๋กœ ์„ ์–ธํ•ด์•ผ ํ•จ์ˆ˜ ์„ ํƒ ๊ฐ€๋Šฅ)

  - Canvas๋ฅผ Prefab ํ˜•ํƒœ๋กœ ์ €์žฅํ•  ๊ฒฝ์šฐ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ํ•„์š”ํ• ๋•Œ๋งˆ๋‹ค ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

  - ์—ฌ๋Ÿฌ๊ฐœ์˜ Canvas๋กœ ์ธํ•ด ๊ฒน์น˜๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ ์ด๋Š” Canvas Component์˜ Sort Order์„ ํ†ตํ•ด ํ•ด๊ฒฐ ๊ฐ€๋Šฅํ•˜๋‹ค.

     (ํŒ์—…์ฐฝ ๊ตฌํ˜„์‹œ ์œ ์šฉ)

Button Event๋ฅผ ์œ„ํ•œ UI_Button Script ์ƒ์„ฑ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UI_Button : MonoBehaviour
{
    [SerializeField]
    Text _text;

    int _score = 0;

    public void OnButtonClicked()
    {
        _score++;
        _text.text = $"์ ์ˆ˜ : {_score}";
    }
}โ€‹

 

UI Click์‹œ ์บ๋ฆญํ„ฐ ์ด๋™์€ ์ œํ•œ๋˜๋„๋ก InputManager ์ˆ˜์ •
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class InputManager
{
    public Action KeyAction = null;
    public Action<Define.MouseEvent> MouseAction = null;

    bool _pressed = false;

    // ์ฒดํฌํ•˜๋Š” ๋ถ€๋ถ„์ด ์œ ์ผํ•ด์ง
    public void OnUpdate()
    {
        // using UnityEngine.EventSystems; ์ถ”๊ฐ€์‹œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
        if (EventSystem.current.IsPointerOverGameObject()) // UI๊ฐ€ Click๋œ ์ƒํ™ฉ์ผ ๊ฒฝ์šฐ 
            return;

        if (Input.anyKey && KeyAction != null)
            KeyAction.Invoke();

        if (MouseAction != null)
        {
            if (Input.GetMouseButton(0))
            {
                MouseAction.Invoke(Define.MouseEvent.Press); // Press Event๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ ์•Œ๋ ค์ค€๋‹ค.
                _pressed = true;
            }
            else
            {
                if (_pressed)
                    MouseAction.Invoke(Define.MouseEvent.Click); // Click Event๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ ์•Œ๋ ค์ค€๋‹ค.
                _pressed = false;
            }
        }
    }
}โ€‹

 

Prefab์œผ๋กœ ์ €์žฅ๋œ UI๋ฅผ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ์œ„ํ•œ ๊ฒƒ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    void Start()
    {
        Managers.Resource.Instantiate("UI_Button"); // ๋‹ค์Œ๊ณผ ๊ฐ™์ด UI Prefab์„ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.
    }
}โ€‹

 

๏ผƒUI ์ž๋™ํ™” #1

  - ๊ฒŒ์ž„ ๊ทœ๋ชจ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก UI์˜ Event ์—ฐ๊ฒฐ์„ Tool์„ ์ด์šฉํ•˜์—ฌ On Click()์„ ํ†ตํ•ด ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒƒ์ด ํž˜๋“ค์–ด์ง„๋‹ค.

     (๋ฟ๋งŒ ์•„๋‹Œ [SerializeField]์— ์„ ์–ธํ•œ UI๋ฅผ Tool์„ ์ด์šฉํ•˜์—ฌ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒƒ๋„ ํž˜๋“ค์–ด์ง„๋‹ค.)

UI ์ž๋™ํ™”๋ฅผ ์œ„ํ•œ UI_Button ์ˆ˜์ •
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UI_Button : MonoBehaviour
{
    Dictionary<Type, UnityEngine.Object[]> _objects = new Dictionary<Type, UnityEngine.Object[]>(); // Dictionary ์‚ฌ์šฉ

    enum Buttons
    {
        PointButton
    }

    enum Texts
    {
        PointText,
        ScoreText
    }

    private void Start()
    {
        Bind<Button>(typeof(Buttons)); // ๋„˜๊ธฐ๊ณ ์ž ํ•˜๋Š” enum์€ Buttons์ด๋ฉฐ, Button์ด๋ผ๋Š” Component๋ฅผ ๊ฐ€์ง„ ๊ฐ์ฒด๋ฅผ ์ฐพ์•„ Mapping ํ•ด๋‹ฌ๋ผ๋Š” ๊ฒƒ
        Bind<Text>(typeof(Texts)); // ๋„˜๊ธฐ๊ณ ์ž ํ•˜๋Š” enum์€ Texts์ด๋ฉฐ, Text๋ผ๋Š” Component๋ฅผ ๊ฐ€์ง„ ๊ฐ์ฒด๋ฅผ ์ฐพ์•„ Mapping ํ•ด๋‹ฌ๋ผ๋Š” ๊ฒƒ
    }

    // C#์˜ Reflection ๊ธฐ๋Šฅ์„ ํ†ตํ•ด enum์„ ํ•ด๋‹น ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ๋„˜๊ฒจ์ค„ ์ˆ˜ ์žˆ๋‹ค.
    // enum ๊ฐ’์„ ์ธ์ž๋กœ ๋„˜๊ฒจ์ฃผ๋ฉด enum ์•ˆ์˜ ์ด๋ฆ„์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ์ฐพ์•„ ์ž๋™์œผ๋กœ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ์—ญํ• ์„ ํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค.
    void Bind<T>(Type type) where T : UnityEngine.Object // using System;์„ ์ถ”๊ฐ€ํ•ด์•ผ Type ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
    {
        // ํ•ด๋‹น enum์— ์กด์žฌํ•˜๋Š” ๋ชจ๋“  ์ด๋ฆ„๋“ค์„ names์— ๋‹ด๋Š” ๊ฒƒ
        string[] names = Enum.GetNames(type); // String ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ (C#์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ)

        // Unity ๋ชจ๋“  ๊ฐ์ฒด์˜ ์ตœ์ƒ์œ„ ๋ถ€๋ชจ๊ฐ€ UnityEngine.Object
        UnityEngine.Object[] objects = new UnityEngine.Object[names.Length];
        _objects.Add(typeof(T), objects); // Dictionary์— ์ถ”๊ฐ€

        for (int i = 0; i < names.Length; i++)
        {
            objects[i] = Util.FindChild<T>(gameObject, names[i], true); // enum์— ์กด์žฌํ•˜๋Š” ์ด๋ฆ„์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ์ฐพ์•„ objects์— ์ €์žฅ
        }
    }

    int _score = 0;

    public void OnButtonClicked()
    {
        _score++;
    }
}โ€‹

 

Util ์„ฑ๊ฒฉ์„ ๊ฐ€์ง„ ํ•จ์ˆ˜๋“ค์„ ๊ด€๋ฆฌํ•˜๋Š” Util Script ์ƒ์„ฑ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Util
{
    // ์ตœ์ƒ์œ„ ๋ถ€๋ชจ๋ฅผ ๋ฐ›๊ณ , ์ด๋ฆ„์„ ์ž…๋ ฅํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ ํƒ€์ž…๋งŒ ์ผ์น˜ํ•ด๋„ ๋ฆฌํ„ด, ์žฌ๊ท€์ ์œผ๋กœ ์ฐพ์„๊ฑฐ๋ƒ? (์ฆ‰, ์ž์‹์˜ ์ž์‹๋„)
    public static T FindChild<T>(GameObject go, string name = null, bool recursive = false) where T : UnityEngine.Object // T๊ฐ€ UnityEngine.Object ์ธ๊ฒƒ๋งŒ ์ฐพ์„ ๊ฒƒ์ด๋‹ค.
    {
        if (go == null)
            return null;

        if (recursive == false)
        {
            for(int i = 0; i < go.transform.childCount; i++)
            {
                Transform transform = go.transform.GetChild(i);
                if (string.IsNullOrEmpty(name) || transform.name == name)
                {
                    T component = transform.GetComponent<T>();
                    if (component != null)
                        return component;
                }
            }
        }
        else
        {
            foreach (T component in go.GetComponentsInChildren<T>())
            {
                if (string.IsNullOrEmpty(name) || component.name == name)
                    return component;
            }
        }

        return null;
    }
}โ€‹

 

+ ์ถ”๊ฐ€ ๊ฒ€์ƒ‰ (https://engineer-mole.tistory.com/174)
 - Dictionary๋Š” Index ๋Œ€์‹  ์ค‘๋ณต ๋ถˆ๊ฐ€๋Šฅํ•œ Key๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  Value์™€ ํ•จ๊ป˜ ๋‹ค๋ฃฌ๋‹ค. ์ด์ฒ˜๋Ÿผ Key์™€ Value ์„ธํŠธ๋กœ ๋‹ค๋ฃจ๋Š” ๋ฐฐ์—ด์„

   "์—ฐ๊ด€ ๋ฐฐ์—ด"์ด๋ผ๊ณ  ํ•œ๋‹ค.

 - C#์—์„œ ์—ฐ๊ด€ ๋ฐฐ์—ด์„ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•œ Class๊ฐ€ ๋ฐ”๋กœ Dictionary Class์ด๋‹ค. Dictionary Class๋Š” Key๋ฅผ ํ†ตํ•ด Value์˜ ๊ฐ’์„ ์–ป์„

   ์ˆ˜ ์žˆ๋‹ค.

 - ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Add Method๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

 

+ ์ถ”๊ฐ€ ๊ฒ€์ƒ‰ (https://velog.io/@yongseok1000/%EC%9C%A0%EB%8B%88%ED%8B%B0-%EB%A6%AC%ED%94%8C%EB%A0%89%EC%85%98)
 - C#์€ Reflection ๊ธฐ๋Šฅ์„ ์ง€์›ํ•œ๋‹ค. ์ด๋Š” ๊ฐ์ฒด(Instance)๋ฅผ ํ† ๋Œ€๋กœ ๋ฐ์ดํ„ฐํƒ€์ž…์˜ ๋ฉ”ํƒ€์ ์ธ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ธฐ๋ฒ•์ด๋‹ค.

 - Reflection์€ ์กฐ์‚ฌ, Instance ์ƒ์„ฑ, ๊ธฐ์กด ๊ฐœ์ฒด์—์„œ ํ˜•์‹์„ ๊ฐ€์ ธ์™€ ํ˜ธ์ถœ, ์ ‘๊ทผ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.

 

+ ์ถ”๊ฐ€ ๊ฒ€์ƒ‰ (https://www.csharpstudy.com/CSharp/CSharp-generics.aspx)
 - C#์€ Generics ๊ธฐ๋Šฅ์„ ์ง€์›ํ•œ๋‹ค. ์ด๋Š” ๋ฐ์ดํ„ฐ์˜ Type์„ ํ™•์ •ํ•˜์ง€ ์•Š๊ณ  ๋ฐ์ดํ„ฐ Type ์ž์ฒด๋ฅผ Parameter๋กœ ๋ฐ›์•„๋“ค์ธ๋‹ค.

 - ์ด๋Š” ์—ฌ๋Ÿฌ ๋ฐ์ดํ„ฐ ํ˜•์‹์— ๋™์ผํ•œ Logic์„ ์ ์šฉํ•ด์•ผ ํ•  ๋•Œ ์œ ์šฉํ•˜๋‹ค.

 - Generic Type ์„ ์–ธ์‹œ where T : ~ ๋ฅผ ํ†ตํ•ด Type Parameter์— ์ œ์•ฝ ์กฐ๊ฑด์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

๏ผƒUI ์ž๋™ํ™” #2

  - Bind ํ•จ์ˆ˜๋Š” enum์— ์กด์žฌํ•˜๋Š” ์ด๋ฆ„์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ์ฐพ์•„ ์ €์žฅํ•œ๋‹ค. ์ด๋•Œ ์ €์žฅ๋œ ๊ฐ์ฒด๋“ค ์ค‘ index๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„

    ํ•ด๋‹นํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” Get ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

  - Bind ํ•จ์ˆ˜์ฒ˜๋Ÿผ Component๋ฅผ ์ฐพ๋Š” ๊ฒƒ์ด ์•„๋‹Œ Object ์ž์ฒด๋ฅผ Mapping ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด์— GameObject๋ฅผ

    ์œ„ํ•œ FindChild ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

Get ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•œ ํ›„ UI_Base Script๋ฅผ ์ƒ์„ฑํ•˜์—ฌ UI_Button๊ณผ ๋ถ„๋ฆฌ(UI_Button ์ด UI_Base๋ฅผ ์ƒ์†๋ฐ›๋„๋ก)
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UI_Base : MonoBehaviour
{
    protected Dictionary<Type, UnityEngine.Object[]> _objects = new Dictionary<Type, UnityEngine.Object[]>(); // Dictionary ์‚ฌ์šฉ

    // C#์˜ Reflection ๊ธฐ๋Šฅ์„ ํ†ตํ•ด enum์„ ํ•ด๋‹น ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ๋„˜๊ฒจ์ค„ ์ˆ˜ ์žˆ๋‹ค.
    // enum ๊ฐ’์„ ์ธ์ž๋กœ ๋„˜๊ฒจ์ฃผ๋ฉด enum ์•ˆ์˜ ์ด๋ฆ„์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ์ฐพ์•„ ์ž๋™์œผ๋กœ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ์—ญํ• ์„ ํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค.
    protected void Bind<T>(Type type) where T : UnityEngine.Object // using System;์„ ์ถ”๊ฐ€ํ•ด์•ผ Type ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
    {
        // ํ•ด๋‹น enum์— ์กด์žฌํ•˜๋Š” ๋ชจ๋“  ์ด๋ฆ„๋“ค์„ names์— ๋‹ด๋Š” ๊ฒƒ
        string[] names = Enum.GetNames(type); // String ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ (C#์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ)

        // Unity ๋ชจ๋“  ๊ฐ์ฒด์˜ ์ตœ์ƒ์œ„ ๋ถ€๋ชจ๊ฐ€ UnityEngine.Object
        UnityEngine.Object[] objects = new UnityEngine.Object[names.Length];
        _objects.Add(typeof(T), objects); // Dictionary์— ์ถ”๊ฐ€

        for (int i = 0; i < names.Length; i++)
        {
            if (typeof(T) == typeof(GameObject))
                objects[i] = Util.FindChild(gameObject, names[i], true);
            else
                objects[i] = Util.FindChild<T>(gameObject, names[i], true); // enum์— ์กด์žฌํ•˜๋Š” ์ด๋ฆ„์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ์ฐพ์•„ objects์— ์ €์žฅ
        }
    }

    // index๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„ ํ•ด๋‹นํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜
    protected T Get<T>(int idx) where T : UnityEngine.Object
    {
        // Key ๊ฐ’์„ ์ด์šฉํ•˜์—ฌ ์ถ”์ถœ
        UnityEngine.Object[] objects = null;
        if (_objects.TryGetValue(typeof(T), out objects) == false) // ๋งŒ์•ฝ ์ถ”์ถœ์— ์‹คํŒจํ•œ ๊ฒฝ์šฐ
            return null;

        return objects[idx] as T; // ์ถ”์ถœ์— ์„ฑ๊ณตํ•œ ๊ฒฝ์šฐ T๋กœ Castingํ•˜์—ฌ ๋ฐ˜ํ™˜ (objects๋Š” UnityEngine.Object ์ด๋ฏ€๋กœ)
    }

    // ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋“ค์€ ๊ตณ์ด Get์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋„๋ก
    protected Text GetText(int idx) { return Get<Text>(idx); }
    protected Button GetButton(int idx) { return Get<Button>(idx); }
    protected Image GetImage(int idx) { return Get<Image>(idx); }
}โ€‹

 

UI_Base๋ฅผ ์ƒ์† ๋ฐ›๋Š” UI_Button ์ˆ˜์ •
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UI_Button : UI_Base
{
    enum Buttons
    {
        PointButton
    }

    enum Texts
    {
        PointText,
        ScoreText
    }

    enum GameObjects
    {
        TestObject,
    }

    private void Start()
    {
        Bind<Button>(typeof(Buttons)); // ๋„˜๊ธฐ๊ณ ์ž ํ•˜๋Š” enum์€ Buttons์ด๋ฉฐ, Button์ด๋ผ๋Š” Component๋ฅผ ๊ฐ€์ง„ ๊ฐ์ฒด๋ฅผ ์ฐพ์•„ Mapping ํ•ด๋‹ฌ๋ผ๋Š” ๊ฒƒ
        Bind<Text>(typeof(Texts)); // ๋„˜๊ธฐ๊ณ ์ž ํ•˜๋Š” enum์€ Texts์ด๋ฉฐ, Text๋ผ๋Š” Component๋ฅผ ๊ฐ€์ง„ ๊ฐ์ฒด๋ฅผ ์ฐพ์•„ Mapping ํ•ด๋‹ฌ๋ผ๋Š” ๊ฒƒ
        Bind<GameObject>(typeof(GameObjects)); // Component๋ฅผ ์ฐพ๋Š” ๊ฒƒ์ด ์•„๋‹Œ Object ์ž์ฒด๋ฅผ Mappingํ•˜๋Š” ๊ฒฝ์šฐ

        GetText((int)Texts.ScoreText).text = "Bind Test"; // ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉ
    }

    int _score = 0;

    public void OnButtonClicked()
    {
        _score++;
    }
}

 

GameObject๋ฅผ ์œ„ํ•œ FindChild ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•œ Util ์ˆ˜์ •
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Util
{
    // GameObject๋ฅผ ์œ„ํ•œ FindChild ์ƒ์„ฑ
    public static GameObject FindChild(GameObject go, string name = null, bool recursive = false)
    {
        Transform transform = FindChild<Transform>(go, name, recursive); // ๋ชจ๋“  GameObject๋Š” Transform Component๋ฅผ ๊ฐ€์ง€๋ฏ€๋กœ
        if (transform == null)
            return null;
        return transform.gameObject;
    }

    // ์ตœ์ƒ์œ„ ๋ถ€๋ชจ๋ฅผ ๋ฐ›๊ณ , ์ด๋ฆ„์„ ์ž…๋ ฅํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ ํƒ€์ž…๋งŒ ์ผ์น˜ํ•ด๋„ ๋ฆฌํ„ด, ์žฌ๊ท€์ ์œผ๋กœ ์ฐพ์„๊ฑฐ๋ƒ? (์ฆ‰, ์ž์‹์˜ ์ž์‹๋„)
    public static T FindChild<T>(GameObject go, string name = null, bool recursive = false) where T : UnityEngine.Object // T๊ฐ€ UnityEngine.Object ์ธ๊ฒƒ๋งŒ ์ฐพ์„ ๊ฒƒ์ด๋‹ค.
    {
        if (go == null)
            return null;

        if (recursive == false)
        {
            for(int i = 0; i < go.transform.childCount; i++)
            {
                Transform transform = go.transform.GetChild(i);
                if (string.IsNullOrEmpty(name) || transform.name == name)
                {
                    T component = transform.GetComponent<T>();
                    if (component != null)
                        return component;
                }
            }
        }
        else
        {
            foreach (T component in go.GetComponentsInChildren<T>())
            {
                if (string.IsNullOrEmpty(name) || component.name == name)
                    return component;
            }
        }

        return null;
    }
}โ€‹

 

๏ผƒUI ์ž๋™ํ™” #3

  - UI Event ์—ฐ๋™์„ ์œ„ํ•ด์„œ๋Š” Event System์„ ์ด์šฉํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

UI Event๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” UI_EventHandler Script ์ƒ์„ฑ
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class UI_EventHandler : MonoBehaviour, IBeginDragHandler, IDragHandler
{
    public Action<PointerEventData> OnBeginDragHandler = null;
    public Action<PointerEventData> OnDragHandler = null;

    public void OnBeginDrag(PointerEventData eventData)
    {
        if (OnBeginDragHandler != null)
            OnBeginDragHandler.Invoke(eventData);
    }

    public void OnDrag(PointerEventData eventData)
    {
        if (OnDragHandler != null)
            OnDragHandler.Invoke(eventData);
    }
}โ€‹

 

Event ์ถ”๊ฐ€๋ฅผ ์œ„ํ•œ UI_Button ์ˆ˜์ •
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class UI_Button : UI_Base
{
    enum Buttons
    {
        PointButton
    }

    enum Texts
    {
        PointText,
        ScoreText
    }

    enum GameObjects
    {
        TestObject,
    }

    enum Images
    {
        ItemIcon,
    }

    private void Start()
    {
        Bind<Button>(typeof(Buttons)); // ๋„˜๊ธฐ๊ณ ์ž ํ•˜๋Š” enum์€ Buttons์ด๋ฉฐ, Button์ด๋ผ๋Š” Component๋ฅผ ๊ฐ€์ง„ ๊ฐ์ฒด๋ฅผ ์ฐพ์•„ Mapping ํ•ด๋‹ฌ๋ผ๋Š” ๊ฒƒ
        Bind<Text>(typeof(Texts)); // ๋„˜๊ธฐ๊ณ ์ž ํ•˜๋Š” enum์€ Texts์ด๋ฉฐ, Text๋ผ๋Š” Component๋ฅผ ๊ฐ€์ง„ ๊ฐ์ฒด๋ฅผ ์ฐพ์•„ Mapping ํ•ด๋‹ฌ๋ผ๋Š” ๊ฒƒ
        Bind<GameObject>(typeof(GameObjects)); // Component๋ฅผ ์ฐพ๋Š” ๊ฒƒ์ด ์•„๋‹Œ Object ์ž์ฒด๋ฅผ Mappingํ•˜๋Š” ๊ฒฝ์šฐ
        Bind<Image>(typeof(Images));

        GetText((int)Texts.ScoreText).text = "Bind Test"; // ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉ

        // ์ด๋ฒคํŠธ ์ถ”๊ฐ€
        GameObject go = GetImage((int)Images.ItemIcon).gameObject; // ItemIcon์„ ์ฐพ์•„ Bindํ•œ ๊ฒƒ์˜ Image Component๋ฅผ ๋ฝ‘์•„์˜จ ๋’ค, ํ•ด๋‹น ๊ฐ์ฒด ์ž์ฒด๋ฅผ ๊ฐ€์ ธ์˜จ ๊ฒƒ (GameObject)
        UI_EventHandler evt = go.GetComponent<UI_EventHandler>(); // ํ•ด๋‹น ๊ฐ์ฒด์˜ UI_EventHandler Component๋ฅผ ๋ฝ‘์•„์˜จ ๊ฒƒ
        evt.OnDragHandler += ((PointerEventData data) => { evt.gameObject.transform.position = data.position; });
    }

    int _score = 0;

    public void OnButtonClicked()
    {
        _score++;
    }
}

 

+ ์ถ”๊ฐ€ ๊ฒ€์ƒ‰ 

 - Delegate, ๋ฌด๋ช… Method, ๋žŒ๋‹ค์‹์˜ ๊ฐœ๋…์„ ์•„๋ž˜ ์œ ํŠœ๋ธŒ ์˜์ƒ์„ ํ†ตํ•ด ์‰ฝ๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

( https://www.youtube.com/watch?v=6FomZi4QiRY&ab_channel=%EC%BC%80%EC%9D%B4%EB%94%94  )

 - Delegate๋Š” Method Parameter์™€ Return Type์— ๋Œ€ํ•œ ์ •์˜ ํ›„, ๋™์ผํ•œ Parameter์™€ Return Type์„ ๊ฐ€์ง„ Method๋ฅผ ์„œ๋กœ

   ํ˜ธํ™˜ํ•ด์„œ ๋ถˆ๋Ÿฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค์–ด์ค€๋‹ค.

 - ๋ฌด๋ช… Method๋Š” ์–ด๋–ค Method๊ฐ€ ์ผํšŒ์šฉ์œผ๋กœ ๋‹จ์ˆœํ•œ ๋ฌธ์žฅ๋“ค๋กœ ๊ตฌ์„ฑ๋œ ๊ฒฝ์šฐ ๋ณ„๋„์˜ Method๋กœ ์ •์˜ํ•˜์ง€ ์•Š๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ

   ๋„๋ก ๋งŒ๋“ค์–ด์ค€๋‹ค. ์ด๋Š” delegate ํ‚ค์›Œ๋“œ์™€ ํ•จ๊ป˜ ์„ ์–ธํ•˜๋ฉฐ ์ด๋ฆ„์€ ์ง€์ •ํ•˜์ง€ ์•Š๋Š”๋‹ค. (Delegate๋ฅผ ํ†ตํ•ด์„œ๋งŒ ํ˜ธ์ถœ ๊ฐ€๋Šฅ)
 - ๋žŒ๋‹ค์‹์€ ๋ฌด๋ช… ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋ฉฐ ๊ฐ„๊ฒฐํ•˜๊ณ  ์ง๊ด€์ ์ธ ํ˜•ํƒœ๋กœ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค. ์ด๋Š” C# ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€

   ํ˜•์‹ ์œ ์ถ” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋ฏ€๋กœ Parameter์˜ Type์„ ๊ตณ์ด ์ง€์ •ํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

   (์ฆ‰, ๋žŒ๋‹ค์‹์„ ํ†ตํ•ด ๋ฌด๋ช… Method๋ณด๋‹ค ๋” ์งง์€ ์ฝ”๋“œ๋กœ ๋ฌด๋ช… Method๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.)

Delegate, ๋ฌด๋ช… Method, ๋žŒ๋‹ค์‹ ์˜ˆ์ œ
int a = 5;
int b = 5;

int sum;

void Add() {
	sum = A + b;
}

void Back() {
	sum = 0;
}

delegate void MyDelegate();
MyDelegate() myDelegate;

void Start() {
    myDelegate = Add;
    myDelegate += delegate() { print(sum); }; // ๋ฌด๋ช… ๋ฉ”์†Œ๋“œ
    myDelegate += () => print(sum); // ๋žŒ๋‹ค์‹
    myDelegate += Back;
    
    myDelegate();
}

 

๏ผƒUI ์ž๋™ํ™” #4

  - UI Event ์ถ”๊ฐ€ ์ฝ”๋“œ๋ฅผ ์ •๋ฆฌ

OnBeginDrag ์‚ญ์ œ ํ›„ OnPointerClick์„ ์ถ”๊ฐ€ํ•œ UI_EventHandler ์ˆ˜์ •
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class UI_EventHandler : MonoBehaviour, IPointerClickHandler, IDragHandler
{
    public Action<PointerEventData> OnClickHandler = null;
    public Action<PointerEventData> OnDragHandler = null;

    public void OnPointerClick(PointerEventData eventData)
    {
        if (OnClickHandler != null)
            OnClickHandler.Invoke(eventData);
    }

    public void OnDrag(PointerEventData eventData)
    {
        if (OnDragHandler != null)
            OnDragHandler.Invoke(eventData);
    }
}โ€‹

 

UIEvent enum์„ ์ถ”๊ฐ€ํ•œ Define ์ˆ˜์ •
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Define
{
    public enum UIEvent
    {
        Click,
        Drag,
    }

    public enum MouseEvent
    {
        Press,
        Click,
    }

    public enum CameraMode
    {
        QuaterView, 
    }
}โ€‹

 

GetOrAddComponent ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•œ Util ์ˆ˜์ •
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Util
{
    public static T GetOrAddComponent<T>(GameObject go) where T : UnityEngine.Component
    {
        T component = go.GetComponent<T>();
        if (component == null)
            component = go.AddComponent<T>();
        return component;
    }

    // GameObject๋ฅผ ์œ„ํ•œ FindChild ์ƒ์„ฑ
    public static GameObject FindChild(GameObject go, string name = null, bool recursive = false)
    {
        Transform transform = FindChild<Transform>(go, name, recursive); // ๋ชจ๋“  GameObject๋Š” Transform Component๋ฅผ ๊ฐ€์ง€๋ฏ€๋กœ
        if (transform == null)
            return null;
        return transform.gameObject;
    }

    // ์ตœ์ƒ์œ„ ๋ถ€๋ชจ๋ฅผ ๋ฐ›๊ณ , ์ด๋ฆ„์„ ์ž…๋ ฅํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ ํƒ€์ž…๋งŒ ์ผ์น˜ํ•ด๋„ ๋ฆฌํ„ด, ์žฌ๊ท€์ ์œผ๋กœ ์ฐพ์„๊ฑฐ๋ƒ? (์ฆ‰, ์ž์‹์˜ ์ž์‹๋„)
    public static T FindChild<T>(GameObject go, string name = null, bool recursive = false) where T : UnityEngine.Object // T๊ฐ€ UnityEngine.Object ์ธ๊ฒƒ๋งŒ ์ฐพ์„ ๊ฒƒ์ด๋‹ค.
    {
        if (go == null)
            return null;

        if (recursive == false)
        {
            for(int i = 0; i < go.transform.childCount; i++)
            {
                Transform transform = go.transform.GetChild(i);
                if (string.IsNullOrEmpty(name) || transform.name == name)
                {
                    T component = transform.GetComponent<T>();
                    if (component != null)
                        return component;
                }
            }
        }
        else
        {
            foreach (T component in go.GetComponentsInChildren<T>())
            {
                if (string.IsNullOrEmpty(name) || component.name == name)
                    return component;
            }
        }

        return null;
    }
}โ€‹

 

AddUIEvent ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•œ UI_Base ์ˆ˜์ •
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class UI_Base : MonoBehaviour
{
    protected Dictionary<Type, UnityEngine.Object[]> _objects = new Dictionary<Type, UnityEngine.Object[]>(); // Dictionary ์‚ฌ์šฉ

    // C#์˜ Reflection ๊ธฐ๋Šฅ์„ ํ†ตํ•ด enum์„ ํ•ด๋‹น ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ๋„˜๊ฒจ์ค„ ์ˆ˜ ์žˆ๋‹ค.
    // enum ๊ฐ’์„ ์ธ์ž๋กœ ๋„˜๊ฒจ์ฃผ๋ฉด enum ์•ˆ์˜ ์ด๋ฆ„์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ์ฐพ์•„ ์ž๋™์œผ๋กœ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ์—ญํ• ์„ ํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค.
    protected void Bind<T>(Type type) where T : UnityEngine.Object // using System;์„ ์ถ”๊ฐ€ํ•ด์•ผ Type ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
    {
        // ํ•ด๋‹น enum์— ์กด์žฌํ•˜๋Š” ๋ชจ๋“  ์ด๋ฆ„๋“ค์„ names์— ๋‹ด๋Š” ๊ฒƒ
        string[] names = Enum.GetNames(type); // String ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ (C#์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ)

        // Unity ๋ชจ๋“  ๊ฐ์ฒด์˜ ์ตœ์ƒ์œ„ ๋ถ€๋ชจ๊ฐ€ UnityEngine.Object
        UnityEngine.Object[] objects = new UnityEngine.Object[names.Length];
        _objects.Add(typeof(T), objects); // Dictionary์— ์ถ”๊ฐ€

        for (int i = 0; i < names.Length; i++)
        {
            if (typeof(T) == typeof(GameObject))
                objects[i] = Util.FindChild(gameObject, names[i], true);
            else
                objects[i] = Util.FindChild<T>(gameObject, names[i], true); // enum์— ์กด์žฌํ•˜๋Š” ์ด๋ฆ„์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ์ฐพ์•„ objects์— ์ €์žฅ
        }
    }

    // index๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„ ํ•ด๋‹นํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜
    protected T Get<T>(int idx) where T : UnityEngine.Object
    {
        // Key ๊ฐ’์„ ์ด์šฉํ•˜์—ฌ ์ถ”์ถœ
        UnityEngine.Object[] objects = null;
        if (_objects.TryGetValue(typeof(T), out objects) == false) // ๋งŒ์•ฝ ์ถ”์ถœ์— ์‹คํŒจํ•œ ๊ฒฝ์šฐ
            return null;

        return objects[idx] as T; // ์ถ”์ถœ์— ์„ฑ๊ณตํ•œ ๊ฒฝ์šฐ T๋กœ Castingํ•˜์—ฌ ๋ฐ˜ํ™˜ (objects๋Š” UnityEngine.Object ์ด๋ฏ€๋กœ)
    }

    // ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋“ค์€ ๊ตณ์ด Get์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋„๋ก
    protected Text GetText(int idx) { return Get<Text>(idx); }
    protected Button GetButton(int idx) { return Get<Button>(idx); }
    protected Image GetImage(int idx) { return Get<Image>(idx); }

    public static void AddUIEvent(GameObject go, Action<PointerEventData> action, Define.UIEvent type = Define.UIEvent.Click)
    {
        UI_EventHandler evt = Util.GetOrAddComponent<UI_EventHandler>(go);

        switch (type)
        {
            case Define.UIEvent.Click:
                evt.OnClickHandler -= action;
                evt.OnClickHandler += action;
                break;
            case Define.UIEvent.Drag:
                evt.OnDragHandler -= action;
                evt.OnDragHandler += action;
                break;
        }

        evt.OnDragHandler += ((PointerEventData data) => { evt.gameObject.transform.position = data.position; });
    }
}โ€‹

 

์œ„์˜ ์ˆ˜์ •์„ ํ†ตํ•ด ๊ฐ„๋‹จํ•˜๊ฒŒ ์ด๋ฒคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋„๋ก UI_Button Event ํ˜ธ์ถœ ์ˆ˜์ •
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class UI_Button : UI_Base
{
    enum Buttons
    {
        PointButton
    }

    enum Texts
    {
        PointText,
        ScoreText
    }

    enum GameObjects
    {
        TestObject,
    }

    enum Images
    {
        ItemIcon,
    }

    private void Start()
    {
        Bind<Button>(typeof(Buttons)); // ๋„˜๊ธฐ๊ณ ์ž ํ•˜๋Š” enum์€ Buttons์ด๋ฉฐ, Button์ด๋ผ๋Š” Component๋ฅผ ๊ฐ€์ง„ ๊ฐ์ฒด๋ฅผ ์ฐพ์•„ Mapping ํ•ด๋‹ฌ๋ผ๋Š” ๊ฒƒ
        Bind<Text>(typeof(Texts)); // ๋„˜๊ธฐ๊ณ ์ž ํ•˜๋Š” enum์€ Texts์ด๋ฉฐ, Text๋ผ๋Š” Component๋ฅผ ๊ฐ€์ง„ ๊ฐ์ฒด๋ฅผ ์ฐพ์•„ Mapping ํ•ด๋‹ฌ๋ผ๋Š” ๊ฒƒ
        Bind<GameObject>(typeof(GameObjects)); // Component๋ฅผ ์ฐพ๋Š” ๊ฒƒ์ด ์•„๋‹Œ Object ์ž์ฒด๋ฅผ Mappingํ•˜๋Š” ๊ฒฝ์šฐ
        Bind<Image>(typeof(Images));

        GetText((int)Texts.ScoreText).text = "Bind Test"; // ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉ

        // ์ด๋ฒคํŠธ ์ถ”๊ฐ€
        GameObject go = GetImage((int)Images.ItemIcon).gameObject; // ItemIcon์„ ์ฐพ์•„ Bindํ•œ ๊ฒƒ์˜ Image Component๋ฅผ ๋ฝ‘์•„์˜จ ๋’ค, ํ•ด๋‹น ๊ฐ์ฒด ์ž์ฒด๋ฅผ ๊ฐ€์ ธ์˜จ ๊ฒƒ (GameObject)
        AddUIEvent(go, (PointerEventData data) => {go.transform.position = data.position; }, Define.UIEvent.Drag);
    }

    int _score = 0;

    public void OnButtonClicked()
    {
        _score++;
    }
}โ€‹

 

+ ์ถ”๊ฐ€ ๊ฒ€์ƒ‰ (https://developer-talk.tistory.com/477)

 - ํ™•์žฅ Method๋Š” Class ๋˜๋Š” Interface๋ฅผ ์ƒ์†ํ•˜๊ฑฐ๋‚˜ ์žฌ๊ตฌ์„ฑํ•˜์ง€ ์•Š๊ณ  Class์— Method๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

 - ํ™•์žฅ Method๋Š” ๊ธฐ์กด Class์— ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉฐ Static Class์—์„œ ์ •์˜ํ•ด์•ผ ํ•œ๋‹ค. ๋˜ํ•œ ํ™•์žฅ Method์˜ ์ฒซ๋ฒˆ์งธ Parameter

   ๋ฅผ Binding Parameter๋ผ๊ณ  ํ•˜๋ฉฐ, ํ•ด๋‹น Parameter์˜ Type์€ Binding ๋˜์–ด์•ผ ํ•˜๋Š” Class์ด๋‹ค. ์ด๋•Œ Class ์ด๋ฆ„ ์•ž์— this

   Keyword๊ฐ€ ์กด์žฌํ•ด์•ผํ•œ๋‹ค.

 

๏ผƒUI Manager #1

  - UI๋Š” PopUp UI์™€ Scene UI๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๋‹ค.

  - UI_Manager๋ฅผ ํ†ตํ•ด PopUp UI Canvas Component์˜ Sort Order๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ , ์ด๋ฅผ Stack์„ ํ†ตํ•ด ๊ด€๋ฆฌํ•œ๋‹ค.

UI ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ UIManager ์ƒ์„ฑ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIManager
{
    int _order = 0; // ์ตœ๊ทผ์— ์‚ฌ์šฉํ•œ order๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ๋ณ€์ˆ˜

    // Stack์„ ํ†ตํ•ด Popup์„ ๊ด€๋ฆฌ (๊ฐ€์žฅ ๋งˆ์ง€๋ง‰์— ๋„์šด PopUp์ด ๊ฐ€์žฅ ๋จผ์ € ์‚ญ์ œ๋˜์–ด์•ผ ํ•˜๋ฏ€๋กœ)
    Stack<UI_Popup> _popupStack = new Stack<UI_Popup>(); // ์‚ฌ์‹ค์ƒ GameObject๋Š” ๋นˆ ๊นกํ†ต๊ณผ ๊ฐ™๋‹ค. ํ•ด๋‹น GameObject์˜ Component์— ๋งŽ์€ ์ •๋ณด๋“ค์ด ๋‹ด๊ฒจ์žˆ๋Š”๊ฒƒ (๋•Œ๋ฌธ์— UI_PopUp Component ์ •๋ณด๋ฅผ ๋‹ด๋Š” ๊ฒƒ)

    public T ShowPopupUI<T>(string name = null) where T : UI_Popup // name์€ Prefab์˜ ์ด๋ฆ„๊ณผ, T๋Š” Script์™€ ๊ด€๋ จ์ด ์žˆ๋‹ค. (name์€ ํ•„์ˆ˜๊ฐ€ ์•„๋‹Œ ์˜ต์…˜์œผ๋กœ)
    {
        if (string.IsNullOrEmpty(name))
            name = typeof(T).Name;

        GameObject go = Managers.Resource.Instantiate($"UI/Popup/{name}");
        T popup = Util.GetOrAddComponent<T>(go);
        _popupStack.Push(popup);

        return popup;
    }

    public void ClosePopupUI(UI_Popup popup)
    {
        if (_popupStack.Count == 0)
            return;

        if(_popupStack.Peek() != popup)
        {
            Debug.Log("Close Popup Failed!");
            return;
        }

        ClosePopupUI();
    }

    public void ClosePopupUI()
    {
        if (_popupStack.Count == 0)
            return;

        UI_Popup popup = _popupStack.Pop();
        Managers.Resource.Destroy(popup.gameObject);
        popup = null;

        _order--;
    }

    public void CloseAllPopupUI()
    {
        while (_popupStack.Count > 0)
            ClosePopupUI();
    }
}โ€‹

 

Managers์— ResourceManager ์ถ”๊ฐ€
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Managers : MonoBehaviour
{
    static Managers s_instance; // ์œ ์ผ์„ฑ ๋ณด์žฅ
    static Managers Instance { get { Init(); return s_instance; } } // ์œ ์ผํ•œ ๋งค๋‹ˆ์ €๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค

    InputManager _input = new InputManager();
    ResourceManager _resource = new ResourceManager();
    UIManager _ui = new UIManager();

    public static InputManager Input { get { return Instance._input; } }
    public static ResourceManager Resource { get { return Instance._resource; } }
    public static UIManager UI {  get { return Instance._ui; } }

    void Start()
    {
        Init();
    }

    void Update()
    {
        _input.OnUpdate();
    }

    static void Init()
    {
        // ์ดˆ๊ธฐํ™”
        if (s_instance == null) {
            GameObject go = GameObject.Find("Managers");
            if (go == null) {
                go = new GameObject { name = "Managers" };
                go.AddComponent<Managers>();
            }
            DontDestroyOnLoad(go);
            s_instance = go.GetComponent<Managers>();
        }
    }
}โ€‹

 

+ ์ถ”๊ฐ€ ๊ฒ€์ƒ‰ (https://jeong-f.tistory.com/3)

 - Stack์—์„œ์˜ Peek() ํ•จ์ˆ˜๋Š” ๋นผ๋‚ด๊ณ ์ž ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•œ ํ•จ์ˆ˜์ด๋‹ค.

 

๏ผƒUI Manager #2

  - Unity์˜ Hierarchy์—๋Š” ํด๋”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— Create Empty๋ฅผ ํ†ตํ•œ GameObject๋ฅผ ํด๋”๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

Virtual Method์ธ Init() ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•œ UI_Popup ์ˆ˜์ •
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UI_Popup : UI_Base
{
    public virtual void Init()
    {
        Managers.UI.SetCanvas(gameObject, true);
    }

    public virtual void ClosePopupUI()
    {
        Managers.UI.ClosePopupUI(this);
    }
}

 

Virtual Method์ธ Init() ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•œ UI_Scene ์ˆ˜์ •
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UI_Scene : UI_Base
{
    public virtual void Init()
    {
        Managers.UI.SetCanvas(gameObject, false);
    }
}โ€‹

 

UI_Popup์˜ Init() ํ•จ์ˆ˜๋ฅผ Overrideํ•œ UI_Button ์ˆ˜์ •
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class UI_Button : UI_Popup
{
    enum Buttons
    {
        PointButton
    }

    enum Texts
    {
        PointText,
        ScoreText
    }

    enum GameObjects
    {
        TestObject,
    }

    enum Images
    {
        ItemIcon,
    }

    private void Start()
    {
        Init();
    }

    public override void Init()
    {
        base.Init();

        Bind<Button>(typeof(Buttons)); // ๋„˜๊ธฐ๊ณ ์ž ํ•˜๋Š” enum์€ Buttons์ด๋ฉฐ, Button์ด๋ผ๋Š” Component๋ฅผ ๊ฐ€์ง„ ๊ฐ์ฒด๋ฅผ ์ฐพ์•„ Mapping ํ•ด๋‹ฌ๋ผ๋Š” ๊ฒƒ
        Bind<Text>(typeof(Texts)); // ๋„˜๊ธฐ๊ณ ์ž ํ•˜๋Š” enum์€ Texts์ด๋ฉฐ, Text๋ผ๋Š” Component๋ฅผ ๊ฐ€์ง„ ๊ฐ์ฒด๋ฅผ ์ฐพ์•„ Mapping ํ•ด๋‹ฌ๋ผ๋Š” ๊ฒƒ
        Bind<GameObject>(typeof(GameObjects)); // Component๋ฅผ ์ฐพ๋Š” ๊ฒƒ์ด ์•„๋‹Œ Object ์ž์ฒด๋ฅผ Mappingํ•˜๋Š” ๊ฒฝ์šฐ
        Bind<Image>(typeof(Images));

        GetButton((int)Buttons.PointButton).gameObject.AddUIEvent(OnButtonClicked);

        // ์ด๋ฒคํŠธ ์ถ”๊ฐ€
        GameObject go = GetImage((int)Images.ItemIcon).gameObject; // ItemIcon์„ ์ฐพ์•„ Bindํ•œ ๊ฒƒ์˜ Image Component๋ฅผ ๋ฝ‘์•„์˜จ ๋’ค, ํ•ด๋‹น ๊ฐ์ฒด ์ž์ฒด๋ฅผ ๊ฐ€์ ธ์˜จ ๊ฒƒ (GameObject)
        AddUIEvent(go, (PointerEventData data) => { go.transform.position = data.position; }, Define.UIEvent.Drag);
    }

    int _score = 0;

    public void OnButtonClicked(PointerEventData data)
    {
        _score++;


        GetText((int)Texts.ScoreText).text = $"์ ์ˆ˜ : { _score}";
    }
}โ€‹

 

Sort Order ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ UIManager ์ˆ˜์ •
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIManager
{
    int _order = 10; // ์ตœ๊ทผ์— ์‚ฌ์šฉํ•œ order๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ๋ณ€์ˆ˜

    // Stack์„ ํ†ตํ•ด Popup์„ ๊ด€๋ฆฌ (๊ฐ€์žฅ ๋งˆ์ง€๋ง‰์— ๋„์šด PopUp์ด ๊ฐ€์žฅ ๋จผ์ € ์‚ญ์ œ๋˜์–ด์•ผ ํ•˜๋ฏ€๋กœ)
    Stack<UI_Popup> _popupStack = new Stack<UI_Popup>(); // ์‚ฌ์‹ค์ƒ GameObject๋Š” ๋นˆ ๊นกํ†ต๊ณผ ๊ฐ™๋‹ค. ํ•ด๋‹น GameObject์˜ Component์— ๋งŽ์€ ์ •๋ณด๋“ค์ด ๋‹ด๊ฒจ์žˆ๋Š”๊ฒƒ (๋•Œ๋ฌธ์— UI_PopUp Component ์ •๋ณด๋ฅผ ๋‹ด๋Š” ๊ฒƒ)
    UI_Scene _sceneUI = null;

    public GameObject Root
    {
        get
        {
            GameObject root = GameObject.Find("@UI_Root");
            if (root == null)
                root = new GameObject { name = "@UI_Root" };
            return root;
        }
    }

    public void SetCanvas(GameObject go, bool sort = true) // ์™ธ๋ถ€์—์„œ Popup UI ์ƒ์„ฑ์‹œ ์ž์‹ ์˜ Canvas์— ์กด์žฌํ•˜๋Š” UI์˜ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฒฐ์ •
    {
        Canvas canvas = Util.GetOrAddComponent<Canvas>(go);
        canvas.renderMode = RenderMode.ScreenSpaceOverlay;
        canvas.overrideSorting = true; // Canvas๊ฐ€ ์ค‘์ฒฉ๋œ ๊ฒฝ์šฐ ๋ถ€๋ชจ์™€ ๋…๋ฆฝํ•˜์—ฌ ์ž์‹ ๋งŒ์˜ sortingOrder๋ฅผ ๊ฐ–๋Š”๋‹ค๋Š” ๊ฒƒ

        if (sort)
        {
            canvas.sortingOrder = _order;
            _order++;
        }
        else // sort ์š”์ฒญ์„ ์•ˆ ํ•œ ๊ฒฝ์šฐ๋Š” Popup UI์™€ ๊ด€๋ จ์ด ์—†๋Š” ์ผ๋ฐ˜ UI๋ผ๋Š” ๊ฒƒ
        {
            canvas.sortingOrder = 0;
        }    
    }

    public T ShowSceneUI<T>(string name = null) where T : UI_Scene // name์€ Prefab์˜ ์ด๋ฆ„๊ณผ, T๋Š” Script์™€ ๊ด€๋ จ์ด ์žˆ๋‹ค. (name์€ ํ•„์ˆ˜๊ฐ€ ์•„๋‹Œ ์˜ต์…˜์œผ๋กœ)
    {
        if (string.IsNullOrEmpty(name))
            name = typeof(T).Name;

        GameObject go = Managers.Resource.Instantiate($"UI/Scene/{name}");
        T sceneUI = Util.GetOrAddComponent<T>(go);
        _sceneUI = sceneUI;

        go.transform.SetParent(Root.transform);

        return sceneUI;
    }

    public T ShowPopupUI<T>(string name = null) where T : UI_Popup // name์€ Prefab์˜ ์ด๋ฆ„๊ณผ, T๋Š” Script์™€ ๊ด€๋ จ์ด ์žˆ๋‹ค. (name์€ ํ•„์ˆ˜๊ฐ€ ์•„๋‹Œ ์˜ต์…˜์œผ๋กœ)
    {
        if (string.IsNullOrEmpty(name))
            name = typeof(T).Name;

        GameObject go = Managers.Resource.Instantiate($"UI/Popup/{name}");
        T popup = Util.GetOrAddComponent<T>(go);
        _popupStack.Push(popup);

        go.transform.SetParent(Root.transform);

        return popup;
    }

    public void ClosePopupUI(UI_Popup popup)
    {
        if (_popupStack.Count == 0)
            return;

        if(_popupStack.Peek() != popup)
        {
            Debug.Log("Close Popup Failed!");
            return;
        }

        ClosePopupUI();
    }

    public void ClosePopupUI()
    {
        if (_popupStack.Count == 0)
            return;

        UI_Popup popup = _popupStack.Pop();
        Managers.Resource.Destroy(popup.gameObject);
        popup = null;

        _order--;
    }

    public void CloseAllPopupUI()
    {
        while (_popupStack.Count > 0)
            ClosePopupUI();
    }
}โ€‹

 

Blocker ์ƒ์„ฑ

  - ํŒ์—…์ฐฝ ๋’ค UI๋“ค์˜ Event ๋ฐœ์ƒ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด์„œ๋Š” ์ผ์ข…์˜ Blocker๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค.

  - Blocker๋Š” [ Hierarchy ] - [ UI ] - [ Image ๋˜๋Š” Panel ] ์„ ์ƒ์„ฑํ•˜๊ณ  Alpha ๊ฐ’์„ 0์œผ๋กœ ์„ค์ •ํ•œ ๋’ค ํฌ๊ธฐ๋ฅผ ํฌ๊ฒŒ ๋Š˜๋ ค์ค€๋‹ค. 

    ์ด๋•Œ Blocker์˜ Raycast Target์€ ๋ฐ˜๋“œ์‹œ ์„ค์ •๋˜์–ด ์žˆ์–ด์•ผ ํ•œ๋‹ค.

   > Hierarchy ์ฐฝ์—์„œ Blocker ์•„๋ž˜์— ์œ„์น˜ํ•œ UI๋“ค์€ Blocker๊ฐ€ ๋Œ€์‹  Raycast๋ฅผ ๋ฐ›๊ธฐ ๋•Œ๋ฌธ์— Event ๋ฐœ์ƒ์ด ๋ฐฉ์ง€๋œ๋‹ค.

 

+ ์ถ”๊ฐ€ ๊ฒ€์ƒ‰ (https://developer-talk.tistory.com/469)

 - Virtual Method๋ž€ ์ž์‹ ํด๋ž˜์Šค์—์„œ ๋ถ€๋ชจ Method์˜ Parameter ๋ฐ Return Type ์žฌ์ •์˜๋ฅผ ํ—ˆ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

 - C#์—์„œ Method ์žฌ์ •์˜๋ฅผ ํ—ˆ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ Method๋ฅผ Virtual ํ‚ค์›Œ๋“œ๋กœ ์„ ์–ธํ•œ๋‹ค. ์ด๋•Œ Virtual ํ‚ค์›Œ๋“œ๋กœ ์„ ์–ธ

   ๋œ Method๋ฅผ Virtual Method๋ผ๊ณ  ํ•œ๋‹ค.

 - ์ž์‹ ํด๋ž˜์Šค๋Š” Override ํ‚ค์›Œ๋“œ๋ฅผ ํ†ตํ•ด Property ๋˜๋Š” Method๋ฅผ ์žฌ์ •์˜ํ•œ๋‹ค.

 

๏ผƒ์ธ๋ฒคํ† ๋ฆฌ ์‹ค์Šต #1

  -  Layout Group Component๋ฅผ ํ†ตํ•ด Inventory Item์„ ๋ฐฐ์น˜๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.

     (Grid Layout Group, Horizontal Layout Group, Vertical Layout Group)

 

๏ผƒ ์ธ๋ฒคํ† ๋ฆฌ ์‹ค์Šต #2

abstract Method์ธ Init() ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•œ UI_Base ์ˆ˜์ •
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public abstract class UI_Base : MonoBehaviour
{
    protected Dictionary<Type, UnityEngine.Object[]> _objects = new Dictionary<Type, UnityEngine.Object[]>(); // Dictionary ์‚ฌ์šฉ

    public abstract void Init();

    // C#์˜ Reflection ๊ธฐ๋Šฅ์„ ํ†ตํ•ด enum์„ ํ•ด๋‹น ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ๋„˜๊ฒจ์ค„ ์ˆ˜ ์žˆ๋‹ค.
    // enum ๊ฐ’์„ ์ธ์ž๋กœ ๋„˜๊ฒจ์ฃผ๋ฉด enum ์•ˆ์˜ ์ด๋ฆ„์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ์ฐพ์•„ ์ž๋™์œผ๋กœ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ์—ญํ• ์„ ํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค.
    protected void Bind<T>(Type type) where T : UnityEngine.Object // using System;์„ ์ถ”๊ฐ€ํ•ด์•ผ Type ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
    {
        // ํ•ด๋‹น enum์— ์กด์žฌํ•˜๋Š” ๋ชจ๋“  ์ด๋ฆ„๋“ค์„ names์— ๋‹ด๋Š” ๊ฒƒ
        string[] names = Enum.GetNames(type); // String ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ (C#์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ)

        // Unity ๋ชจ๋“  ๊ฐ์ฒด์˜ ์ตœ์ƒ์œ„ ๋ถ€๋ชจ๊ฐ€ UnityEngine.Object
        UnityEngine.Object[] objects = new UnityEngine.Object[names.Length];
        _objects.Add(typeof(T), objects); // Dictionary์— ์ถ”๊ฐ€

        for (int i = 0; i < names.Length; i++)
        {
            if (typeof(T) == typeof(GameObject))
                objects[i] = Util.FindChild(gameObject, names[i], true);
            else
                objects[i] = Util.FindChild<T>(gameObject, names[i], true); // enum์— ์กด์žฌํ•˜๋Š” ์ด๋ฆ„์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ์ฐพ์•„ objects์— ์ €์žฅ
        }
    }

    // index๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„ ํ•ด๋‹นํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜
    protected T Get<T>(int idx) where T : UnityEngine.Object
    {
        // Key ๊ฐ’์„ ์ด์šฉํ•˜์—ฌ ์ถ”์ถœ
        UnityEngine.Object[] objects = null;
        if (_objects.TryGetValue(typeof(T), out objects) == false) // ๋งŒ์•ฝ ์ถ”์ถœ์— ์‹คํŒจํ•œ ๊ฒฝ์šฐ
            return null;

        return objects[idx] as T; // ์ถ”์ถœ์— ์„ฑ๊ณตํ•œ ๊ฒฝ์šฐ T๋กœ Castingํ•˜์—ฌ ๋ฐ˜ํ™˜ (objects๋Š” UnityEngine.Object ์ด๋ฏ€๋กœ)
    }

    // ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋“ค์€ ๊ตณ์ด Get์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋„๋ก
    protected Text GetText(int idx) { return Get<Text>(idx); }
    protected Button GetButton(int idx) { return Get<Button>(idx); }
    protected Image GetImage(int idx) { return Get<Image>(idx); }

    public static void AddUIEvent(GameObject go, Action<PointerEventData> action, Define.UIEvent type = Define.UIEvent.Click)
    {
        UI_EventHandler evt = Util.GetOrAddComponent<UI_EventHandler>(go);

        switch (type)
        {
            case Define.UIEvent.Click:
                evt.OnClickHandler -= action;
                evt.OnClickHandler += action;
                break;
            case Define.UIEvent.Drag:
                evt.OnDragHandler -= action;
                evt.OnDragHandler += action;
                break;
        }

        evt.OnDragHandler += ((PointerEventData data) => { evt.gameObject.transform.position = data.position; });
    }
}โ€‹

 

UI_Base๋ฅผ ์ƒ์†๋ฐ›๋Š” UI_Popup ์ˆ˜์ •
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UI_Popup : UI_Base
{
    public override void Init()
    {
        Managers.UI.SetCanvas(gameObject, true);
    }

    public virtual void ClosePopupUI()
    {
        Managers.UI.ClosePopupUI(this);
    }
}โ€‹

 

UI_Base๋ฅผ ์ƒ์†๋ฐ›๋Š” UI_Scene ์ˆ˜์ •
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UI_Scene : UI_Base
{
    public override void Init()
    {
        Managers.UI.SetCanvas(gameObject, false);
    }
}โ€‹

 

UI_Scene์„ ์ƒ์†๋ฐ›๋Š” UI_Inven ์ƒ์„ฑ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UI_Inven : UI_Scene
{
    enum GameObjects
    {
        GridPanel
    }

    // Start is called before the first frame update
    void Start()
    {
        Init();
    }

    public override void Init()
    {
        base.Init();

        Bind<GameObject>(typeof(GameObjects));

        GameObject gridPanel = Get<GameObject>((int)GameObjects.GridPanel);
        foreach (Transform child in gridPanel.transform)
            Managers.Resource.Destroy(child.gameObject);

        // ์‹ค์ œ ์ธ๋ฒคํ† ๋ฆฌ ์ •๋ณด๋ฅผ ์ฐธ๊ณ ํ•ด์„œ
        for (int i = 0; i < 8; i++)
        {
            GameObject item = Managers.Resource.Instantiate("UI/Scene/UI_Inven_Item");
            item.transform.SetParent(gridPanel.transform);

            UI_Inven_Item invenItem = Util.GetOrAddComponent<UI_Inven_Item>(item);
            invenItem.SetInfo($"์ง‘ํ–‰๊ฒ€{i}๋ฒˆ");
        }
    }
}โ€‹

 

UI_Base๋ฅผ ์ƒ์†๋ฐ›๋Š” UI_Inven_Item ์ƒ์„ฑ
 using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UI_Inven_Item : UI_Base
{
    enum GameObjects
    {
        ItemIcon,
        ItemNameText,
    }

    string _name;

    void Start()
    {
        Init();
    }

    public override void Init()
    {
        Bind<GameObject>(typeof(GameObjects));
        Get<GameObject>((int)GameObjects.ItemNameText).GetComponent<Text>().text = _name;
        Get<GameObject>((int)GameObjects.ItemIcon).AddUIEvent((PointerEventData) => { Debug.Log($"์•„์ดํ…œ ํด๋ฆญ! {_name}"); });
    }

    public void SetInfo(string name)
    {
        _name = name;
    }
}โ€‹

 

+ ์ถ”๊ฐ€ ๊ฒ€์ƒ‰ (https://eboong.tistory.com/63)

 - foreach๋ฌธ์€ ๋ฐฐ์—ด์„ ์ˆœํšŒํ•˜๋ฉด์„œ ๊ฐ๊ฐ์˜ ๋ฐ์ดํ„ฐ ์š”์†Œ๋“ค์— ์ˆœ์„œ๋Œ€๋กœ ์ ‘๊ทผํ•˜๋ฉฐ ๋ฐฐ์—ด์˜ ๋์— ๋„๋‹ฌํ•  ๊ฒฝ์šฐ ์ž๋™์œผ๋กœ ๋ฐ˜๋ณต์ด

   ์ข…๋ฃŒ๋œ๋‹ค.

 

+ ์ถ”๊ฐ€ ๊ฒ€์ƒ‰ (https://jshzizon.tistory.com/entry/C-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-%EC%B6%94%EC%83%81-%ED%95%A8%EC%88%98-%EC%B6%94%EC%83%81-%ED%81%B4%EB%9E%98%EC%8A%A4-Abstract-Mehtod-Abstract-Class)

 - Abstract Method๋Š” ๋ชธ์ฒด๊ฐ€ ์—†๋Š” ํ•จ์ˆ˜๋ฅผ ์˜๋ฏธํ•œ๋‹ค. Abstract Method ์‚ฌ์šฉ์‹œ ๋ชธ์ฒด ์•ž์— ๋ฐ˜๋“œ์‹œ abstract ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์—ฌ์•ผ 

  ํ•˜๋ฉฐ, ์ด๋Ÿฌํ•œ Abstract Method๋ฅผ 1๊ฐœ๋ผ๋„ ํฌํ•จํ•˜๊ณ  ์žˆ๋Š” Class ๋˜ํ•œ ๋ฐ˜๋“œ์‹œ abstract ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์—ฌ Abstract Class์ž„์„

  ๋ช…์‹œํ•ด์•ผ ํ•œ๋‹ค.

 - Abstract์œผ๋กœ ์„ ์–ธ๋œ Abstract Method๋Š” ์ƒ์† ๋ฐ›์€ ํ•˜์œ„ Class์—์„œ ๋ฐ˜๋“œ์‹œ Override ํ‚ค์›Œ๋“œ๋ฅผ ํ†ตํ•ด ์˜ค๋ฒ„๋ผ์ด๋”ฉ ํ•ด์ค€๋‹ค. 



[ ์„น์…˜ 8. Scene ]

๏ผƒ Scene Manager #1

Scene๊ณผ ๊ด€๋ จ๋œ enum์„ ์ถ”๊ฐ€ํ•œ Define ์ˆ˜์ •
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Define
{
    public enum Scene{
        Unknown,
        Login,
        Lobby,
        Game,
    }

    public enum UIEvent
    {
        Click,
        Drag,
    }

    public enum MouseEvent
    {
        Press,
        Click,
    }

    public enum CameraMode
    {
        QuaterView, 
    }
}โ€‹

 

BaseScene ์ƒ์„ฑ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public abstract class BaseScene : MonoBehaviour
{
    public Define.Scene SceneType {get; protected set;} = Define.Scene.Unknown;

    void Awake() {
        Init();
    }

    protected virtual void Init() {
        // Event System Component๋ฅผ ๋“ค๊ณ  ์žˆ๋Š” GameObject๋ฅผ ์ฐพ๋Š” ๊ฒƒ
        Object obj = GameObject.FindObjectOfType(typeof(EventSystem));
        if (obj == null)
            Managers.Resource.Instantiate("UI/EventSystem").name = "@EventSystem";
    }

    public abstract void Clear();
}โ€‹

 

BaseScene์„ ์ƒ์†๋ฐ›๋Š” GameScene ์ƒ์„ฑ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameScene : BaseScene
{
    protected override void Init() {
        base.Init();

        SceneType = Define.Scene.Game;

        Managers.UI.ShowSceneUI<UI_Inven>();
    }

    public override void Clear() {

    }
}โ€‹

 

BaseScene์„ ์ƒ์†๋ฐ›๋Š” LoginScene ์ƒ์„ฑ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LoginScene : BaseScene
{
    protected override void Init() {
        base.Init();

        SceneType = Define.Scene.Login;
    }
    
    public override void Clear() {

    }
}โ€‹

 

๏ผƒ Scene Manager #2

SceneManagerEx ์ถ”๊ฐ€
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class SceneManagerEx
{
    public BaseScene CurrentScene { get { return GameObject.FindObjectOfType<BaseScene>(); } }

    public void LoadScene(Define.Scene type) {
        CurrentScene.Clear();
        SceneManager.LoadScene(GetSceneName(type));
    }

    string GetSceneName(Define.Scene type) {
        // C#์˜ Reflection ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉ
        string name = System.Enum.GetName(typeof(Define.Scene), type);
        return name;
    }
}โ€‹

 

Managers์— SceneManagerEx ์ถ”๊ฐ€
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Managers : MonoBehaviour
{
    static Managers s_instance; // ์œ ์ผ์„ฑ ๋ณด์žฅ
    static Managers Instance { get { Init(); return s_instance; } } // ์œ ์ผํ•œ ๋งค๋‹ˆ์ €๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค

    InputManager _input = new InputManager();
    ResourceManager _resource = new ResourceManager();
    SceneManagerEx _scene = new SceneManagerEx();
    UIManager _ui = new UIManager();

    public static InputManager Input { get { return Instance._input; } }
    public static ResourceManager Resource { get { return Instance._resource; } }
    public static SceneManagerEx Scene {get { return Instance._scene; }}
    public static UIManager UI {  get { return Instance._ui; } }

    void Start()
    {
        Init();
    }

    void Update()
    {
        _input.OnUpdate();
    }

    static void Init()
    {
        // ์ดˆ๊ธฐํ™”
        if (s_instance == null) {
            GameObject go = GameObject.Find("Managers");
            if (go == null) {
                go = new GameObject { name = "Managers" };
                go.AddComponent<Managers>();
            }
            DontDestroyOnLoad(go);
            s_instance = go.GetComponent<Managers>();
        }
    }
}โ€‹

 

LoginScene ์ˆ˜์ •
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement; 

public class LoginScene : BaseScene
{
    protected override void Init() {
        base.Init();

        SceneType = Define.Scene.Login;
    }

    private void Update() {
        if (Input.GetKeyDown(KeyCode.Q)){
            Managers.Scene.LoadScene(Define.Scene.Game);
        }
    }
    
    public override void Clear() {
        Debug.Log("LoginScene Clear!");
    }
}โ€‹

 

+ ์ถ”๊ฐ€ ๊ฒ€์ƒ‰ (https://rucira-tte.tistory.com/115)

 - Find("~~")๋Š” Object์˜ ์ด๋ฆ„์„ ํ†ตํ•ด ์ฐพ๋Š” ํ•จ์ˆ˜, FindObjectOfType< ~~>()๋Š” Script ์ด๋ฆ„์„ ํ†ตํ•ด ์ฐพ๋Š” ํ•จ์ˆ˜, 

   FindGameObjectWithTag("~~")๋Š” Tag๋ฅผ ํ†ตํ•ด ์ฐพ๋Š” ํ•จ์ˆ˜์ด๋‹ค.


 
[ ์„น์…˜ 9. Sound ]

๏ผƒ Sound Manager #1

  - Sound๋ฅผ ์œ„ํ•ด์„œ๋Š” Sound๋ฅผ ์žฌ์ƒํ•˜๊ธฐ ์œ„ํ•œ Player, Sound๋ฅผ ์œ„ํ•œ ์Œ์›, ์ด๋ฅผ ๋“ฃ๋Š” ๊ด€๊ฐ ์ด 3๊ฐ€์ง€๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

  - ์ฐจ๋ก€๋Œ€๋กœ AudioSource, AudioClip, AudioListener๊ฐ€ ์œ„๋ฅผ ๋‹ด๋‹นํ•œ๋‹ค.

 

๏ผƒ Sound Manager #2

Sound์™€ ๊ด€๋ จ๋œ enum์„ ์ถ”๊ฐ€ํ•œ Define ์ˆ˜์ •
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Define
{
    public enum Scene{
        Unknown,
        Login,
        Lobby,
        Game,
    }
    
    public enum Sound
    {
        Bgm,
        Effect,
        MaxCount,
    }

    public enum UIEvent
    {
        Click,
        Drag,
    }

    public enum MouseEvent
    {
        Press,
        Click,
    }

    public enum CameraMode
    {
        QuaterView, 
    }
}โ€‹

 

SoundManager ์ถ”๊ฐ€
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SoundManager
{
    AudioSource[] _audioSources = new AudioSource[(int)Define.Sound.MaxCount];

    public void Init()
    {
        GameObject root = GameObject.Find("@Sound");
        if (root == null)
        {
            root = new GameObject { name = "@Sound" };
            Object.DontDestroyOnLoad(root);

            string[] soundNames = System.Enum.GetNames(typeof(Define.Sound));
            for (int i = 0; i < soundNames.Length - 1; i++)
            {
                GameObject go = new GameObject { name = soundNames[i] };
                _audioSources[i] = go.AddComponent<AudioSource>();
                go.transform.parent = root.transform; // UI๋Š” Rect Transform์ด๋ฏ€๋กœ SetParent๋ฅผ ์‚ฌ์šฉ, ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ์—๋Š” parent๋ฅผ ์‚ฌ์šฉ
            }

            _audioSources[(int)Define.Sound.Bgm].loop = true;
        }
    }

    public void Play(string path, Define.Sound type = Define.Sound.Effect, float pitch = 1.0f)
    {
        if (path.Contains("Sounds/") == false)
            path = $"Sounds/{path}";

        if (type == Define.Sound.Bgm)
        {
            AudioClip audioClip = Managers.Resource.Load<AudioClip>(path);
            if (audioClip == null)
            {
                Debug.Log($"AudioClip Missing! {path}");
                return;
            }

            AudioSource audioSource = _audioSources[(int)Define.Sound.Bgm];
            if (audioSource.isPlaying)
                audioSource.Stop();

            audioSource.pitch = pitch;
            audioSource.clip = audioClip;
            audioSource.Play();
        }
        else
        {
            AudioClip audioClip = Managers.Resource.Load<AudioClip>(path);
            if (audioClip == null)
            {
                Debug.Log($"AudioClip Missing! {path}");
                return;
            }

            AudioSource audioSource = _audioSources[(int)Define.Sound.Effect];
            audioSource.pitch = pitch;
            audioSource.PlayOneShot(audioClip);
        }
    }
}โ€‹

 

Manager์— SoundManager ์ถ”๊ฐ€ ๋ฐ SoundManager์˜ Init ํ•จ์ˆ˜ ์‹คํ–‰
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Managers : MonoBehaviour
{
    static Managers s_instance; // ์œ ์ผ์„ฑ ๋ณด์žฅ
    static Managers Instance { get { Init(); return s_instance; } } // ์œ ์ผํ•œ ๋งค๋‹ˆ์ €๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค

    InputManager _input = new InputManager();
    ResourceManager _resource = new ResourceManager();
    SceneManagerEx _scene = new SceneManagerEx();
    SoundManager _sound = new SoundManager();
    UIManager _ui = new UIManager();

    public static InputManager Input { get { return Instance._input; } }
    public static ResourceManager Resource { get { return Instance._resource; } }
    public static SceneManagerEx Scene {get { return Instance._scene; }}
    public static SoundManager Sound { get { return Instance._sound; }}
    public static UIManager UI {  get { return Instance._ui; } }

    void Start()
    {
        Init();
    }

    void Update()
    {
        _input.OnUpdate();
    }

    static void Init()
    {
        // ์ดˆ๊ธฐํ™”
        if (s_instance == null) {
            GameObject go = GameObject.Find("Managers");
            if (go == null) {
                go = new GameObject { name = "Managers" };
                go.AddComponent<Managers>();
            }
            DontDestroyOnLoad(go);
            s_instance = go.GetComponent<Managers>();

            s_instance._sound.Init();
        }
    }
}โ€‹

 

๏ผƒ Sound Manager #3

  - BGM ๋ณ€๊ฒฝ์€ ์ž์ฃผ ๋ฐœ์ƒํ•˜์ง€ ์•Š์•„ ์ž์ฃผ ์‹คํ–‰๋˜์ง€ ์•Š์œผ๋‚˜, Effect๋Š” ์ž์ฃผ ์‹คํ–‰๋œ๋‹ค. ์ด๋ฅผ ๊ฒฝ๋กœ๋ฅผ ํ†ตํ•ด ๋ถˆ๋Ÿฌ์˜ค๋Š” ๊ฒƒ์€

    ๋ถ€ํ•˜๋ฅผ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ Cashing์„ ํ†ตํ•ด ํ•ด๊ฒฐํ•˜๊ณ ์ž ํ•œ๋‹ค.

Cashing์„ ์œ„ํ•œ SoundManager ์ˆ˜์ •
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SoundManager
{
    AudioSource[] _audioSources = new AudioSource[(int)Define.Sound.MaxCount];
    Dictionary<string, AudioClip> _audioClips = new Dictionary<string, AudioClip>(); // Cashing์„ ์œ„ํ•œ Dictionary (๊ฒฝ๋กœ์™€ AudioClip์„ ๊ฐ€์ง)

    public void Init()
    {
        GameObject root = GameObject.Find("@Sound");
        if (root == null)
        {
            root = new GameObject { name = "@Sound" };
            Object.DontDestroyOnLoad(root);

            string[] soundNames = System.Enum.GetNames(typeof(Define.Sound));
            for (int i = 0; i < soundNames.Length - 1; i++)
            {
                GameObject go = new GameObject { name = soundNames[i] };
                _audioSources[i] = go.AddComponent<AudioSource>();
                go.transform.parent = root.transform; // UI๋Š” Rect Transform์ด๋ฏ€๋กœ SetParent๋ฅผ ์‚ฌ์šฉ, ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ์—๋Š” parent๋ฅผ ์‚ฌ์šฉ
            }

            _audioSources[(int)Define.Sound.Bgm].loop = true;
        }
    }

    public void Clear() // ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด Scene ์ด๋™์‹œ ์ดˆ๊ธฐํ™”ํ•˜๊ธฐ ์œ„ํ•œ ํ•จ์ˆ˜
    {
        foreach (AudioSource audioSource in _audioSources)
        {
            audioSource.clip = null;
            audioSource.Stop();
        }
        _audioClips.Clear();
    }

    public void Play(string path, Define.Sound type = Define.Sound.Effect, float pitch = 1.0f)
    {
        if (path.Contains("Sounds/") == false)
            path = $"Sounds/{path}";

        if (type == Define.Sound.Bgm)
        {
            AudioClip audioClip = Managers.Resource.Load<AudioClip>(path);
            if (audioClip == null)
            {
                Debug.Log($"AudioClip Missing! {path}");
                return;
            }

            AudioSource audioSource = _audioSources[(int)Define.Sound.Bgm];
            if (audioSource.isPlaying)
                audioSource.Stop();

            audioSource.pitch = pitch;
            audioSource.clip = audioClip;
            audioSource.Play();        
        }
        else
        {
            AudioClip audioClip = GetOrAddAudioClip(path);
            if (audioClip == null)
            {
                Debug.Log($"AudioClip Missing! {path}");
                return;
            }

            AudioSource audioSource = _audioSources[(int)Define.Sound.Effect];
            audioSource.pitch = pitch;
            audioSource.PlayOneShot(audioClip);
        }
    }

    AudioClip GetOrAddAudioClip(string path) // Cashing์„ ์œ„ํ•œ ํ•จ์ˆ˜
    {
        AudioClip audioClip = null;
        if (_audioClips.TryGetValue(path, out audioClip) == false)
        {
            audioClip = Managers.Resource.Load<AudioClip>(path);
            _audioClips.Add(path, audioClip);
        }
        return audioClip;
    }
}โ€‹

 

+ ์ถ”๊ฐ€ ๊ฒ€์ƒ‰

 - Dictionary๋Š” ํŠน์ • Key๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์‚ญ์ œํ•˜๋Š” Remove() Method์™€ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์‚ญ์ œํ•˜๋Š” Clear() Method๋ฅผ 

   ์ œ๊ณตํ•œ๋‹ค.

 - Dictionary๋Š” ํŠน์ • Key๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๋Š”์ง€์˜ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ContainsKey() Method์™€ TryGetValue() Method๋ฅผ

   ์ œ๊ณตํ•œ๋‹ค. ์ด๋•Œ out Keyword๋ฅผ ํ†ตํ•ด ๋ณ„๋„์˜ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜์ง€ ์•Š์•„๋„ ๋ฐ˜ํ™˜๊ฐ’์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

   (๋‘˜ ๋‹ค ๋ฐ˜ํ™˜๊ฐ’์€ Bool Type์ด๋ฉฐ, TryGetValue() Method๊ฐ€ ๋” ํšจ์œจ์ ) 

 

๏ผƒ Sound Manager #4

  - Audio Source Component์˜ Spatial Blend๋ฅผ 2D์—์„œ 3D๋กœ ๋ณ€๊ฒฝํ•  ๊ฒฝ์šฐ 3D Sound๋ฅผ ์ง€์›ํ•œ๋‹ค.

    (ํ•ด๋‹น Object ์ž์ฒด๊ฐ€ ์†Œ๋ฆฌ์˜ ์ง„์›์ง€๊ฐ€ ๋˜๋Š” ๊ฒƒ)

  - PlayClipAtPoint(AudioClip, Vector3) Method๋ฅผ ํ†ตํ•ด ํŠน์ • ์ขŒํ‘œ์—์„œ Sound๋ฅผ ์žฌ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.


 
[ ์„น์…˜ 10. Object Pooling ]

๏ผƒ Pool Manager #1

  - Object๋ฅผ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ํŒŒ๊ดดํ•˜๋Š” ์ž‘์—…์€ ๊ฝค๋‚˜ ๋ฌด๊ฑฐ์šด ์ž‘์—…์œผ๋กœ ๋ถ„๋ฅ˜๋œ๋‹ค. Object ์ƒ์„ฑ์€ Memory๋ฅผ ์ƒˆ๋กœ ํ• ๋‹นํ•˜๊ณ  

    Resource๋ฅผ Loadํ•˜๋Š” ๋“ฑ์˜ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๊ณผ์ •์œผ๋กœ, Object ํŒŒ๊ดด๋Š” ํŒŒ๊ดด ์ดํ›„์— ๋ฐœ์ƒํ•˜๋Š” Garbage Collecting์œผ๋กœ ์ธํ•œ

    Frame Drop์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

  - ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ๊ธฐ๋ฒ•์ด Object Pooling์ด๋‹ค.

  - Poolingํ•  Object๋ฅผ ๋‹ด์€ Object Pool์„ ๊ตฌ์„ฑํ•œ ๋’ค ์™ธ๋ถ€์—์„œ ํ•ด๋‹น Object๊ฐ€ ํ•„์š”ํ•˜๋ฉด Object Pool์—์„œ ๊บผ๋‚ด ์‚ฌ์šฉํ•œ๋‹ค.

  - Object Pool์—์„œ ๊บผ๋‚ธ Object์˜ ์‚ฌ์šฉ์ด ๋๋‚˜๋ฉด Object๋ฅผ Pool์— ๋Œ๋ ค์ค€๋‹ค.

  - ๋งŒ์•ฝ Object Pool์—์„œ Object๋ฅผ ๊ฐ€์ ธ์˜ค๋ ค๊ณ  ํ•  ๋•Œ, ๋ชจ๋“  Object๊ฐ€ ์ด๋ฏธ ์‚ฌ์šฉ์ค‘์ด๋ผ๋ฉด ์ƒˆ๋กœ์šด Object๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

 

+ ์ถ”๊ฐ€ ๊ฒ€์ƒ‰ (https://wergia.tistory.com/203)

 

๏ผƒ Pool Manager #2

  - Poolable Script๋ฅผ Component๋กœ ๋“ค๊ณ  ์žˆ๋‹ค๋ฉด Memory Pooling ๋Œ€์ƒ์ด ๋œ๋‹ค.

 Poolable ์ƒ์„ฑ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Poolable : MonoBehaviour
{
    // Poolable Script๋ฅผ Component๋กœ ๋“ค๊ณ  ์žˆ๋‹ค๋ฉด Memory Pooling ๋Œ€์ƒ์ด ๋œ๋‹ค.
    public bool IsUsing; // ํ˜„์žฌ Pooling์ด ๋œ ์ƒํƒœ์ธ์ง€
}โ€‹

 

PoolManager ์ƒ์„ฑ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PoolManager
{
    #region Pool
    class Pool{
        public GameObject Original {get; private set;}
        public Transform Root {get; set;}

        Stack<Poolable> _poolStack = new Stack<Poolable>();

        public void Init(GameObject original, int count = 5){
            Original = original
            Root = new GameObject().transform;
            Root.name = $"{original.name}_Root";

            for (int i = 0; i < count; i++)
                Push(Create());
        }

        Poolable Create() {
            GameObject go = object.Instantiate<GameObject>(Original);
            go.name = Original.name;
            return go.GetOrAddComponent<Pollable>();
        }

        public void Push(Poolable poolable) {
            if (poolable == null)
                return;
            
            poolable.transform.parent = Root;
            poolable.gamoObject.SetActive(false);
            poolable.IsUsing = false;

            _poolStack.Push(poolable);
        }

        public Poolable Pop(Transform parent) {
            Poolable poolable;

            if (_poolStack.Count > 0)
                poolable = _poolStack.Pop();
            else
                poolable = Create();

            poolable.gameObject.SetActive(true);
            poolable.transform.parent = parent;
            poolable.IsUsing = true;

            return poolable;
        }
    }
    #endregion

    // PoolManager๋Š” ์—ฌ๋Ÿฌ๊ฐœ์˜ Pool์„ ๊ฐ€์ง€๋ฉฐ ๊ฐ๊ฐ์˜ Pool๋“ค์€ ์ด๋ฆ„์„ ํ†ตํ•ด ๊ด€๋ฆฌ๋ฅผ ํ•  ๊ฒƒ์ด๋‹ค.
    Dictionary<string, Pool> _pool = new Dictionary<string, Pool>();

    Transform _root;
    // Pool๋“ค์˜ Root๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ (๋Œ€๊ธฐ์‹ค ์—ญํ• )
    public void Init() {
        if (_root == null) {
            _root = new GameObject { name = "@Pool_Root" }.transform;
            object.DontDestroyOnLoad(_root);
        }
    }

    public void CreatePool(GameObject original, int count = 5) {
        Pool pool = new Pool();
        pool.Init(original, count);
        pool.Root.parent = _root;

        _pool.Add(original.name, pool);
    }

    // Pool์— Object๋ฅผ ์ง‘์–ด๋„ฃ๋Š” ๊ฒƒ
    public void Push(Poolable poolable) {
        string name = poolable.gameObject.name;
        if(_pool.ContainsKey(name) == false) {
            GameObject.Destroy(poolable.gameObject);
            return;
        }

        _pool[name].Push(poolable);
    }

    public Poolable Pop(GameObject original, Transform parent = null) {
        if (_pool.ContainsKey(original.name) == false)
            CreatePool(original);
        return _pool[original.name].Pop(parent);
    }

    public GameObject GetOriginal(string name) {
        if (_pool.ContainsKey(name) == false)
            return null;
        return _pool[name].Original;
    }

    public void Clear() {
        foreach (Transform child in _root)
            GameObject.Destroy(child.gameObject);
        
        _pool.Clear();
    }
}โ€‹

 

Manager์— PoolManager ์ถ”๊ฐ€
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Managers : MonoBehaviour
{
    static Managers s_instance; // ์œ ์ผ์„ฑ ๋ณด์žฅ
    static Managers Instance { get { Init(); return s_instance; } } // ์œ ์ผํ•œ ๋งค๋‹ˆ์ €๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค

    InputManager _input = new InputManager();
    PoolManager _pool = new PoolManager();
    ResourceManager _resource = new ResourceManager();
    SceneManagerEx _scene = new SceneManagerEx();
    SoundManager _sound = new SoundManager();
    UIManager _ui = new UIManager();

    public static InputManager Input { get { return Instance._input; } }
    public static PoolManager Pool { get { return Instance._pool; } }
    public static ResourceManager Resource { get { return Instance._resource; } }
    public static SceneManagerEx Scene {get { return Instance._scene; }}
    public static SoundManager Sound { get { return Instance._sound; }}
    public static UIManager UI {  get { return Instance._ui; } }

    void Start()
    {
        Init();
    }

    void Update()
    {
        _input.OnUpdate();
    }

    static void Init()
    {
        // ์ดˆ๊ธฐํ™”
        if (s_instance == null) {
            GameObject go = GameObject.Find("Managers");
            if (go == null) {
                go = new GameObject { name = "Managers" };
                go.AddComponent<Managers>();
            }
            DontDestroyOnLoad(go);
            s_instance = go.GetComponent<Managers>();

            s_instance._sound.Init();
        }
    }

    public static void Clear()
    {
        Input.Clear();
        Sound.Clear();
        Scene.Clear();
        UI.Clear();
    }
}โ€‹

 

+ ์ถ”๊ฐ€ ๊ฒ€์ƒ‰  (https://crazykim2.tistory.com/540)

 - C#์€ #region๊ณผ #endregion์„ ํ†ตํ•ด ์ฝ”๋“œ๋ฅผ ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

 - #region๊ณผ #endregion ์˜†์— Comment๋ฅผ ๋ถ™์—ฌ ๋ถ€๊ฐ€ ์„ค๋ช…์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

+ ์ถ”๊ฐ€ ์ •๋ฆฌ

๏ผƒ Pool Manager #3

PoolManager๋ฅผ ํ†ตํ•œ ResourceManager ์ˆ˜์ •
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ResourceManager
{
    public T Load<T>(string path) where T : Object
    {
        if(typeof(T) == typeof(GameObject)) { // ๋งŒ์•ฝ ๊ฐ™๋‹ค๋ฉด Prefab์ผ ํ™•๋ฅ ์ด ๋†’๋‹ค.
            string name = path;
            int index = name.LastIndexOf('/');
            if (index >= 0)
                name = name.Substring(index + 1);

            GameObject go = Managers.Pool.GetOriginal(name);
            if (go != null)
                return go as T;
        }

        return Resources.Load<T>(path);
    }

    public GameObject Instantiate(string path, Transform parent = null)
    {
        GameObject original = Load<GameObject>($"Prefabs/{path}");
        if (original == null)
        {
            Debug.Log($"Failed to load prefab : {path}");
            return null;
        }

        if(original.GetComponent<Poolable>() != null) // ๋งŒ์•ฝ ํ•ด๋‹น GameObject๊ฐ€ Pooling ๋Œ€์ƒ์ด๋ผ๋ฉด Pool์—์„œ ๊บผ๋‚ด์˜จ๋‹ค.   
            return Managers.Pool.Pop(original, parent).gameObject;    

        GameObject go = Object.Instantiate(original, parent);
        go.name = original.name;
        return go;
    }

    public void Destroy(GameObject go)
    {
        if (go == null)
            return;

        Poolable poolable = go.GetComponent<Poolable>();
        if (poolable != null) { // ๋งŒ์•ฝ ํ•ด๋‹น GameObject๊ฐ€ Pooling ๋Œ€์ƒ์ด๋ผ๋ฉด ๋‹ค์‹œ Pool์— ์ง‘์–ด๋„ฃ๋Š”๋‹ค.
            Managers.Pool.Push(poolable);
            return;
        }

        Object.Destroy(go);
    }
}

 

DontDestroyOnLoad ํ•ด์ œ๋ฅผ ์œ„ํ•œ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ PoolManager ์ˆ˜์ •
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PoolManager
{
    #region Pool
    class Pool{
        public GameObject Original {get; private set;} // Pool ์•ˆ์— ์ƒ์„ฑํ•  GameObject
        public Transform Root {get; set;} // Pool์˜ Root

        Stack<Poolable> _poolStack = new Stack<Poolable>();

        public void Init(GameObject original, int count = 5){
            Original = original;
            Root = new GameObject().transform;
            Root.name = $"{original.name}_Root";

            for (int i = 0; i < count; i++)
                Push(Create());
        }

        Poolable Create() {
            GameObject go = Object.Instantiate<GameObject>(Original); // GameObject๋ฅผ ๋™์ ์œผ๋กœ ์ƒ์„ฑ
            go.name = Original.name;
            return go.GetOrAddComponent<Poolable>();
        }

        public void Push(Poolable poolable) {
            if (poolable == null)
                return;
            
            poolable.transform.parent = Root;
            poolable.gameObject.SetActive(false);
            poolable.IsUsing = false;

            _poolStack.Push(poolable);
        }

        public Poolable Pop(Transform parent) {
            Poolable poolable;

            if (_poolStack.Count > 0)
                poolable = _poolStack.Pop();
            else
                poolable = Create();

            poolable.gameObject.SetActive(true);

            // DontDestroyOnLoad ํ•ด์ œ ์šฉ๋„
            if (parent == null)
                poolable.transform.parent = Managers.Scene.CurrentScene.transform;

            poolable.transform.parent = parent;
            poolable.IsUsing = true;

            return poolable;
        }
    }
    #endregion

    // PoolManager๋Š” ์—ฌ๋Ÿฌ๊ฐœ์˜ Pool์„ ๊ฐ€์ง€๋ฉฐ ๊ฐ๊ฐ์˜ Pool๋“ค์€ ์ด๋ฆ„์„ ํ†ตํ•ด ๊ด€๋ฆฌ๋ฅผ ํ•  ๊ฒƒ์ด๋‹ค.
    Dictionary<string, Pool> _pool = new Dictionary<string, Pool>();

    Transform _root;
    // Pool๋“ค์˜ Root๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ (๋Œ€๊ธฐ์‹ค ์—ญํ• )
    public void Init() {
        if (_root == null) {
            _root = new GameObject { name = "@Pool_Root" }.transform;
            Object.DontDestroyOnLoad(_root);
        }
    }

    public void CreatePool(GameObject original, int count = 5) {
        Pool pool = new Pool();
        pool.Init(original, count);
        pool.Root.parent = _root;

        _pool.Add(original.name, pool);
    }

    // Pool์— Object๋ฅผ ์ง‘์–ด๋„ฃ๋Š” ๊ฒƒ
    public void Push(Poolable poolable) {
        string name = poolable.gameObject.name;
        if(_pool.ContainsKey(name) == false) {
            GameObject.Destroy(poolable.gameObject);
            return;
        }

        _pool[name].Push(poolable);
    }

    public Poolable Pop(GameObject original, Transform parent = null) {
        if (_pool.ContainsKey(original.name) == false)
            CreatePool(original);
        return _pool[original.name].Pop(parent);
    }

    public GameObject GetOriginal(string name) {
        if (_pool.ContainsKey(name) == false)
            return null;
        return _pool[name].Original;
    }

    public void Clear() {
        foreach (Transform child in _root)
            GameObject.Destroy(child.gameObject);
        
        _pool.Clear();
    }
}โ€‹

 


 
[ ์„น์…˜ 11. Coroutine ]

๏ผƒ Coroutine #1

  - Coroutine์„ ํ†ตํ•ด ํ•จ์ˆ˜์˜ ์ƒํƒœ๋ฅผ ์ €์žฅ/๋ณต์›ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ์›ํ•˜๋Š” ํƒ€์ด๋ฐ์— ํ•จ์ˆ˜๋ฅผ ์ž ์‹œ ์ค‘๋‹จ/๋ณต์›์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

  - Coroutine์„ ํ†ตํ•ด ์‹œ๊ฐ„ ๊ด€๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค. (Ex : ๋ช‡ ์ดˆ ํ›„ ์‹คํ–‰)

 

+ ์ถ”๊ฐ€ ๊ฒ€์ƒ‰  (https://codeposting.tistory.com/entry/Unity-%EC%9C%A0%EB%8B%88%ED%8B%B0-%EC%BD%94%EB%A3%A8%ED%8B%B4-%EC%82%AC%EC%9A%A9%EB%B2%95-%EC%A0%95%EC%A7%80-Coroutine-%EC%9D%B4%EC%9C%A0-%EC%B5%9C%EC%A0%81%ED%99%94)

 - Coroutine์ด๋ž€ ์ฝ”๋“œ ๋‚ด์—์„œ ๊ตฌ๋ฌธ ์‹คํ–‰ ๋„์ค‘์— ์ฒ˜๋ฆฌ๋ฅผ ๋Œ€๊ธฐ์‹œํ‚ค๊ฑฐ๋‚˜ ์ˆœ์ฐจ ์ฒ˜๋ฆฌ์— ํ•จ์ˆ˜๋ฅผ ๋ณ‘๋ ฌ๋กœ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก

   ๋งŒ๋“ค์–ด ์ค€๋‹ค. (Thread์™€๋Š” ๋‹ค๋ฅธ ๊ฐœ๋…)

 - Coroutine์€ IEnumerator ํ˜•ํƒœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์ด๋ฉฐ, yield Keyword๋ฅผ ํ†ตํ•ด return์„ ํ•„์ˆ˜์ ์œผ๋กœ ํ•ด์•ผํ•œ๋‹ค.

 

๏ผƒ Coroutine #2

Coroutine ์˜ˆ์ œ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CoroutineEx : MonoBehaviour
{
    Coroutine co;
    
    void Awake()
    {
    	co = StartCoroutine("ExplodeAfterSeconds", 4.0f);
        StartCoroutine("StopExplode", 2.0f);
    }
    
    IEnumerator ExplodeAfterSeconds(float seconds)
    {
    	Debug.Log("Explode Enter");
        yield return new WaitForSeconds(seconds);
        Debug.Log("Explode Execute!");
    }
    
    IEnumerator StopExplode(float seconds)
    {
    	Debug.Log("Stop Enter");
        yield return new WaitForSeconds(seconds);
        Debug.Log("Stop Execute!");
        if (co != null)
        {
            Stopcoroutine(co);
            co = null;
        }
    }
}

 
[ ์„น์…˜ 12. Data ]

๏ผƒ Data Manager #1

  - ๋ณดํ†ต Assets/Resources/Data ๊ฒฝ๋กœ์— Data ํŒŒ์ผ๋“ค์„ ์ €์žฅํ•œ๋‹ค.

  - json ํŒŒ์ผ์€ Unity์—์„œ [ ์˜ค๋ฅธ์ชฝ ๋งˆ์šฐ์Šค ] - [ Create ] ๋ฅผ ํ†ตํ•ด ๋งŒ๋“ค ์ˆ˜ ์—†๊ณ  ์•„๋ž˜์™€ ๊ฐ™์ด ๋งŒ๋“ ๋‹ค.

Resources ํด๋” ์„ ํƒ ํ›„ [ ์˜ค๋ฅธ์ชฝ ๋งˆ์šฐ์Šค ] - [ Show In Explorer ] -> Resources/Data ๊ฒฝ๋กœ์— [ ์˜ค๋ฅธ์ชฝ ๋งˆ์šฐ์Šค ] - [ ์ƒˆ๋กœ ๋งŒ๋“ค๊ธฐ ] - [ ํ…์ŠคํŠธ ๋ฌธ์„œ ]  -> ํ™•์žฅ์ž๋ฅผ txt์—์„œ json์œผ๋กœ ์ˆ˜์ •

 

  - json์—์„œ []๋Š” ๋ฆฌ์ŠคํŠธ๋ฅผ, {}๋Š” ๊ตฌ์กฐ์ฒด๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค.

  - json ํŒŒ์ผ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  Class๋Š” ๋ฐ˜๋“œ์‹œ [Serializable]์„ ๋ถ™์—ฌ์ค˜์•ผ ํ•˜๋ฉฐ, ๋˜ํ•œ ํ•ด๋‹น Class์˜ ๋ณ€์ˆ˜ ์—ญ์‹œ public ๋˜๋Š”

    [SerializeField]๋ฅผ ๋ถ™์—ฌ์ค˜์•ผ ํ•œ๋‹ค. ์ด๋•Œ Class์˜ ๋ณ€์ˆ˜๋ช…์ด json ํŒŒ์ผ์˜ ๊ตฌ์กฐ์ฒด ์•ˆ ๋ณ€์ˆ˜๋ช…๊ณผ ๊ฐ™์•„์•ผ ํ•œ๋‹ค. 

Stat๊ณผ ๊ด€๋ จ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” StatData๋ฅผ json ํŒŒ์ผ๋กœ ์ƒ์„ฑ
{
    "stats": [
        {
            "level": "1",
            "hp": "100",
            "attack": "10"
        },
        {
            "level": "2",
            "hp": "150",
            "attack": "15"
        },
        {
            "level": "3",
            "hp": "200",
            "attack": "20"
        }
    ]
}โ€‹

 

DataManager ์ƒ์„ฑ
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[Serializable]
public class Stat {
    public int level;
    public int hp;
    public int attack;
}

[Serializable]
public class StatData {
    public List<Stat> stats = new List<Stat>();
}

public class DataManager
{
    public void Init() {
        // StatData.json ํŒŒ์ผ์„ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ์œ„ํ•œ ๊ฒƒ
        TextAsset textAsset = Managers.Resource.Load<TextAsset>($"Data/StatData");

        // Unity์—์„œ ์ œ๊ณตํ•˜๋Š” json Parsing
        StatData data = JsonUtility.FromJson<StatData>(textAsset.text);
    }
}โ€‹

 

Manager์— DataManager ์ถ”๊ฐ€
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Managers : MonoBehaviour
{
    static Managers s_instance; // ์œ ์ผ์„ฑ ๋ณด์žฅ
    static Managers Instance { get { Init(); return s_instance; } } // ์œ ์ผํ•œ ๋งค๋‹ˆ์ €๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค

    DataManager _data = new DataManager();
    InputManager _input = new InputManager();
    PoolManager _pool = new PoolManager();
    ResourceManager _resource = new ResourceManager();
    SceneManagerEx _scene = new SceneManagerEx();
    SoundManager _sound = new SoundManager();
    UIManager _ui = new UIManager();

    public static DataManager Data { get { return Instance._data; }}
    public static InputManager Input { get { return Instance._input; } }
    public static PoolManager Pool { get { return Instance._pool; } }
    public static ResourceManager Resource { get { return Instance._resource; } }
    public static SceneManagerEx Scene {get { return Instance._scene; }}
    public static SoundManager Sound { get { return Instance._sound; }}
    public static UIManager UI {  get { return Instance._ui; } }

    void Start()
    {
        Init();
    }

    void Update()
    {
        _input.OnUpdate();
    }

    static void Init()
    {
        // ์ดˆ๊ธฐํ™”
        if (s_instance == null) {
            GameObject go = GameObject.Find("Managers");
            if (go == null) {
                go = new GameObject { name = "Managers" };
                go.AddComponent<Managers>();
            }
            DontDestroyOnLoad(go);
            s_instance = go.GetComponent<Managers>();

            s_instance._data.Init();
            s_instance._pool.Init();
            s_instance._sound.Init();
        }
    }

    public static void Clear()
    {
        Input.Clear();
        Sound.Clear();
        Scene.Clear();
        UI.Clear();
        Pool.Clear();
    }
}โ€‹

 

๏ผƒ Data Manager #2

DataManager ์ˆ˜์ •
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface ILoader<Key, Value> 
{
    Dictionary<Key, Value> MakeDict();
}

public class DataManager
{
    public Dictionary<int, Stat> StatDict { get; private set; } = new Dictionary<int, Stat>();

    public void Init() 
    {
        StatDict = LoadJson<StatData, int, Stat>("StatData").MakeDict();
    }

    Loader LoadJson<Loader, Key, Value>(string path) where Loader : ILoader<Key, Value>
    {
        // json ํŒŒ์ผ์„ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ์œ„ํ•œ ๊ฒƒ
        TextAsset textAsset = Managers.Resource.Load<TextAsset>($"Data/{path}");

        // Unity์—์„œ ์ œ๊ณตํ•˜๋Š” json Parsing
        return JsonUtility.FromJson<Loader>(textAsset.text);
    }
}โ€‹

 

Data.Contents ์ƒ์„ฑ
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

#region Stat

[Serializable]
public class Stat
{
    public int level;
    public int hp;
    public int attack;
}

[Serializable]
public class StatData : ILoader<int, Stat>
{
    public List<Stat> stats = new List<Stat>();

    public Dictionary<int, Stat> MakeDict()
    {
        Dictionary<int, Stat> dict = new Dictionary<int, Stat>();
        foreach(Stat stat in stats)
            dict.Add(stat.level, stat);
        return dict;
    }
}

#endregionโ€‹

 

+ ์ถ”๊ฐ€ ๊ฒ€์ƒ‰  (https://seroi-programming.tistory.com/entry/C-%EC%96%B8%EC%96%B4-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%EC%82%AC%EC%9A%A9-%EB%B0%A9%EB%B2%95)

 - Interface๋Š” ๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํ•ต์‹ฌ ๊ฐœ๋… ์ค‘ ํ•˜๋‚˜์ด๋‹ค.

 - Interface๋Š” Class์™€ ๋น„์Šทํ•˜์ง€๋งŒ, Class์™€ ๋‹ฌ๋ฆฌ ๊ตฌํ˜„๋˜์ง€ ์•Š์€ Method์™€ Property๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค.

 - Interface๋Š” ์ ‘๊ทผ ์ œํ•œ ํ•œ์ •์ž๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ณ , ๋ชจ๋“  ๊ฒƒ์ด public์œผ๋กœ ์„ ์–ธ๋œ๋‹ค.

 - Interface๋Š” Class๊ฐ€ ๋”ฐ๋ผ์•ผํ•˜๋Š” ๊ทœ์•ฝ์„ ์ •์˜ํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋˜๋ฉฐ, Class๋Š” Interface์— ์ •์˜๋œ ๋ชจ๋“  ๋ฉค๋ฒ„๋ฅผ ๊ตฌํ˜„ํ•ด์•ผํ•œ๋‹ค.

 - Interface๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” Class๋Š” Class ์ด๋ฆ„ ๋’ค์— ์ฝœ๋ก (:)์„ ๋ถ™์ด๊ณ  ๊ตฌํ˜„ํ•˜๊ณ ์ž ํ•˜๋Š” Interface์˜ ์ด๋ฆ„์„ ์ง€์ •ํ•œ๋‹ค.

 - Interface๋Š” Instance๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์—†์ง€๋งŒ, Interface๋ฅผ ์ƒ์†๋ฐ›๋Š” Class์˜ Instance๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ๊ฐ€๋Šฅํ•˜๋‹ค.

 - Class๋Š” ์—ฌ๋Ÿฌ๊ฐœ์˜ Interface๋ฅผ ์ƒ์†๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

 

'๐Ÿ“‚ Unity Engine Study > ๐Ÿ“„ Unity ์ธํ”„๋Ÿฐ ๊ฐ•์˜' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

์ธํ”„๋Ÿฐ ๊ฐ•์˜ - [์‹ค์ „ ๊ฒŒ์ž„ ์ฝ”๋“œ ๋ฆฌ๋ทฐ] ์œ ๋‹ˆํ‹ฐ ์บ์ฃผ์–ผ ๊ฒŒ์ž„ (์—˜๋ฆฌ์ŠคํŒก) (์„น์…˜ 0~1)  (0) 2024.04.21
์ธํ”„๋Ÿฐ ๊ฐ•์˜ - Part4: ๊ฒŒ์ž„ ์„œ๋ฒ„ (์„น์…˜ 3 ~ 5)  (0) 2024.02.18
์ธํ”„๋Ÿฐ ๊ฐ•์˜ - Part4: ๊ฒŒ์ž„ ์„œ๋ฒ„ (์„น์…˜ 0 ~ 2)  (0) 2024.02.12
์ธํ”„๋Ÿฐ ๊ฐ•์˜ - Part3: ์œ ๋‹ˆํ‹ฐ ์—”์ง„ ๋‚ด์šฉ ์ •๋ฆฌ (์„น์…˜ 13)  (0) 2024.02.03
์ธํ”„๋Ÿฐ ๊ฐ•์˜ - Part3: ์œ ๋‹ˆํ‹ฐ ์—”์ง„ ๋‚ด์šฉ ์ •๋ฆฌ (์„น์…˜ 0 ~ 6)  (0) 2024.01.04
'๐Ÿ“‚ Unity Engine Study/๐Ÿ“„ Unity ์ธํ”„๋Ÿฐ ๊ฐ•์˜' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • ์ธํ”„๋Ÿฐ ๊ฐ•์˜ - Part4: ๊ฒŒ์ž„ ์„œ๋ฒ„ (์„น์…˜ 3 ~ 5)
  • ์ธํ”„๋Ÿฐ ๊ฐ•์˜ - Part4: ๊ฒŒ์ž„ ์„œ๋ฒ„ (์„น์…˜ 0 ~ 2)
  • ์ธํ”„๋Ÿฐ ๊ฐ•์˜ - Part3: ์œ ๋‹ˆํ‹ฐ ์—”์ง„ ๋‚ด์šฉ ์ •๋ฆฌ (์„น์…˜ 13)
  • ์ธํ”„๋Ÿฐ ๊ฐ•์˜ - Part3: ์œ ๋‹ˆํ‹ฐ ์—”์ง„ ๋‚ด์šฉ ์ •๋ฆฌ (์„น์…˜ 0 ~ 6)
YeonSu02
YeonSu02
Email : rkddustn2519@naver.com
  • YeonSu02
    IsLiife2
    YeonSu02
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ
      • ๐Ÿ“‚ Computer Science
      • ๐Ÿ“‚ Unity Engine Study
        • ๐Ÿ“„ Unity ์ธํ”„๋Ÿฐ ๊ฐ•์˜
        • ๐Ÿ“„ Unity ์œ ํŠœ๋ธŒ ๊ฐ•์˜
        • ๐Ÿ“„ Unity ์ฐธ๊ณ 
      • ๐Ÿ“‚ Game Designer Study
        • ๐Ÿ“„ ๊ธฐํš ์ธํ”„๋Ÿฐ ๊ฐ•์˜
      • ๐Ÿ“‚ Quality Assurance Study
        • ๐Ÿ”ฅ ์—˜๋ฆฌ์Šค SW QAํŠธ๋ž™
        • ๐Ÿ“„ QA ๊ณต๋ถ€
        • ๐Ÿ“š QA ์ฑ… ๋ฆฌ๋ทฐ
      • ๐Ÿ“‚ Program Language Study
        • ๐Ÿ“„ C# ๊ณต๋ถ€
        • ๐Ÿ“„ ํŒŒ์ด์ฌ ๊ณต๋ถ€
        • ๐Ÿ“„ Java ๊ณต๋ถ€
        • ๐Ÿ“„ JavaScript ๊ณต๋ถ€
      • ๐Ÿ“‚ Additional Study
        • ๐Ÿ“„ Git
        • ๐Ÿ“„ Firebase
        • ๐Ÿ“„ License
      • ๐Ÿ’ป Game Development
  • ๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

    • ํ™ˆ
  • ๋งํฌ

    • GitHub
  • ๊ณต์ง€์‚ฌํ•ญ

  • ์ธ๊ธฐ ๊ธ€

  • ํƒœ๊ทธ

    ์ •์ฒ˜๊ธฐ
    ์ •์ฒ˜๊ธฐ ๋…ํ•™
    qa์ž๊ฒฉ์ฆ
    ์ปดํ™œ
    BTS
    QA
    ์ž๊ฒฉ์ฆ
    ์ปดํ“จํ„ฐํ™œ์šฉ๋Šฅ๋ ฅ
    qa ์ฑ…
    ์ปดํ“จํ„ฐํ™œ์šฉ๋Šฅ๋ ฅ2๊ธ‰
    istqb-ctfl
    ISTQB
    ๊ตญ์ œ์ž๊ฒฉ์ฆ
    ํ…Œ์ŠคํŒ…์ž๊ฒฉ์ฆ
    ์—‘์…€
    qa ์ฑ… ๋ฆฌ๋ทฐ
    ์ •์ฒ˜๊ธฐ ์‹ค๊ธฐ
    ์ปดํ“จํ„ฐํ™œ์šฉ๋Šฅ๋ ฅ1๊ธ‰
    ์ปดํ™œ2๊ธ‰
    ์ •์ฒ˜๊ธฐ ํ•„๊ธฐ
  • ์ตœ๊ทผ ๋Œ“๊ธ€

  • ์ตœ๊ทผ ๊ธ€

  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.3
YeonSu02
์ธํ”„๋Ÿฐ ๊ฐ•์˜ - Part3: ์œ ๋‹ˆํ‹ฐ ์—”์ง„ ๋‚ด์šฉ ์ •๋ฆฌ (์„น์…˜ 7 ~ 12)
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”