[CS]디자인 패턴

강동현·2024년 2월 2일
0

CS

목록 보기
15/19

# 게임 개발에 자주 사용되는 디자인 패턴만을 다룰 것

디자인 패턴 : Design Pattern

  • 소프트 웨어 개발 중 자주 발생하는 문제들에 대한 해결책
  • 미친놈들이 만든 방법을 사용하게 된다.

디자인 패턴 이점

  • 수세기동안 고수들이 개발
    • 시도되고 검증됨
  • 개발자간 효율적인 의사소통

디자인 패턴 분류

  • 디자인 패턴은 의도목적에 따라 분류된다.
  • 1. 생성 패턴: 코드의 재활용성 및 유연성을 향상시키는 객체 생성 매커니즘 제공
    • 팩토리[★]
      • 팩토리 매서드[★]
      • 추상 팩토리[★]
    • 빌더[☆]
    • 프로토타입[☆]
    • 싱글톤[★]
  • 2. 구조 패턴: 코드를 유연하고 효율적으로 유지하면서, 객체 및 클래스를 더 큰 규모로 조합하는 방법
    • 어댑터[☆]
    • 브리지
    • 복합체[★] = V
    • 데코레이터
    • 퍼사드
    • 플라이웨이트(=경량)[☆]
    • 프록시
  • 3. 행동 패턴: 객체간 의사소통 및 책임 할당 처리
    • 책임 연쇄
    • 커맨드[★]
    • 반복자
    • 중재자
    • 메멘토
    • 옵저버[★] = M
    • 상태[★]
    • 전략[★] = C
    • 템플릿 매서드
    • 비지터
  • MVC
  • 컴포넌트
  • 오브젝트 풀[★]

0. 다형성

  • 디자인 패턴에선 다형성 패턴을 많이 애용
    • 부모 포인터 <- 자식 객체(가능)
    • 자식 포인터 <- 부모 객체(불가능)
    • 다형성 구현에 virtual or abstract 지정 필수
//부모 포인터 <- 자식 객체 할당
Super obj = new Sub();
//자식 포인터 <- 부모 객체 할당 불가
//Sub obj = new Super();

1. 생성 - 팩토리 패턴(Factory Pattern)

  • 팩토리: 객체 생성을 담당하는 추상 클래스 or 인터페이스
    • 주어진 입력에 따른 객체를 반환하는 메소드 존재
class HumanFactory
{
	Human CreateHuman(HumanType type)
    {
    	switch(type)
        {
        	case HumanType.Teacher:
            	return new Teacher();
                break;
            case HumanType.Student:
            	return new Student();
                break;
        }
    }
};
//사용 시
Human human1 = HumanFactory.CreateHuman(Human.Teacher);
Human human2 = HumanFactory.CreateHuman(Human.Student);

2. 팩토리 메서드 패턴(Factory Mathod Pattern)

  • 추상 클래스 or 인터페이스팩토리 클래스를 통해 객체 생성 메소드(팩토리 매서드)를 선언하고, 실제 객체 생성서브 클래스에서 구현
  • 0-1. 팩토리 클래스 생성
    • 객체 생성을 다루는 클래스 생성
  • 0-2. 팩토리 메소드 생성
    • 객체를 실재로 할당하는 메소드 생성
    1. 부모 포인터 배열 생성
    1. 자식 객체 할당 후 관리
abstract class StageGenerator
{
	abstract void CreateCreatures();
};
class Stage1Generator : StageGenerator
{
	override void CreateCreatures(){
    	//몬스터 10마리 생성
    }
};
class Stage2Generator : StageGenerator
{
	override void CreateCreatures(){
    	//몬스터 15마리 생성
    }
};
class StageFactoryMethod
{
	StageGenerator[] stageGenerator = null;
    StageFactoryMethod()
    {
    	stageGenerator = new StageGenerator[STAGE_SIZE];
        stageGenerator[0] = new Stage1Generator();
        stageGenerator[1] = new Stage2Generator();
    }
    void MakeStage1()
    {
    	stageGenerator[0].CreateCreatures();
    }
    void MakeStage2()
    {
    	stageGenerator[1].CreateCreatures();
    }
};

3. 추상 팩토리 패턴(Abstract Factory Pattern)

  • 추상 팩토리(abstract 부모 클래스 or 인터페이스) 선언
    • 해당 클래스엔 abstract 객체 생성 함수 선언
    • 자식 클래스에서 해당 함수 override
//프린터 객체
class Printer {...};
class PrinterA : Printer {...};
class PrinterB : Printer {...};
//스캐너 객체
class Scanner {...};
class ScannerA : Scanner {...};
class ScannerB : Scanner {...};
//Factory Method
class FactoryPrinter{
//A회사 -> A소프트웨어, B회사 -> B소프트웨어 생성 및 반환
};
class FactoryScanner{
//A회사 -> A소프트웨어, B회사 -> B소프트웨어 생성 및 반환
};
//복합기 객체
class MultifunctionPrinter{
	void UseFactory(CompanyType type)
    {
    	Printer printer = FactoryPrinter.MakePrinter(type);
        Scanner scanner = FactoryScanner.MakeScanner(type);
    }
};
class MultifunctionPrinter {...};
class PrinterA : MultifuncitonPrinter {...};
class PrinterB : MultifunctionPrinter {...};
  • 위 상황에서 Printer, Scanner 뿐만 아닌 더 다양한 객체를 담당할 때, 이를 모두 수정해야하므로 불편
abstract class MultiPrinterFactory
{
	abstract Printer MakePrinter();
    abstract Scanner MakeScanner();
};
class AFactory : MultiPrinterFactory
{
	override Printer MakePrinter() { return new PrinterA(); }
    override Scanner MakeScanner() { return new ScannerA(); }
};
class BFactory : MultiPrinterFactory
{
	override Printer MakePrinter() { return new PrinterB(); }
    override Scanner MakeScanner() { return new ScannerB(); }
};
  • 사용법
MultiPrinterFactory factory = null;
CompanyType type = CompanyType.A;
if(type == CompanyType.A) { factory = new AFactory(); }
else if(type == CompanyType.B) { factory = new BFactory(); }
Printer printer = factory.MakePrinter();
Scanner scanner = factory.MakeScanner();

4. 빌더 패턴(Builder Pattern)

  • 빌더(Builder): 객체 생성을 담당하는 인터페이스
    • 객체 생성 메서드 제공
  • 구체적 빌더(Concrete Builder): 실제로 객체를 조립하는 클래스
  • 제품(Product): 최종적으로 생성되는 복합 객체
  • 감독자, 옵션(Director): Builder를 사용해 객체를 생성하는 클래스
using UnityEngine;
//제품(Product)
public class Character
{
	public string Name;
    public int HP;
    public int ATK;
    public Character(string name, int hp, int atk)
    {
    	Name = name;
        HP = hp;
        ATK = atk;
    }
}
//추상 빌더
public abstract class CharacterBuilder
{
	protected Character character;
    public Character Character { get { return character; } };
    public abstract void BuildName();
    public abstract void BuildHP();
    public abstract void BuildATK();
}
//구체적인 빌더
public class WarriorBuilder : CharacterBuilder
{
	public WarriorBuilder()
    {
    	character = new Character("Warrior", 100, 50);
    }
    public override void BuildName(){
    	character.Name = "Warrior";
    }
    public override void BuildHP(){
    	character.HP = 100;
    }
    public override void BuildATK(){
    	character.ATK = 10;
    }
}
//구체적인 빌더
public class MageBuilder : CharacterBuilder
{
	public MageBuilder()
    {
    	character = new Character("Mage", 100, 50);
    }
    public override void BuildName(){
    	character.Name = "Mage";
    }
    public override void BuildHP(){
    	character.HP = 20;
    }
    public override void BuildATK(){
    	character.ATK = 50;
    }
}
//감독자
public class CharacterCreator : MonoBehaviour
{
	private CharacterBuilder characterBuilder;
    public void SetCharacterBuilder(CharacterBuilder builder){
    	createrBuilder = builder;
    }
    public Character GetCharacter(){
    	return characterBuilder.Character;
    }
}

5. 프로토 타입 패턴(Prototype Pattern)

  • 프로토 타입 객체를 미리 생성
  • 프로토 타입 객체클론해 객체를 생성
  • 높은 비용의 객체 생성 시 효과적
interface IPlayer
{
	IPlayer Clone();
}
class Character : IPlayer
{
	Data data;
    IPlayer Clone()
    {
    	return this.MemberwiseClone() as IPlayer;//얕은 복사
        //깉은 복사 필요 시, 구현 필요
    }
}
Character c1 = new Character();
c1.data = GetDataFromServer();
//클론을 통한 객체 복사
Character c2 = (Character)c1.Clone();

6. 싱글톤 패턴(Singleton pattern)

  • 클래스당 한 개의 객체를 갖도록 보장하는 것
  • 멀티 쓰레드 상황에서 race condition 발생 가능
    • 주의해서 사용
public class GameManager : MonoBehaviour
{
	public static GameManager instance = null;
    private void Start()
    {
    	if(instance == null)
        {
        	instance = this;
        }
        else 
        {
        	Destroy(instance);
        }
    }
}

7. 어댑터 패턴(Adapter Pattern)

  • 한 클래스인터페이스를 사용하고자 하는 다른 인터페이스변환하는 디자인 패턴
  • 외부 라이브러리(LegacyAudioPlayer) 클래스Unity AudioSource 클래스호환되는 인터페이스로 변환하는 어댑터 구현
using UnityEngine;
//외부 라이브러리에서 제공되는 클래스(Adaptee)
public class LegacyAudioPlayer
{
	public void PlaySound(string soundName)
    {
    	Debug.Log("Legacy Audio Player plays sound: " + soundName);
    }
}
//Unity AudioSource와 호환된느 인터페이스(target)
public interface IAudioSource
{
	void Play();
}
//LegacyAudioPlayer를 IAudioSource로 변환하는 어댑터 클래스(Adapter)
public class LegacyAudioAdapter : MonoBehaviour, IAudioSource
{
	private LegacyAudioPlayer legacyAudioPlayer;
    public LegacyAudioAdapter()
    {
    	legacyAudioPlayer = new LegacyAudioPlayer();
    }
    public void Play()
    {
    	legacyAudioPlayer.PlaySound("Adapted Sound");
    }
}
//클라이언트
public class AudioManager : MonoBehaviour
{
	public IAudioSource audioSource;
    void Start()
    {
    	//어댑터를 통해 Legacy의 기능을 사용
    	audioSource.Play();
    }
}

8. 복합체 패턴(Composite Pattern)

  • 객체들을 트리 구조로 구성부분-전체 계층을 표현하는 디자인 패턴
  • Unity에서는 GameObject를 트리 구조로 구성해 부모-자식 관계로 나타내고, 이를 통해 그룹화된 오브젝트 하나를 단일 오브젝트로 취급한다.
using UnityEngine;
using System.Collections.Generic;
//Component: 모든 요소에 대한 공통 인터페이스 정의
public abstract class Component
{
	public string name;
    public abstract void Operation();
}
//Leaf: 복합체 안에 들어가는 개별 객체
public class Leaf : Component
{
	public Leaf(string name)
    {
    	this.name = name;
    }
    public override void Operation()
    {
    	Debug.Log("Leaf " + name + " is performing operation");
    }
}
//Composite: 복합 객체, Leaf 또는 복합 객체 모두 포함 가능
public class Composite : Component
{
	private List<Component> children = new List<Component>();
    public void Add(Component component)
    {
    	children.Add(component);
    }
    public void Remove(Component component)
    {
    	children.Remove(component);
    }
    public override void Operation()
    {
    	Debug.Log("Composite " + name + " is performing operation");
        foreach(var child in chilren)
        {
        	child.Operation();
        }
    }
}
//Client: 복합체를 사용하는 클라이언트
public class Client : MonoBehaviour
{
	void Start()
    {
    	//복합 객체 생성
        Composite root = new Composite();
        root.name = "Root";
        //개별 객체 생성
        Leaf leaf1 = new Leaf("Leaf1");
        Leaf leaf2 = new Leaf("Leaf2");
        //복합 객체에 개별 객체 추가
        root.Add(leaf1);
        root.Add(leaf2);
        //복합 객체에 다른 복합 객체 추가
        Composite subComposite = new Composite();
        subComposite.name = "SubCompoeite";
        Leaf leaf3 = new Leaf("Leaf3");
        subComposite.Add(leaf3);
        root.Add(subComposite);
        //모드 객체에 대한 작업 수행
        root.Operation();
    }
}

9. 경량 패턴(Flyweight Pattern)

  • 이미 생성된 객체공유하는 패턴
    • 생성된 객체가 없는 경우에만 객체 생성
    • 그 외의 경우 객체 재사용
//유닛 생성을 관리하는 Unity Factory Class.
class UnityFactory
{
	static Dictionary<string, Unit> dic = new Dictionary<string, Unit>();
    static Unit GetUnit(string name)
    {
    	if(!dic.ContainsKey(name))
        {
        	Unit temp = new Unit(name);
            dic.Add(name, temp);
        }
        return dic[name];
    }
}
//사용법
Unit u1 = UnitFactory.GetUnit("aaa");
Unit u2 = UnitFactory.GetUnit("bbb");
Unit u3 = UnitFactory.GetUnit("aaa");
//u1 = u3(같은 객체 = 공유 데이터를 공유)

10. 명령 패턴(Command Pattern)

  • 매서드 호출을 실체화 : 객체로 캡슐화하여 요청자와 수신자 사이 의존성을 제거하는 패턴
  • 요청을 객체로 감싸고, 요청을 매개변수화하여 여러 작업을 실행, 취소 및 재실행
using UnityEngine;
using System.Collections.Generic;
//명령 인터페이스
public interface ICommand
{
	void Execute();
    void Undo();
}
//이동 명령
public class MoveCommand : ICommand
{
	private GameObject gameObject;
    private Vector3 startPosition;
    private Vector3 endPosition;
    public MoveCommand(GameObject gameObject, Vector3 endPosition)
    {
    	this.gameObject = gameObject;
        this.endPosition = endPosition;
    }
    public void Excute()
    {
    	startPosition = gameObject.transform.position;
        gameObject.transform.position = endPosition;
    }
    public void Undo()
    {
    	gameObject.transform.position = startPosition;
    }
}
//회전 명령
public class RotateCommand : ICommand
{
	private GameObject gameObject;
    private Quaternion startRotation;
    private Quaternion endRotation;
    public RotateCommand(GameObject gameObject, Quaternion endRotation)
    {
    	this.gameObject = gameObject;
        this.endRotation = endRotation;
    }
    public void Excute()
    {
    	startRotation = gameObject.transform.rotation;
        gameObject.transform.rotation = endRotation;
    }
    public void Undo()
    {
    	gameObject.transform.rotation = startRotation;
    }
}
//명령 실행 관리자
public class CommandManager : MonoBehaviour
{
	private Stack<ICommand> undoStack = new Stack<ICommand>();
    public void ExcuteCommand(ICommand command)
    {
    	command.Execute();
        undoStack.Push(command);
    }
    public void UndoLaskCommand()
    {
    	if(undoStack.Count > 0)
        {
        	ICommand command = undoStack.Pop();
            command.Undo();
        }
    }
}
//클라이언트 사용 예시
public class Client : MonoBehaviour
{
	public GameObject cube;
    void Start()
    {
    	CommandManager commandManager = GetComponent<CommandManager>();
        ICommand moveCommand = new MoveCommand(cube, new Vector3(3f, 0f, 0f));
        ICommand rotateCommand = new RotateCommand(cube, Quaternion.Euler(0f, 90f, 0f));
   		commandManager.ExecuteCommand(moveCommand);
        commandManager.ExecuteCommand(rotateCommand);
        commandManager.UndoLastCommand();
    }
}

11. 옵저버 패턴(Observer Pattern)

  • 객체의 상태 변화를 관찰하는 객체(옵저버) 목록을 가지는 디자인 패턴
  • 객체가 상태 변화 시, 옵저버에게 자동으로 알림을 보내 상호작용 수행
  • Subject & Observer로 구분
    • Subject: 상태를 관찰하는 객체
      • 상태가 변경되면 등록된 옵저버에게 알림을 보냄
    • Observer: Subject의 상태를 관찰하는 객체
      • 알림을 받으면 특정 동작 수행
using UnityEngine;
using System;
using System.Collections.Generic;
//Subject: 상태를 관찰하는 플레이어 클래스
public class Player : MonoBehaviour
{
	//옵저버들을 저장할 리스트
	private List<IObserver> observers = new List<IObserver>();
    //옵저버 등록 매서드
    public void RegisterObserver(IObserver observer)
    {
    	observers.Add(observer);
    }
    //옵저버 해제 매서드
    public void UnregisterObserver(IObserver observer)
    {
    	observers.Remove(observer);
    }
    //플레이어 이동 매서드
    public void Move()
    {
    	//이동 로직...
        //이동 후 옵저버들에게 알림
        observer.NotifyObservers();
    }
    //옵저버들에게 알림을 보내는 메서드
    private void NotifyObservers()
    {
    	foreach (var observer in observers)
        {
        	observer.OnPlayerMoved();
        }
    }
}
//Observer: 변화를 관찰하는 인터페이스
public interface IObserver
{
	void OnPlayerMoved();
}
//Observer 1: 적 클래스
public class Enemy : MonoBehaviour, IObserver
{
	플레이어 이동 시, 호출되는 메서드
    public void OnPlayerMoved()
    {
    	Debug.Log("Enemy: Player had moved. Updating AI...");
        //AI 업데이트 로직...
    }
}
public class UIElement : MonoBehaviour, IObserver
{
	//플레이어 이동 시 호출되는 매서드
    public void OnPlayerMoved()
    {
    	Debug.Log("UIElement: Player had moved. Updating UI...");
        //UI 업데이트 로직...
    }
}
//클라이언트 사용법
public class Client : MonoBehaviour
{
	void Start()
    {
    	Player player = FindObjectOfType<Player>();
        Enemy enemy = FindObjectOfType<Enemy>();
        UIElement uiElement = FindObjectOfType<UIElement>();
        //옵저버들을 플레이어에 등록
        player.RegisterObserver(enemy);
        player.RegisterObserver(uiElement);
        //플레이어 이동 시마다 등록된 옵저버들에게 알람
        player.Move();
    }
}

12. 상태 패턴(State Pattern)

  • 상태 패턴객체의 내부 상태에 따라 객체의 행동이 달라지는 상황에 사용하는 디자인 패턴
  • 게임 캐릭터 및 AI의 상태 관리에 사용
    1. Context(컨텍스트): 상태를 가지고 있는 객체로, 내부 상태가 변경될 때마다 적절한 행동을 수행
    • 게임 캐릭터 및 AI 등이 해당
    1. State(상태): 상태 패턴에서 상태를 나타내는 인터페이스
    • 컨텍스트에서 수행할 동작을 정의
    1. ConcreteState(구체적 상태): State 인터페이스를 구현한 클래스로 실제 특정 상태에서 실행될 동작을 구현
using UnityEngine;
// State 인터페이스
public interface IState
{
    void EnterState();
    void UpdateState();
    void ExitState();
}
// ConcreteState 1: 걷는 상태
public class WalkingState : IState
{
    private readonly Player player;
    public WalkingState(Player player)
    {
        this.player = player;
    }
    public void EnterState()
    {
        Debug.Log("Player enters Walking state");
    }
    public void UpdateState()
    {
        // 걷는 동작 수행
        player.Move();
    }
    public void ExitState()
    {
        Debug.Log("Player exits Walking state");
    }
}
// ConcreteState 2: 점프 상태
public class JumpingState : IState
{
    private readonly Player player;
    public JumpingState(Player player)
    {
        this.player = player;
    }
    public void EnterState()
    {
        Debug.Log("Player enters Jumping state");
    }
    public void UpdateState()
    {
        // 점프 동작 수행
        player.Jump();
    }
    public void ExitState()
    {
        Debug.Log("Player exits Jumping state");
    }
}
// Context 클래스: 상태를 관리하는 컨텍스트
public class Player : MonoBehaviour
{
    private IState currentState;
    public void SetState(IState state)
    {
        // 현재 상태를 종료하고 새로운 상태로 변경
        if (currentState != null)
        {
            currentState.ExitState();
        }
        currentState = state;
        currentState.EnterState();
    }
    void Update()
    {
        // 현재 상태의 동작을 실행
        if (currentState != null)
        {
            currentState.UpdateState();
        }
    }
    // 실제 게임 플레이어의 동작 메서드들
    public void Move()
    {
        Debug.Log("Player is walking...");
        // 이동 로직...
    }
    public void Jump()
    {
        Debug.Log("Player is jumping...");
        // 점프 로직...
    }
}
// 클라이언트 예시
public class Client : MonoBehaviour
{
    private Player player;
    void Start()
    {
        player = GetComponent<Player>();
        // 걷는 상태로 시작
        player.SetState(new WalkingState(player));
        // 점프 상태로 변경
        player.SetState(new JumpingState(player));
    }
}
  • Enum 클래스상태패턴은 병행됨
    • 클래스를 별도로 생성할 이유가 없어짐
    • 단 유지보수 면에서 코드의 독립성이 떨어짐
using UnityEngine;
// 열거형으로 정의된 상태
public enum PlayerState
{
    Walking,
    Jumping,
    Idle
}
// 컨텍스트 클래스: 상태를 관리하는 플레이어 클래스
public class Player : MonoBehaviour
{
    private PlayerState currentState;
    void Start()
    {
        // 초기 상태 설정
        currentState = PlayerState.Idle;
    }
    void Update()
    {
        // 현재 상태에 따른 동작 실행
        switch (currentState)
        {
            case PlayerState.Walking:
                Move();
                break;
            case PlayerState.Jumping:
                Jump();
                break;
            case PlayerState.Idle:
                // Idle 상태에서의 동작 (예: 대기)
                break;
            default:
                break;
        }
    }
    // 상태 변경 메서드
    public void ChangeState(PlayerState newState)
    {
        currentState = newState;
    }
    // 실제 게임 플레이어의 동작 메서드들
    private void Move()
    {
        Debug.Log("Player is walking...");
        // 이동 로직...
    }
    private void Jump()
    {
        Debug.Log("Player is jumping...");
        // 점프 로직...
    }
}
// 클라이언트 예시
public class Client : MonoBehaviour
{
    private Player player;
    void Start()
    {
        player = GetComponent<Player>();
        // 걷는 상태로 변경
        player.ChangeState(PlayerState.Walking);
        // 점프 상태로 변경
        player.ChangeState(PlayerState.Jumping);
    }
}

13. 전략 패턴(Strategy Pattern)

  • 여러 알고리즘을 하나의 추상적인 접근점(인터페이스)를 만들어 접근점에서 알고리즘이 서로 교환 가능하도록 하는 디자인 패턴
  • 객체의 동작을 클래스로 캡슐화하고, 이를 런타임에 변경하도록 해주는 디자인 패턴
  • 게임 캐릭터의 무기 교체 및 전략 선택 등에 사용
class Weapon
{
	IWeapon _weapon;
    void SetWeapon (IWeapon weapon) {_weapon = weapon; }
    void Shoot() { weapon.Shoot(); }
};
class Bullet : Weapon
{
	void Shoot() { Print("Bullet"); }
};
class Missile : Weapon
{
	void Shoot() { Print("Missile"); }
};
class Arrow : Weapon
{
	void Shoot() { Print("Arrow"); }
};
class WeaponManager
{
	Weaopn _w;
    void ChangeBullet() { _w.SetWeapon(new Bullet()); }
    void ChangeMissile() { _w.SetWeapon(new Missile()); }
    void ChangeArrow() { _w.SetWeapon(new Arrow()); }
    void Fire() { _w.Shoot(); }
};

14. 오브젝트 풀 패턴(Object Pool Pattern)

  • 메모리 공간에 사용할 객체를 미리 만들어 두고, 필요할 때 가져다 사용하는 패턴
    • 생성 & 삭제 [X]
    • 생성 -> 활성화 & 비활성화[O]
    • 최초 생성 객체 수를 넘어가는 경우 중간에 확장해서 생성할 수 있다.
    • 플레이웨이트와 비슷하지만, 플라이웨이트는 하나의 공유 데이터를 여러 객체가 공유해서 사용하여 메모리 중복을 피하는 것
    • 오브젝트 풀은 이미 만들어진 여러 객체를 필요할 때 사용하능한 객체를 가져다 사용하는 방식으로 1 : 1로 사용하고, 다 쓰면 반환하는 형식을 가진다.
      • 즉, 플라이웨이트처럼 여러 곳에서 동시에 사용하려는 목적이 아님
//게임 필드에 최대 몬스터 수 만큼 메모리 풀에 만들어두고, 비활성화 해줌
Monster[] monsterPool = new Monster[FIELD_MONSTER_MAX_SIZE];
for(int i = 0; i < FIELD_MONSTER_MAX_SIZE; ++i)
{
	monsterPool[i] = Instantiate(monster);
    monsterPool[i].SetActive(false);
}
//객체가 필요해 사용할때, 모두 활성화 되어있다면 객체 추가 생성 및 continue를 수행해야 함(자율 코드 작성)
for(int i = 0; i < FIELD_MONSTER_MAX_SIZE; ++i)
{
	if(monsterPool[i].GetActive) continue;
    monsterPool[i].position = GetRandomPositionInField();
    monsterPool[i].SetActive(true);
    break;
}
profile
GAME DESIGN & CLIENT PROGRAMMING

0개의 댓글

관련 채용 정보