๋ฐ˜์‘ํ˜•

๐Ÿญ Unity ๋””์ž์ธ ํŒจํ„ด - ํŒฉํ† ๋ฆฌ(Factory) ํŒจํ„ด

1. ํŒฉํ† ๋ฆฌ ํŒจํ„ด์ด๋ž€?

ํŒฉํ† ๋ฆฌ(Factory) ํŒจํ„ด์€ ๊ฐ์ฒด์˜ ์ƒ์„ฑ ๊ณผ์ •์„ ๊ฐ์ถ”๊ณ , ์ƒ์„ฑ ์ฑ…์ž„์„ ๋ณ„๋„์˜ ํŒฉํ† ๋ฆฌ ํด๋ž˜์Šค์— ์œ„์ž„ํ•˜๋Š” ๋””์ž์ธ ํŒจํ„ด์ž…๋‹ˆ๋‹ค. Unity์—์„œ๋Š” ๋‹ค์–‘ํ•œ ํƒ€์ž…์˜ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์กฐ๊ฑด์— ๋”ฐ๋ผ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜, ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์‰ฌ์šด ๊ตฌ์กฐ๋กœ ํ™•์žฅํ•  ๋•Œ ์ž์ฃผ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

"์ง์ ‘ new๋ฅผ ํ•˜์ง€ ์•Š๊ณ , ๋Œ€์‹  '๊ณต์žฅ'์—๊ฒŒ ์ฃผ๋ฌธํ•ด์„œ ๋ฐ›์•„์˜ค๋Š” ๋ฐฉ์‹"์ด๋ผ๊ณ  ์ดํ•ดํ•˜๋ฉด ์‰ฝ์Šต๋‹ˆ๋‹ค.


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

  • ๋‹ค์–‘ํ•œ ํƒ€์ž…์˜ ๊ฐ์ฒด๋ฅผ ์ƒํ™ฉ์— ๋”ฐ๋ผ ์ƒ์„ฑํ•ด์•ผ ํ•  ๋•Œ
  • ์ƒ์„ฑ ๋กœ์ง์ด ์ž์ฃผ ๋ฐ”๋€Œ๊ฑฐ๋‚˜, ๋ณต์žกํ•œ ์ดˆ๊ธฐํ™”๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ
  • ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถ”๊ณ , ํ™•์žฅ์„ฑ์„ ๋†’์ด๊ณ  ์‹ถ์„ ๋•Œ

3. Unity ์˜ˆ์ œ: ์ (Enemy) ์ƒ์„ฑ๊ธฐ ๋งŒ๋“ค๊ธฐ

๐ŸŽฏ ๋ชฉํ‘œ

  • Enemy ํƒ€์ž…์— ๋”ฐ๋ผ ์„œ๋กœ ๋‹ค๋ฅธ ํ”„๋ฆฌํŒน์„ ์ƒ์„ฑ
  • ์ฝ”๋“œ ๋ณ€๊ฒฝ ์—†์ด ์  ์ข…๋ฅ˜๋ฅผ ํ™•์žฅ ๊ฐ€๋Šฅํ•˜๋„๋ก ๊ตฌ์กฐ ์„ค๊ณ„

4. ์˜ˆ์ œ ์ฝ”๋“œ

๐Ÿงฑ Step 1: Enemy ํƒ€์ž… ์ •์˜

public enum EnemyType
{
    Melee,
    Ranged,
    Boss
}

๐ŸŽฎ Step 2: Enemy ๋ฒ ์ด์Šค ํด๋ž˜์Šค

using UnityEngine;

public abstract class Enemy : MonoBehaviour
{
    public abstract void Initialize();
}

๐ŸงŸ Step 3: ์‹ค์ œ ์  ํด๋ž˜์Šค๋“ค

public class MeleeEnemy : Enemy
{
    public override void Initialize() => Debug.Log("๊ทผ์ ‘ ์  ์ƒ์„ฑ ์™„๋ฃŒ");
}

public class RangedEnemy : Enemy
{
    public override void Initialize() => Debug.Log("์›๊ฑฐ๋ฆฌ ์  ์ƒ์„ฑ ์™„๋ฃŒ");
}

public class BossEnemy : Enemy
{
    public override void Initialize() => Debug.Log("๋ณด์Šค ์ƒ์„ฑ ์™„๋ฃŒ");
}

๐Ÿญ Step 4: EnemyFactory

using UnityEngine;

public class EnemyFactory : MonoBehaviour
{
    [Header("Enemy Prefabs")]
    public GameObject meleePrefab;
    public GameObject rangedPrefab;
    public GameObject bossPrefab;

    public Enemy CreateEnemy(EnemyType type, Vector3 spawnPosition)
    {
        GameObject prefab = type switch
        {
            EnemyType.Melee => meleePrefab,
            EnemyType.Ranged => rangedPrefab,
            EnemyType.Boss => bossPrefab,
            _ => null
        };

        if (prefab == null)
        {
            Debug.LogWarning("ํ•ด๋‹น EnemyType์— ๋Œ€ํ•œ ํ”„๋ฆฌํŒน์ด ์—†์Šต๋‹ˆ๋‹ค.");
            return null;
        }

        GameObject enemyObj = Instantiate(prefab, spawnPosition, Quaternion.identity);
        Enemy enemy = enemyObj.GetComponent<Enemy>();
        enemy?.Initialize();
        return enemy;
    }
}

๐Ÿงช Step 5: ์‚ฌ์šฉ ์˜ˆ์‹œ

public class GameManager : MonoBehaviour
{
    public EnemyFactory enemyFactory;

    private void Start()
    {
        enemyFactory.CreateEnemy(EnemyType.Melee, new Vector3(0, 0, 0));
        enemyFactory.CreateEnemy(EnemyType.Ranged, new Vector3(2, 0, 0));
        enemyFactory.CreateEnemy(EnemyType.Boss, new Vector3(4, 0, 0));
    }
}

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

โœ… ์žฅ์ 

  • ๊ฐ์ฒด ์ƒ์„ฑ ๋กœ์ง ๋ถ„๋ฆฌ๋กœ ์ฑ…์ž„์ด ๋ช…ํ™•ํ•ด์ง
  • ์ƒˆ๋กœ์šด Enemy ํƒ€์ž… ์ถ”๊ฐ€ ์‹œ, Factory๋งŒ ์ˆ˜์ •ํ•˜๋ฉด ๋จ
  • ์˜์กด์„ฑ ์ตœ์†Œํ™”, ํ…Œ์ŠคํŠธ์™€ ์œ ์ง€๋ณด์ˆ˜ ์‰ฌ์›€

โŒ ๋‹จ์ 

  • ๊ตฌ์กฐ๊ฐ€ ์กฐ๊ธˆ ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ์Œ
  • Factory์— ๋„ˆ๋ฌด ๋งŽ์€ ์ฑ…์ž„์ด ์ง‘์ค‘๋˜๋ฉด God Object๊ฐ€ ๋  ์ˆ˜ ์žˆ์Œ

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

ํŒฉํ† ๋ฆฌ ํŒจํ„ด์€ **"์ง์ ‘ ๋งŒ๋“ค์ง€ ๋ง๊ณ , ๊ณต์žฅ์— ๋งก๊ฒจ๋ผ"**๋Š” ์›์น™์œผ๋กœ, ์œ ์ง€๋ณด์ˆ˜์„ฑ๊ณผ ํ™•์žฅ์„ฑ์ด ๋›ฐ์–ด๋‚œ ๊ฐ์ฒด ์ƒ์„ฑ ๊ตฌ์กฐ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.


 

๋ฐ˜์‘ํ˜•