๋ฐ˜์‘ํ˜•

๐Ÿ”ญ Unity ๋””์ž์ธ ํŒจํ„ด - ์˜ต์ €๋ฒ„(Observer) ํŒจํ„ด

1. ์˜ต์ €๋ฒ„ ํŒจํ„ด์ด๋ž€?

์˜ต์ €๋ฒ„(Observer) ํŒจํ„ด์€ ์–ด๋–ค ๊ฐ์ฒด์˜ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ, ๊ทธ ๊ฐ์ฒด๋ฅผ "๊ตฌ๋…"ํ•˜๊ณ  ์žˆ๋Š” ๋‹ค๋ฅธ ๊ฐ์ฒด๋“ค์—๊ฒŒ ์ž๋™์œผ๋กœ ์•Œ๋ฆผ์„ ๋ณด๋‚ด๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค. Unity์—์„œ๋Š” UI๋‚˜ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ๋ฐ์ดํ„ฐ๋‚˜ ์ด๋ฒคํŠธ์˜ ๋ณ€๊ฒฝ์„ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ฐ˜์˜ํ•ด์•ผ ํ•  ๋•Œ ์ž์ฃผ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

"ํ”Œ๋ ˆ์ด์–ด์˜ ์ฒด๋ ฅ์ด ๋ณ€ํ•˜๋ฉด ์ฒด๋ ฅ๋ฐ”๊ฐ€ ์ž๋™์œผ๋กœ ๋ฐ”๋€Œ๋Š” ๊ฒƒ"์ด ๋Œ€ํ‘œ์ ์ธ ์˜ˆ์ž…๋‹ˆ๋‹ค.


2. ์–ธ์ œ ์‚ฌ์šฉํ•˜๋‚˜์š”?

  • ํ”Œ๋ ˆ์ด์–ด ์ฒด๋ ฅ/๋งˆ๋‚˜ ๋“ฑ์˜ ์ˆ˜์น˜ ๋ณ€ํ™” → UI ์—…๋ฐ์ดํŠธ
  • ๊ฒŒ์ž„ ์„ค์ • ๋ณ€๊ฒฝ → ์—ฌ๋Ÿฌ ์˜ค๋ธŒ์ ํŠธ์— ์ฆ‰์‹œ ๋ฐ˜์˜
  • ์ด๋ฒคํŠธ ์ค‘์‹ฌ ๊ตฌ์กฐ๋กœ ๊ฒŒ์ž„ ๋กœ์ง์„ ๊ด€๋ฆฌํ•  ๋•Œ

3. ๊ตฌ์กฐ ์„ค๋ช…

  • Subject (๋ฐœํ–‰์ž): ์ƒํƒœ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฐ์ฒด. ๋ณ€ํ™”๊ฐ€ ์ƒ๊ธฐ๋ฉด ์˜ต์ €๋ฒ„์—๊ฒŒ ์•Œ๋ฆผ
  • Observer (๊ตฌ๋…์ž): Subject์˜ ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€ํ•˜๊ณ  ๋ฐ˜์‘ํ•˜๋Š” ๊ฐ์ฒด๋“ค

4. Unity ์˜ˆ์ œ: ํ”Œ๋ ˆ์ด์–ด ์ฒด๋ ฅ ๋ณ€ํ™” → ์ฒด๋ ฅ๋ฐ” UI ๊ฐฑ์‹ 

๐Ÿ“ฆ ์ธํ„ฐํŽ˜์ด์Šค ์ •์˜ (์˜ต์ €๋ฒ„ ๊ณตํ†ต)

public interface IHealthObserver
{
    void OnHealthChanged(int current, int max);
}

๐ŸŽฎ Subject: Player

using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour
{
    private int maxHp = 100;
    private int currentHp;

    private List<IHealthObserver> observers = new();

    private void Start()
    {
        currentHp = maxHp;
    }

    public void TakeDamage(int damage)
    {
        currentHp = Mathf.Max(currentHp - damage, 0);
        NotifyObservers();
    }

    public void Heal(int amount)
    {
        currentHp = Mathf.Min(currentHp + amount, maxHp);
        NotifyObservers();
    }

    public void AddObserver(IHealthObserver observer)
    {
        if (!observers.Contains(observer)) observers.Add(observer);
    }

    public void RemoveObserver(IHealthObserver observer)
    {
        if (observers.Contains(observer)) observers.Remove(observer);
    }

    private void NotifyObservers()
    {
        foreach (var observer in observers)
        {
            observer.OnHealthChanged(currentHp, maxHp);
        }
    }
}

๐Ÿ–ผ๏ธ Observer: HealthBar

using UnityEngine;
using UnityEngine.UI;

public class HealthBar : MonoBehaviour, IHealthObserver
{
    [SerializeField] private Slider slider;
    private Player player;

    private void Start()
    {
        player = FindObjectOfType<Player>();
        player?.AddObserver(this);
        OnHealthChanged(playerHp: 100, maxHp: 100); // ์ดˆ๊ธฐํ™”
    }

    public void OnHealthChanged(int playerHp, int maxHp)
    {
        slider.value = (float)playerHp / maxHp;
    }

    private void OnDestroy()
    {
        player?.RemoveObserver(this);
    }
}

5. ์ •๋ฆฌ ๋ฐ ์žฅ๋‹จ์ 

โœ… ์žฅ์ 

  • ๋А์Šจํ•œ ๊ฒฐํ•ฉ (Player์™€ UI๋Š” ์„œ๋กœ ์ง์ ‘ ๋ชฐ๋ผ๋„ ๋จ)
  • ์‹ค์‹œ๊ฐ„ ๋ฐ˜์‘ ๊ตฌ์กฐ
  • ์—ฌ๋Ÿฌ ๊ฐ์ฒด์— ๋™์ผํ•œ ๋ณ€ํ™” ์ „ํŒŒ ๊ฐ€๋Šฅ

โŒ ๋‹จ์ 

  • Observer ๋“ฑ๋ก/ํ•ด์ œ ๋ˆ„๋ฝ ์‹œ ์˜ˆ๊ธฐ์น˜ ์•Š์€ ๋™์ž‘ ๋ฐœ์ƒ
  • ๊ทœ๋ชจ๊ฐ€ ์ปค์ง€๋ฉด ๋””๋ฒ„๊น…์ด ์–ด๋ ค์›Œ์งˆ ์ˆ˜ ์žˆ์Œ

โœ… ๋งˆ๋ฌด๋ฆฌ ํ•œ ์ค„ ์š”์•ฝ

์˜ต์ €๋ฒ„ ํŒจํ„ด์€ "์–ด๋–ค ์ผ์ด ์ƒ๊ธฐ๋ฉด ์•Œ๋ ค์ค„๊ฒŒ" ๋ผ๋Š” ์•ฝ์†์œผ๋กœ, ๊ฒŒ์ž„ ๋‚ด ์‹ค์‹œ๊ฐ„ ๋ฐ˜์‘ํ˜• ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐ ๋งค์šฐ ์œ ์šฉํ•œ ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

 

๋ฐ˜์‘ํ˜•