no image
DesignPattern - 전략(Strategy) 패턴
🧠 Unity 디자인 패턴 - 전략(Strategy) 패턴1. 전략 패턴이란?전략(Strategy) 패턴은 행동(알고리즘)을 객체로 분리하여, 런타임에 자유롭게 교체할 수 있도록 하는 패턴입니다."동일한 행동 인터페이스를 가진 여러 전략 중 하나를 선택해서 실행하는 구조"입니다.게임에서는 주로 공격 방식, 이동 방식, 스킬 사용 방식 등에 다양하게 활용됩니다.2. 언제 사용하나요?캐릭터의 스킬/공격 방식이 상황에 따라 바뀌어야 할 때AI의 행동 방식, 경로 찾기 알고리즘 등 다양한 알고리즘 중 선택적으로 적용해야 할 때if나 switch 문으로 전략 분기를 하고 있을 때 → 리팩토링 시 효과적3. 구조 구성요소역할설명ISkillStrategy전략(알고리즘) 인터페이스FireSkill, IceSkill ..
2025.08.06
no image
DesignPattern - 커맨드(Command) 패턴
🎮 Unity 디자인 패턴 - 커맨드(Command) 패턴1. 커맨드 패턴이란?커맨드(Command) 패턴은 요청(행동)을 하나의 객체로 캡슐화하여,나중에 실행하거나취소하거나저장하거나여러 명령을 큐에 쌓아두었다가 순차적으로 실행할 수 있도록 도와주는 패턴입니다."행동을 직접 수행하지 않고, 명령 쪽지를 만들어서 전달하는 방식"이라고 생각하면 이해가 쉽습니다.2. 언제 사용하나요?행동(명령)을 재사용하거나 기록하고 싶을 때Undo/Redo, 매크로 명령, 리플레이 기능을 만들고 싶을 때UI 버튼이나 키 입력에 대응하는 로직을 유연하게 처리하고 싶을 때3. 구조 구성요소역할설명ICommand명령의 인터페이스 (Execute, Undo 등)ConcreteCommand실제 실행 로직을 담은 명령 객체Invok..
2025.08.06
no image
DesignPattern - 상태 패턴(State Pattern) vs FSM
🔄 Unity 디자인 패턴 - 상태 패턴(State Pattern) vs FSM1. 상태를 관리하는 두 가지 방식게임 캐릭터의 행동이나 UI의 전환처럼 상태에 따라 동작이 달라져야 할 때, 우리는 다음 두 가지 접근 방식을 고려하게 됩니다:FSM (Finite State Machine): 전통적인 조건 분기 기반 구조상태 패턴 (State Pattern): 객체지향 원칙을 적용한 확장 가능한 구조2. FSM이란?FSM(Finite State Machine)은 하나의 상태만 유지하며, 조건에 따라 다른 상태로 전이되는 방식입니다.📦 특징enum, switch-case 구조로 단순 구현 가능빠르고 직관적인 로직 구성에 유리✅ 예제 코드 (Unity 기준)public enum PlayerState { Id..
2025.08.06
no image
DesignPattern - 이벤트 버스(Event Bus) 패턴
📡 Unity 디자인 패턴 - 이벤트 버스(Event Bus) 패턴1. 이벤트 버스란?이벤트 버스(Event Bus) 패턴은 객체 간 직접적인 참조 없이, 전역 이벤트 허브를 통해 메시지를 주고받는 구조입니다."A가 B를 직접 알지 못해도, 이벤트 버스를 통해 소통할 수 있는 구조"입니다.Unity에서는 UI, 게임 로직, 시스템 간 느슨한 연결(Decoupling) 이 필요할 때 매우 유용합니다.2. 언제 사용하나요?시스템 간 결합도를 낮추고 싶을 때여러 UI/오브젝트가 동일한 이벤트를 구독해야 할 때특정 이벤트에 반응하는 대상이 자주 바뀌거나 많을 때3. 구조 설명Publisher (발행자): 이벤트를 전송함Subscriber (구독자): 특정 이벤트를 듣고 반응함EventBus: 중재자 역할. 모..
2025.08.06
no image
DesignPattern - 팩토리(Factory) 패턴
🏭 Unity 디자인 패턴 - 팩토리(Factory) 패턴1. 팩토리 패턴이란?팩토리(Factory) 패턴은 객체의 생성 과정을 감추고, 생성 책임을 별도의 팩토리 클래스에 위임하는 디자인 패턴입니다. Unity에서는 다양한 타입의 오브젝트를 조건에 따라 생성하거나, 유지보수가 쉬운 구조로 확장할 때 자주 사용됩니다."직접 new를 하지 않고, 대신 '공장'에게 주문해서 받아오는 방식"이라고 이해하면 쉽습니다.2. 언제 사용하나요?다양한 타입의 객체를 상황에 따라 생성해야 할 때생성 로직이 자주 바뀌거나, 복잡한 초기화가 필요한 경우결합도를 낮추고, 확장성을 높이고 싶을 때3. Unity 예제: 적(Enemy) 생성기 만들기🎯 목표Enemy 타입에 따라 서로 다른 프리팹을 생성코드 변경 없이 적 종류..
2025.08.06
no image
DesignPattern - 옵저버(Observer) 패턴
🔭 Unity 디자인 패턴 - 옵저버(Observer) 패턴1. 옵저버 패턴이란?옵저버(Observer) 패턴은 어떤 객체의 상태가 변경될 때, 그 객체를 "구독"하고 있는 다른 객체들에게 자동으로 알림을 보내는 구조입니다. Unity에서는 UI나 게임 오브젝트가 데이터나 이벤트의 변경을 실시간으로 반영해야 할 때 자주 사용됩니다."플레이어의 체력이 변하면 체력바가 자동으로 바뀌는 것"이 대표적인 예입니다.2. 언제 사용하나요?플레이어 체력/마나 등의 수치 변화 → UI 업데이트게임 설정 변경 → 여러 오브젝트에 즉시 반영이벤트 중심 구조로 게임 로직을 관리할 때3. 구조 설명Subject (발행자): 상태를 가지고 있는 객체. 변화가 생기면 옵저버에게 알림Observer (구독자): Subject의 ..
2025.08.06
no image
Unity - Input System - InputAction
🎮 Unity Input System - InputAction 완전 정복1. 🧭 InputAction이란?InputAction은 Unity의 새 Input System에서 사용자의 입력을 추상화하여 "행동" 단위로 정의하는 구성 요소입니다.예를 들어 Jump, Move, Shoot 같은 게임 내 행동(행위) 을 정의하고, 여기에 어떤 키보드/마우스/게임패드 입력이 연결될지를 설정합니다.📦 InputAction 구성 구조InputActionAsset └─ Action Map (예: Player) └─ InputAction (예: Move, Jump) └─ Binding (예: WASD, Spacebar, Gamepad A버튼)InputActionAsset: 모든 입력 행동을 담는..
2025.08.06
no image
내일배움캠프 27일차 TIL [팀프로젝트 마무리 + 발표]
🗓️ 오늘 하루 일정✅ 오전09:00 ~ 13:00 :프로젝트 시연 영상 2종 촬영GitHub README 파일 최종 수정결과보고서 최종 점검프로젝트 기능 최종 확인 및 점검최종 발표 준비 진행🍽️ 점심시간13:00 ~ 14:00 : 점심시간✅ 오후14:00 ~ 18:00 :최종 프로젝트 발표 및 발표 시청🍽️ 저녁시간18:00 ~ 19:00 : 저녁시간✅ 저녁19:00 ~ 21:00 :객체지향 프로그래밍 강의 수강✅ 오늘 학습 키워드프로젝트 최종 점검 및 발표GitHub 리드미 수정객체지향 프로그래밍 강의 수강✅ 오늘 학습 한 내용을 나만의 언어로 정리하기오늘은 그동안 진행했던 팀 프로젝트의 마무리 단계로, 오전에는 결과물 점검과 발표 준비에 집중했습니다. 먼저 게임 시연을 위한 영상 2개를 촬영..
2025.08.05
반응형

🧠 Unity 디자인 패턴 - 전략(Strategy) 패턴

1. 전략 패턴이란?

전략(Strategy) 패턴은 행동(알고리즘)을 객체로 분리하여, 런타임에 자유롭게 교체할 수 있도록 하는 패턴입니다.

"동일한 행동 인터페이스를 가진 여러 전략 중 하나를 선택해서 실행하는 구조"입니다.

게임에서는 주로 공격 방식, 이동 방식, 스킬 사용 방식 등에 다양하게 활용됩니다.


2. 언제 사용하나요?

  • 캐릭터의 스킬/공격 방식이 상황에 따라 바뀌어야 할 때
  • AI의 행동 방식, 경로 찾기 알고리즘 등 다양한 알고리즘 중 선택적으로 적용해야 할 때
  • ifswitch 문으로 전략 분기를 하고 있을 때 → 리팩토링 시 효과적

3. 구조 구성요소

역할 설명
ISkillStrategy 전략(알고리즘) 인터페이스
FireSkill, IceSkill 실제 전략을 구현한 클래스들
Player 전략을 사용하는 컨텍스트 역할

4. Unity 예제: 플레이어 스킬 시스템

📦 Step 1: 전략 인터페이스 정의

public interface ISkillStrategy
{
    void Use(GameObject caster);
}

🔥 Step 2: 다양한 스킬 전략들

using UnityEngine;

public class FireSkill : ISkillStrategy
{
    public void Use(GameObject caster)
    {
        Debug.Log("🔥 파이어볼 발사!");
    }
}

public class IceSkill : ISkillStrategy
{
    public void Use(GameObject caster)
    {
        Debug.Log("❄️ 아이스 스톰 시전!");
    }
}

public class HealSkill : ISkillStrategy
{
    public void Use(GameObject caster)
    {
        Debug.Log("💚 힐링 시전! HP +30");
    }
}

🧍 Step 3: 전략을 사용하는 플레이어

using UnityEngine;

public class Player : MonoBehaviour
{
    private ISkillStrategy currentSkill;

    public void SetSkill(ISkillStrategy skill)
    {
        currentSkill = skill;
    }

    public void UseSkill()
    {
        if (currentSkill != null)
            currentSkill.Use(gameObject);
        else
            Debug.Log("스킬이 설정되지 않았습니다.");
    }
}

🕹️ Step 4: 전략 전환 예시

public class GameManager : MonoBehaviour
{
    public Player player;

    void Start()
    {
        player.SetSkill(new FireSkill());
        player.UseSkill(); // 🔥

        player.SetSkill(new IceSkill());
        player.UseSkill(); // ❄️

        player.SetSkill(new HealSkill());
        player.UseSkill(); // 💚
    }
}

5. 정리 및 장단점

✅ 장점

  • if/switch 분기 없이 동작을 교체할 수 있음
  • 전략을 독립적으로 구현/유지/확장 가능
  • 런타임에 알고리즘 변경이 용이함

❌ 단점

  • 클래스 수 증가
  • 구조를 이해하는 데 약간의 시간 필요

✅ 마무리 한 줄 요약

전략 패턴은 **"어떻게 실행할지를 나중에 결정할 수 있는 설계"**로, 캐릭터 스킬, AI 전략, UI 전환 방식 등에서 매우 유연하게 사용할 수 있습니다.

반응형
반응형

🎮 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, 입력 처리, 실행 기록 기능 등에 매우 적합한 패턴입니다.

반응형
반응형

🔄 Unity 디자인 패턴 - 상태 패턴(State Pattern) vs FSM

1. 상태를 관리하는 두 가지 방식

게임 캐릭터의 행동이나 UI의 전환처럼 상태에 따라 동작이 달라져야 할 때, 우리는 다음 두 가지 접근 방식을 고려하게 됩니다:

  • FSM (Finite State Machine): 전통적인 조건 분기 기반 구조
  • 상태 패턴 (State Pattern): 객체지향 원칙을 적용한 확장 가능한 구조

2. FSM이란?

FSM(Finite State Machine)은 하나의 상태만 유지하며, 조건에 따라 다른 상태로 전이되는 방식입니다.

📦 특징

  • enum, switch-case 구조로 단순 구현 가능
  • 빠르고 직관적인 로직 구성에 유리

✅ 예제 코드 (Unity 기준)

public enum PlayerState { Idle, Move, Jump }

public class PlayerFSM : MonoBehaviour
{
    private PlayerState state = PlayerState.Idle;

    void Update()
    {
        switch (state)
        {
            case PlayerState.Idle:
                if (Input.GetKeyDown(KeyCode.W))
                    state = PlayerState.Move;
                break;
            case PlayerState.Move:
                if (Input.GetKeyDown(KeyCode.Space))
                    state = PlayerState.Jump;
                break;
            case PlayerState.Jump:
                if (IsGrounded())
                    state = PlayerState.Idle;
                break;
        }
    }

    private bool IsGrounded() => true; // 착지 판정은 생략
}

👍 장점

  • 구현이 간단하다
  • 로직 흐름이 눈에 잘 보인다

👎 단점

  • 상태가 많아질수록 switch 문이 길어짐
  • 상태별 로직이 섞이기 쉬움 → 유지보수 어려움

3. 상태 패턴이란?

상태 패턴은 각 상태를 독립된 클래스로 분리하여, 상태 전환과 실행 로직을 캡슐화하는 객체지향 방식입니다.

📦 구조

  • 공통 인터페이스 IState
  • 각각의 상태 클래스 (IdleState, MoveState, JumpState 등)
  • 상태를 관리하는 컨텍스트 (PlayerStateMachine 등)

✅ 예제 코드

public interface IState
{
    void Enter();
    void Execute();
    void Exit();
}

public class IdleState : IState
{
    public void Enter() => Debug.Log("Idle 진입");
    public void Execute() => Debug.Log("대기 중...");
    public void Exit() => Debug.Log("Idle 종료");
}

public class MoveState : IState
{
    public void Enter() => Debug.Log("이동 시작");
    public void Execute() => Debug.Log("이동 중...");
    public void Exit() => Debug.Log("이동 종료");
}

public class PlayerStateMachine : MonoBehaviour
{
    private IState currentState;

    void Start()
    {
        ChangeState(new IdleState());
    }

    void Update()
    {
        currentState?.Execute();

        // 임시 예제 전환 로직
        if (Input.GetKeyDown(KeyCode.W)) ChangeState(new MoveState());
    }

    public void ChangeState(IState newState)
    {
        currentState?.Exit();
        currentState = newState;
        currentState.Enter();
    }
}

👍 장점

  • 상태별 로직이 분리되어 깔끔함
  • 새로운 상태를 클래스 추가만으로 확장 가능
  • 상태 전이가 내부적으로 처리되어 유연함

👎 단점

  • 처음 구성할 때 코드 양이 많아 보임
  • 작은 규모의 FSM에는 오히려 과할 수 있음

4. FSM vs 상태 패턴 비교

항목 FSM 상태 패턴
구현 난이도 낮음 중간 이상
코드 구조 절차적 객체지향적
확장성 낮음 높음
테스트 용이성 낮음 높음
권장 대상 간단한 상태 전이 상태가 많거나 복잡한 시스템

✅ 마무리 한 줄 요약

FSM은 빠르게 시작할 수 있는 도구, 상태 패턴은 견고한 구조를 위한 설계입니다.

프로토타입 → FSM → 복잡해질수록 상태 패턴으로 리팩토링하는 흐름이 이상적입니다.

반응형
반응형

📡 Unity 디자인 패턴 - 이벤트 버스(Event Bus) 패턴

1. 이벤트 버스란?

이벤트 버스(Event Bus) 패턴은 객체 간 직접적인 참조 없이, 전역 이벤트 허브를 통해 메시지를 주고받는 구조입니다.

"A가 B를 직접 알지 못해도, 이벤트 버스를 통해 소통할 수 있는 구조"입니다.

Unity에서는 UI, 게임 로직, 시스템 간 느슨한 연결(Decoupling) 이 필요할 때 매우 유용합니다.


2. 언제 사용하나요?

  • 시스템 간 결합도를 낮추고 싶을 때
  • 여러 UI/오브젝트가 동일한 이벤트를 구독해야 할 때
  • 특정 이벤트에 반응하는 대상이 자주 바뀌거나 많을 때

3. 구조 설명

  • Publisher (발행자): 이벤트를 전송함
  • Subscriber (구독자): 특정 이벤트를 듣고 반응함
  • EventBus: 중재자 역할. 모든 이벤트를 관리하고 전달함

4. Unity 예제: 플레이어가 아이템을 먹었을 때 UI 업데이트

🧠 Step 1: EventBus 클래스

using System;
using System.Collections.Generic;

public static class EventBus
{
    private static Dictionary<string, Action<object>> eventTable = new();

    public static void Subscribe(string key, Action<object> callback)
    {
        if (!eventTable.ContainsKey(key))
            eventTable[key] = delegate { };

        eventTable[key] += callback;
    }

    public static void Unsubscribe(string key, Action<object> callback)
    {
        if (eventTable.ContainsKey(key))
            eventTable[key] -= callback;
    }

    public static void Publish(string key, object data = null)
    {
        if (eventTable.TryGetValue(key, out var callback))
            callback.Invoke(data);
    }
}

🎮 Step 2: Player에서 아이템 획득 시 이벤트 발행

using UnityEngine;

public class Player : MonoBehaviour
{
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.E))
        {
            Debug.Log("플레이어가 아이템을 획득!");
            EventBus.Publish("ItemPicked", "HealthPotion");
        }
    }
}

🖼️ Step 3: UI가 이벤트를 구독하여 표시

using UnityEngine;
using TMPro;

public class ItemUI : MonoBehaviour
{
    [SerializeField] private TextMeshProUGUI itemText;

    private void OnEnable()
    {
        EventBus.Subscribe("ItemPicked", OnItemPicked);
    }

    private void OnDisable()
    {
        EventBus.Unsubscribe("ItemPicked", OnItemPicked);
    }

    private void OnItemPicked(object itemName)
    {
        itemText.text = $"획득한 아이템: {itemName}";
    }
}

5. 장점과 단점

✅ 장점

  • 완전한 느슨한 결합
  • 여러 오브젝트가 하나의 이벤트에 반응 가능
  • 발행자와 구독자가 서로 몰라도 됨 → 확장성↑

❌ 단점

  • 실행 흐름이 명확하지 않음 → 디버깅 어려움
  • 잘못된 이벤트 키 입력 시 런타임 오류 유발 가능

✅ 마무리 한 줄 요약

이벤트 버스는 "말만 하면 누구든 들을 수 있는 마이크" 같은 구조로, Unity 프로젝트의 복잡도를 낮추는 강력한 도구입니다.

반응형
반응형

🏭 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가 될 수 있음

✅ 마무리 한 줄 요약

팩토리 패턴은 **"직접 만들지 말고, 공장에 맡겨라"**는 원칙으로, 유지보수성과 확장성이 뛰어난 객체 생성 구조를 제공합니다.


 

반응형
반응형

🔭 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 등록/해제 누락 시 예기치 않은 동작 발생
  • 규모가 커지면 디버깅이 어려워질 수 있음

✅ 마무리 한 줄 요약

옵저버 패턴은 "어떤 일이 생기면 알려줄게" 라는 약속으로, 게임 내 실시간 반응형 구조를 만드는 데 매우 유용한 패턴입니다.

 

반응형
반응형

🎮 Unity Input System - InputAction 완전 정복

1. 🧭 InputAction이란?

InputAction은 Unity의 새 Input System에서 사용자의 입력을 추상화하여 "행동" 단위로 정의하는 구성 요소입니다.

예를 들어 Jump, Move, Shoot 같은 게임 내 행동(행위) 을 정의하고, 여기에 어떤 키보드/마우스/게임패드 입력이 연결될지를 설정합니다.


📦 InputAction 구성 구조

InputActionAsset
 └─ Action Map (예: Player)
     └─ InputAction (예: Move, Jump)
         └─ Binding (예: WASD, Spacebar, Gamepad A버튼)
  • InputActionAsset: 모든 입력 행동을 담는 설정 파일 (보통 .inputactions 확장자)
  • Action Map: 논리적인 입력 그룹 (예: Player, UI, Vehicle 등)
  • InputAction: 실제 행동 정의 (Move, Jump, Fire 등)
  • Binding: 특정 입력 장치와의 연결 (키보드, 마우스, 게임패드 등)

⚙️ 기존 방식 vs InputAction

기존 방식 InputAction
Input.GetKeyDown(KeyCode.Space) InputAction("Jump").performed += ...
코드 내에 직접 키 입력 체크 행동 단위로 추상화된 구조
입력마다 조건문 필요 입력 행동별로 분리 가능
디바이스 변경 시 코드 수정 하나의 Action에 여러 디바이스 바인딩 가능

💬 한 마디로 정리하면?

"InputAction은 '어떤 키를 눌렀는가'가 아니라, '어떤 행동을 실행할 것인가'에 집중하는 시스템입니다."

이 방식은 복잡한 입력 처리, 다양한 디바이스 대응, 깔끔한 코드 구조 등을 모두 만족시킬 수 있어 중대형 프로젝트에서 특히 강력한 입력 처리 구조입니다.


2. 🎯 InputAction 타입 종류

InputAction을 만들 때 선택할 수 있는 Action Type은 세 가지가 있습니다:

① Button (버튼 입력)

  • 가장 기본적인 입력 방식입니다.
  • 키보드나 게임패드의 특정 버튼처럼 눌렀다 뗐다의 이벤트를 감지합니다.
  • 예: 점프, 공격, 상호작용 등
InputAction jumpAction = new InputAction(type: InputActionType.Button);
jumpAction.performed += ctx => Jump();
  • 관련 phase:
    • started: 버튼이 눌리는 순간
    • performed: 동작이 수행된 순간
    • canceled: 버튼에서 손을 뗀 순간

② Value (값 입력)

  • 방향키, 스틱, 마우스 이동 등 연속적인 값을 처리할 때 사용합니다.
  • Vector2, float, int 등 다양한 타입의 값을 받아 처리할 수 있습니다.
  • 예: 이동, 마우스 위치, 줌 레벨 등
InputAction moveAction = new InputAction(type: InputActionType.Value);
Vector2 moveDir = moveAction.ReadValue<Vector2>();

③ Pass-through (즉시 전달형)

  • Unity 이벤트나 다른 처리 로직을 통하지 않고 바로 값 전달이 필요한 경우 사용합니다.
  • performed만 호출되며 started, canceled은 호출되지 않습니다.
  • 보통 처리 과정을 생략하고 입력 값을 그대로 넘겨야 할 때 사용됩니다.
InputAction lookAction = new InputAction(type: InputActionType.PassThrough);
lookAction.performed += ctx => Look(ctx.ReadValue<Vector2>());

✅ 타입 선택 기준 요약

타입 사용 예시 특징
Button 점프, 공격 상태 변화가 있는 단순 입력 처리
Value 이동, 카메라, 줌 값의 변화량을 지속적으로 감지
Pass-through 마우스 이동 빠르고 직접적인 값 전달, 필터 없음

 

3. 🧠 InputAction 이벤트 처리 완전 이해

InputAction의 입력 이벤트는 CallbackContext를 통해 다양한 정보를 제공합니다.

📌 CallbackContext란?

InputAction.CallbackContext는 입력 이벤트가 발생했을 때 전달되는 구조체입니다. 이 안에는 어떤 값이 눌렸는지, 어떤 상태인지 등 중요한 정보가 담겨 있습니다.


📍 주요 속성 설명

속성 설명
ctx.phase 입력의 현재 상태 (Started, Performed, Canceled)
ctx.ReadValue<T>() 입력값을 원하는 타입으로 받아옴 (예: Vector2, float, bool)
ctx.control.name 어떤 입력 컨트롤이 눌렸는지 확인 가능

✅ phase란?

  • Started: 키가 눌리기 시작했을 때 호출
  • Performed: 실제 동작이 완료되었을 때 호출 (ex. 스페이스바 눌러서 점프)
  • Canceled: 입력이 해제됐을 때 호출 (ex. 키에서 손 뗌)
public void OnJumpInput(InputAction.CallbackContext context)
{
    if (context.phase == InputActionPhase.Started)
    {
        Debug.Log("점프 시작!");
    }
    else if (context.phase == InputActionPhase.Performed)
    {
        Debug.Log("점프 실행!");
    }
    else if (context.phase == InputActionPhase.Canceled)
    {
        Debug.Log("점프 해제!");
    }
}

✅ ReadValue()란?

입력으로부터 값을 받을 때 사용되는 함수입니다.

  • ReadValue<Vector2>() → 방향키 입력
  • ReadValue<float>() → 마우스 휠, 트리거 압력
  • ReadValue<bool>() → 단순 버튼 on/off
Vector2 movement = context.ReadValue<Vector2>();

※ 제네릭 타입을 잘못 입력하면 런타임 에러가 발생할 수 있으니 주의해야 합니다.

 

 

 

4. 🧩 PlayerInput 컴포넌트와 InputAction 연동

InputAction을 사용하려면 Unity 오브젝트에 실제 입력을 받을 수단이 필요합니다. 바로 그것이 PlayerInput 컴포넌트입니다.

PlayerInput은 InputActionAsset과 연동되어 입력을 받아 동작을 실행하도록 해주는 중계자 역할을 합니다.


✅ PlayerInput의 구성 요소

항목 설명
Actions 사용할 InputActionAsset 파일 지정
Default Map 시작 시 활성화할 Action Map 선택 (예: "Player")
Behavior 이벤트 처리 방식 선택 (SendMessage, UnityEvents, Invoke C# Events 등)
Camera Look 입력을 카메라 기준으로 보정할 경우 연결

⚙️ Behavior 방식 비교

① SendMessage 방식

  • Unity의 기본 메시지 시스템 활용
  • 액션 이름과 같은 이름의 함수를 MonoBehaviour에서 자동으로 찾아 호출
void OnJump(InputValue value) { ... }
  • ✅ 빠른 구현 가능 / ❌ 퍼포먼스 이슈 가능, 함수명 일치 필수

② UnityEvents 방식

  • 인스펙터에서 액션별로 함수 연결 가능
  • 비개발자도 설정 가능하여 협업에 유리
  • PlayerInputEvents 탭에서 직접 함수 연결
// PlayerController.cs
public void OnMove(InputAction.CallbackContext context) { ... }

③ C# Events 방식

  • 가장 유연하고 퍼포먼스가 좋은 방식
  • 코드에서 직접 InputAction에 접근하고 .performed += 으로 연결
playerInput.actions["Jump"].performed += ctx => Jump();
  • ✅ 코드 기반으로 철저히 제어 가능 / ❌ 초보자에겐 진입장벽 있음

🎮 실습 예시: UnityEvents 방식 연결

  1. Player 오브젝트에 PlayerInput 컴포넌트 추가
  2. Actions에 .inputactions 파일 연결
  3. Behavior를 Invoke Unity Events로 설정
  4. PlayerController 스크립트에 이벤트 함수 작성
  5. 인스펙터에서 해당 액션에 함수 연결
public void OnMove(InputAction.CallbackContext context)
{
    Vector2 input = context.ReadValue<Vector2>();
    // 이동 처리
}

🔍 팁: PlayerInput 자동 생성 방지하기

PlayerInput 컴포넌트를 수동으로 붙여 쓰는 경우, 코드나 다른 매니저에서 InputAction을 생성하면 중복 생성될 수 있습니다. 항상 하나의 PlayerInput만 사용하도록 주의.

 

반응형
반응형

🗓️ 오늘 하루 일정

✅ 오전

  • 09:00 ~ 13:00 :
    • 프로젝트 시연 영상 2종 촬영
    • GitHub README 파일 최종 수정
    • 결과보고서 최종 점검
    • 프로젝트 기능 최종 확인 및 점검
    • 최종 발표 준비 진행

🍽️ 점심시간

  • 13:00 ~ 14:00 : 점심시간

✅ 오후

  • 14:00 ~ 18:00 :
    • 최종 프로젝트 발표 및 발표 시청

🍽️ 저녁시간

  • 18:00 ~ 19:00 : 저녁시간

✅ 저녁

  • 19:00 ~ 21:00 :
    • 객체지향 프로그래밍 강의 수강

✅ 오늘 학습 키워드

  • 프로젝트 최종 점검 및 발표
  • GitHub 리드미 수정
  • 객체지향 프로그래밍 강의 수강

✅ 오늘 학습 한 내용을 나만의 언어로 정리하기

오늘은 그동안 진행했던 팀 프로젝트의 마무리 단계로, 오전에는 결과물 점검과 발표 준비에 집중했습니다. 먼저 게임 시연을 위한 영상 2개를 촬영하고, GitHub의 README를 최종적으로 다듬어 프로젝트를 보다 이해하기 쉽고 보기 좋게 구성했습니다. 이후 결과보고서를 다시 확인하며 누락된 내용이 없는지 꼼꼼히 점검했고, 실제로 게임 기능을 최종 점검하면서 발생할 수 있는 예외 상황도 다시 확인했습니다.

오후에는 팀원들과 함께 프로젝트를 발표하고, 다른 팀의 발표도 시청하며 다양한 아이디어를 접할 수 있었습니다. 발표를 통해 우리 팀의 작업이 체계적으로 잘 정리되었다는 느낌을 받았고, 다른 팀의 피드백을 들으며 앞으로 개선할 점도 생각해볼 수 있었습니다.


🧩 학습하며 겪었던 문제점 & 에러


📝 메모

오늘은 일주일 동안 집중해서 달려온 팀 프로젝트의 마지막 날이었습니다. 결과물을 발표하면서 다른 팀의 작업을 보며 비교도 해보고, 우리 팀만의 강점과 앞으로 보완하면 좋을 점도 함께 느낄 수 있는 시간이었습니다.

무엇보다 이번 팀원들과의 호흡이 너무 좋아서 헤어지는 것이 유난히 아쉽게 느껴졌습니다. 새로운 팀으로 배정받을 때마다 항상 이별의 아쉬움은 있었지만, 이번에는 특히 마음이 많이 가서 그런지 더 깊은 여운이 남습니다.

용민님, 유경님, 노아님, 세윤님, 우리 팀원들! 팀장 잘못 만나서 3D로 고생 많으셨죠ㅎㅎ… 그럼에도 불구하고 묵묵히 따라와 주셔서 정말 고맙습니다. 여러분 덕분에 이 프로젝트가 끝까지 완성될 수 있었습니다.

언젠가 또 만나 함께 웃으며 개발할 수 있기를 진심으로 바랍니다. 감사했고, 또 고마웠어요! 😊

 

 

프로젝트 소개 - 「현대세계 최후의 궁수」

🎮 1. 게임 소개이번 프로젝트는 '궁수의 전설(Archero)'에서 영감을 받아 제작한 탑다운 슈팅 기반의 액션 게임입니다.현대 세계를 배경으로, 마지막 남은 궁수가 되어 적들을 물리치고 스테이지

dev-jen.tistory.com

이번에 진행한 현대세계 최후의 궁수 프로젝트입니다!

반응형