๋ฐ˜์‘ํ˜•

๐ŸŽฎ Unity ๋””์ž์ธ ํŒจํ„ด - ์ปค๋งจ๋“œ(Command) ํŒจํ„ด

1. ์ปค๋งจ๋“œ ํŒจํ„ด์ด๋ž€?

์ปค๋งจ๋“œ(Command) ํŒจํ„ด์€ ์š”์ฒญ(ํ–‰๋™)์„ ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋กœ ์บก์Аํ™”ํ•˜์—ฌ,

  • ๋‚˜์ค‘์— ์‹คํ–‰ํ•˜๊ฑฐ๋‚˜
  • ์ทจ์†Œํ•˜๊ฑฐ๋‚˜
  • ์ €์žฅํ•˜๊ฑฐ๋‚˜
  • ์—ฌ๋Ÿฌ ๋ช…๋ น์„ ํ์— ์Œ“์•„๋‘์—ˆ๋‹ค๊ฐ€ ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

"ํ–‰๋™์„ ์ง์ ‘ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๊ณ , ๋ช…๋ น ์ชฝ์ง€๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ์‹"์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ์ดํ•ด๊ฐ€ ์‰ฝ์Šต๋‹ˆ๋‹ค.


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

  • ํ–‰๋™(๋ช…๋ น)์„ ์žฌ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ๊ธฐ๋กํ•˜๊ณ  ์‹ถ์„ ๋•Œ
  • Undo/Redo, ๋งคํฌ๋กœ ๋ช…๋ น, ๋ฆฌํ”Œ๋ ˆ์ด ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค๊ณ  ์‹ถ์„ ๋•Œ
  • UI ๋ฒ„ํŠผ์ด๋‚˜ ํ‚ค ์ž…๋ ฅ์— ๋Œ€์‘ํ•˜๋Š” ๋กœ์ง์„ ์œ ์—ฐํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ์„ ๋•Œ

3. ๊ตฌ์กฐ ๊ตฌ์„ฑ์š”์†Œ

์—ญํ•  ์„ค๋ช…
ICommand ๋ช…๋ น์˜ ์ธํ„ฐํŽ˜์ด์Šค (Execute, Undo ๋“ฑ)
ConcreteCommand ์‹ค์ œ ์‹คํ–‰ ๋กœ์ง์„ ๋‹ด์€ ๋ช…๋ น ๊ฐ์ฒด
Invoker ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋Š” ์ฃผ์ฒด (์˜ˆ: InputHandler, ๋ฒ„ํŠผ ๋“ฑ)
Receiver ๋ช…๋ น์˜ ์‹ค์ œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฐ์ฒด

4. Unity ์˜ˆ์ œ: ํ”Œ๋ ˆ์ด์–ด ๋ช…๋ น ์‹œ์Šคํ…œ

๐ŸŽฎ Step 1: ICommand ์ธํ„ฐํŽ˜์ด์Šค

public interface ICommand
{
    void Execute();
    void Undo();
}

๐Ÿงฑ Step 2: ์‹ค์ œ ๋ช…๋ น๋“ค

public class MoveCommand : ICommand
{
    private Player player;
    public MoveCommand(Player p) => player = p;

    public void Execute() => player.Move();
    public void Undo() => player.Stop();
}

public class JumpCommand : ICommand
{
    private Player player;
    public JumpCommand(Player p) => player = p;

    public void Execute() => player.Jump();
    public void Undo() => Debug.Log("์ ํ”„ ์ทจ์†Œ");
}

๐Ÿง Step 3: ์ˆ˜์‹ ์ž(Receiver) - Player

using UnityEngine;

public class Player : MonoBehaviour
{
    public void Move() => Debug.Log("ํ”Œ๋ ˆ์ด์–ด ์ด๋™ ์ค‘...");
    public void Jump() => Debug.Log("ํ”Œ๋ ˆ์ด์–ด ์ ํ”„!");
    public void Stop() => Debug.Log("ํ”Œ๋ ˆ์ด์–ด ์ •์ง€");
}

๐Ÿ•น๏ธ Step 4: ์ž…๋ ฅ ํ•ธ๋“ค๋Ÿฌ (Invoker)

using UnityEngine;

public class InputHandler : MonoBehaviour
{
    public Player player;

    private ICommand moveCommand;
    private ICommand jumpCommand;

    private void Start()
    {
        moveCommand = new MoveCommand(player);
        jumpCommand = new JumpCommand(player);
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.W))
            moveCommand.Execute();

        if (Input.GetKeyDown(KeyCode.Space))
            jumpCommand.Execute();
    }
}

5. ํ™•์žฅ: ๋ช…๋ น ํžˆ์Šคํ† ๋ฆฌ๋กœ Undo ๊ตฌํ˜„ํ•˜๊ธฐ

using System.Collections.Generic;

public class CommandManager
{
    private Stack<ICommand> history = new();

    public void ExecuteCommand(ICommand command)
    {
        command.Execute();
        history.Push(command);
    }

    public void UndoCommand()
    {
        if (history.Count > 0)
        {
            ICommand last = history.Pop();
            last.Undo();
        }
    }
}

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

โœ… ์žฅ์ 

  • ๋ช…๋ น์„ ๋‚˜์ค‘์— ์‹คํ–‰ํ•˜๊ฑฐ๋‚˜ ์ทจ์†Œ ๊ฐ€๋Šฅ (Undo, Replay ๋“ฑ)
  • ๋ช…๋ น์„ ๋ชจ๋“ˆํ™”ํ•˜์—ฌ ํ™•์žฅ์„ฑ ↑
  • ์ž…๋ ฅ → ํ–‰๋™์„ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ด€๋ฆฌํ•˜๊ธฐ ์‰ฌ์›€

โŒ ๋‹จ์ 

  • ํด๋ž˜์Šค ์ˆ˜ ์ฆ๊ฐ€
  • ๋‹จ์ˆœํ•œ ์ž‘์—…์—” ์˜ค๋ฒ„ํ—ค๋“œ ๋ฐœ์ƒ

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

์ปค๋งจ๋“œ ํŒจํ„ด์€ ํ–‰๋™์„ ๊ฐ์ฒด๋กœ ๋งŒ๋“ค๊ณ , ์‹คํ–‰์„ ์ œ์–ดํ•˜๋Š” ๊ตฌ์กฐ๋กœ, UI, ์ž…๋ ฅ ์ฒ˜๋ฆฌ, ์‹คํ–‰ ๊ธฐ๋ก ๊ธฐ๋Šฅ ๋“ฑ์— ๋งค์šฐ ์ ํ•ฉํ•œ ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

๋ฐ˜์‘ํ˜•