반응형

 

게임 개발은 객체 생성과 관리가 핵심적인 역할을 합니다. 이를 효율적으로 다루기 위해 Factory 패턴은 유니티(Unity)에서 강력한 디자인 패턴 중 하나로 사용됩니다. Factory 패턴은 게임 오브젝트나 컴포넌트 등의 생성과 관리를 추상화하여 코드의 가독성, 유지보수성, 그리고 재사용성을 향상시키는 데 도움을 주는 패턴입니다.

Factory 패턴이란?

Factory 패턴은 객체 생성 로직을 별도의 클래스로 분리하는 디자인 패턴입니다. 이를 통해 개체 생성에 대한 세부 사항을 숨기고, 클라이언트 코드가 생성 프로세스를 알 필요 없이 객체를 생성할 수 있게 됩니다. Factory 패턴은 크게 두 가지 형태로 나뉩니다.

  • 단순 팩토리(Simple Factory) 객체 생성을 위한 인터페이스를 제공하고, 클라이언트에게 어떤 클래스를 생성할 것인지 선택하는 책임을 지게 합니다. 유니티에서는 이 패턴을 자주 사용합니다.
  • 추상 팩토리(Abstract Factory) 여러 종류의 관련된 객체를 생성하며, 이러한 객체들이 함께 작동할 수 있도록 보장합니다. 일반적으로 복잡한 시스템에서 사용됩니다.

 

햄버거 가게를 상상해보세요. 햄버거 가게는 다양한 종류의 햄버거를 만듭니다. 이 가게에서는 각 햄버거를 주문할 때마다 주문한 종류에 따라 조리과정이 달라집니다. Factory 패턴을 사용하여 이 가게의 동작을 설명해보겠습니다.
햄버거 공장 (Hamburger Factory) 이 공장은 다양한 종류의 햄버거를 만들어내는 곳입니다. 이 팩토리는 주문받은 햄버거의 종류에 따라 다른 햄버거를 생성합니다.
햄버거 (Hamburger) 각각의 햄버거는 고유한 레시피와 재료를 가지고 있습니다. 팩토리는 이 햄버거를 만들 때 필요한 재료와 조리 방법을 알고 있습니다.
주문 (Order) 고객이 원하는 햄버거 종류를 주문합니다. 예를 들어, "치즈버거 주세요" 라고 주문하면, 팩토리는 치즈버거를 만들어 제공합니다.
서비스 (Service) 팩토리는 주문을 받고, 그에 맞는 햄버거를 만들어내며, 최종적으로 손님에게 제공합니다.

Factory 패턴을 사용하면 고객은 어떤 햄버거가 만들어지는지, 어떤 재료와 레시피가 사용되는지 신경 쓸 필요 없이 주문만 하면 됩니다. 팩토리가 주문에 따라 올바른 햄버거를 만들어주기 때문입니다.

이런 방식으로 Factory 패턴은 객체를 생성하고 초기화하는 복잡한 작업을 추상화하며, 클라이언트가 생성 과정을 신경 쓰지 않고 필요한 객체를 얻을 수 있도록 도와줍니다.

 

Factory 패턴의 장점

  • 유연성: 객체 생성 방법을 중앙에서 관리하므로 생성 로직 변경 시 코드 수정이 최소화됩니다.
  • 유지보수성: 객체 생성 코드가 중앙 집중화되므로 유지보수가 쉬워집니다.
  • 재사용성: 객체 생성 로직을 재사용 가능한 컴포넌트로 만들어 코드의 재사용성을 향상시킵니다.

 

Factory 패턴 간단한 실 예제

게임에서 캐릭터를 생성해야 한다고 가정해봅시다. 캐릭터의 생성은 다양한 속성과 초기화 과정이 포함될 수 있습니다.

using UnityEngine;

public class CharacterFactory : MonoBehaviour
{
    public GameObject playerPrefab; // 플레이어 프리팹을 할당할 변수
    public GameObject enemyPrefab;  // 적 캐릭터 프리팹을 할당할 변수

    // 플레이어 캐릭터를 생성하는 메서드
    public GameObject CreatePlayer(Vector3 position)
    {
        GameObject player = Instantiate(playerPrefab, position, Quaternion.identity);
        return player;
    }

    // 적 캐릭터를 생성하는 메서드
    public GameObject CreateEnemy(Vector3 position)
    {
        GameObject enemy = Instantiate(enemyPrefab, position, Quaternion.identity);
        return enemy;
    }
}

 

위의 코드에서 CharacterFactory 클래스는 플레이어와 적 캐릭터를 생성하는 두 가지 메서드를 제공합니다. 클라이언트는 이 팩토리 클래스를 사용하여 필요한 캐릭터를 생성하고 초기화할 수 있습니다.

using UnityEngine;

public class CharacterSpawner : MonoBehaviour
{
    public CharacterFactory characterFactory; // 팩토리 클래스를 할당할 변수

    void Start()
    {
        // 플레이어 생성
        GameObject player = characterFactory.CreatePlayer(new Vector3(0, 0, 0));
        
        // 적 생성
        GameObject enemy = characterFactory.CreateEnemy(new Vector3(5, 0, 0));
    }
}

 

위의 CharacterSpawner 스크립트에서 CharacterFactory 클래스를 사용하여 플레이어와 적을 생성할 수 있습니다.

 

이 예제 외에도

총알을 발사하는 과정에서 총알마다 각기 다른 사거리, 속도, 데미지 등을 설정하고

필요한 상황에 맞게 어떤 총알을 생성하여 어떻게 발사할지 관리하게 만들 수도 있겠죠.

마치며

Factory 패턴을 이용하면 게임 오브젝트 생성과 관리를 효율적으로 다룰 수 있으며, 복잡한 게임에서 객체 생성과 초기화를 효과적으로 관리할 수 있습니다. Factory 패턴은 유니티 프로젝트에서 객체 생성과 관리에 있어서 필수적인 디자인 패턴 중 하나입니다.

 

이런 Factroy 패턴으로 코드를 작성한다면 생성하는 부분과 관리하는 부분을 별도로 가지고있기에 오류가 생길 확률이 적어집니다.

또한, 오브젝트 풀링과도 많은 연관이 있기에 잘 이용한다면 관리가 쉬운 코드를 짤수있습니다.

반응형
반응형

오랜만의 포스팅을 싱글톤으로 하게 되었네요.

 

 

일단 제 기준으로 유니티에서 사용하기 편하고 관리하기 쉬운 방법의 싱글톤 예제를 가지고 왔습니다.

 

싱글톤의 역할

싱글톤은 프로그래밍 디자인 패턴 중 추상 객체 인스턴스 생성 패턴 중의 하나로

유니티에서 싱글톤의 역할은

 

1. 게임 시스템에서 전체를 관장하는 스크립트(단일 시스템 자원 관리 차원)

2. 게임 시스템상 전역 변수의 역할을 하는 스크립트

3. 씬 로드시 데이터가 파괴되지 않고 유지

4. 여러 오브젝트가 접근을 해야 하는 스크립트의 역할

5. 단 한개의 객체만 존재(게임 전체를 관장하는 스크립트가 둘 이상 있으면 꼬이겠죠?)

 

등등 많겠지만 결론은 다 같은 말이죠? 네 이 모든 역할을 할 수 있는게 Singleton Pattern입니다.

 

 

아마 새로운 씬을 로드를 하게 되면 앞에 있던 변수들은 전부 파괴되고 새로운 씬이 로드가 될 거예요.

하지만 싱글톤은 씬 이동시 자신을 파괴하지 않으면서 자신이 가진 데이터들 또한 함께 유지한답니다.

 

실습 예제 및 스크립트

씬이 이동되면서 내 골드의 정보가 초기화 되는 것을 알 수 있습니다.

 

위 그림과 같은 경우로

유니티 내에서 씬과 씬 사이를 넘어갈 때 앞의 씬에서 데이터를 받아와서 다음 씬에서 받고 싶을 때 사용할 수 있어요.

 

그럼 MyGold 가 씬이 이동이 되어도 계속해서 유지할 수 있는 방법을 알아볼게요

 

저는 우선 "GameManager"라는 이름의 스크립트를 만들었습니다.

많은 사람들이 GameManager라는 이름으로 스크립트를 사용 하다보니 유니티에서 아이콘을 바꿔주네요.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameManager : MonoBehaviour
{
    /* // 싱글톤 //
     * instance라는 변수를 static으로 선언을 하여 다른 오브젝트 안의 스크립트에서도 instance를 불러올 수 있게 합니다 
     */
    public static GameManager instance = null; 

    private void Awake()
    {
        if (instance == null) //instance가 null. 즉, 시스템상에 존재하고 있지 않을때
        {
            instance = this; //내자신을 instance로 넣어줍니다.
            DontDestroyOnLoad(gameObject); //OnLoad(씬이 로드 되었을때) 자신을 파괴하지 않고 유지
        }
        else
        {
            if (instance != this) //instance가 내가 아니라면 이미 instance가 하나 존재하고 있다는 의미
                Destroy(this.gameObject); //둘 이상 존재하면 안되는 객체이니 방금 AWake된 자신을 삭제
        }
    }

    //게임 내에서 씬이동시 유지하고 픈 골드 값(변수)
    public int myGold = 0;
}

 위와 같이 스크립트를 짜주시고, 각 씬의 하이라키창에 빈 오브젝트(Empty Object)를 생성해줍니다.

 

이러면 준비 끝!

이제 어디서든

GameManager.instance.(변수 혹은 함수명)

으로 불러 줄 수 가 있게 되었습니다!

 

지금 의 예제로는

GameManager.instance.myGold 라고 불러 줄 수 가 있겠네요.

 

그럼 Main 씬에서 '돈 벌기' 버튼을 눌렀을때 아래가 작동이 되는 스크립트를 만들어주고,

GameManager.instance.myGold += 2;

씬을 이동(상점) 후, 아이템 구매마다 해당하는 가격만큼 myGold가 줄어들게 설정을 하고 테스트를 해보면..

GameManager.instance.myGold -= (아이템가격);

 

씬 이동을 했음에도 'GameManager'가 파괴되지 않아, 'MyGold' 변수 값이 유지가 되는 모습 
플레이 중에 하이라키에서도 씬 이동이 계속 되어짐에도 GameObject(GameManager Componenet가 들어있는)가 지워지지 않고 유지되고 있다.

주의할 점

쉽게 사용이 가능하다보니 되나 가나 모든 데이터,

객체 등을 이곳에 마구잡이로 때려 넣으면 안 된다는 것!!

 

접근이 쉽다보니 막 갖다쓰다보면 비대칭적인 크기로 게임이 만들어지게되고,

나중에 다시 재정리 하려면 이미 꼬일대로 꼬인 상황이 올거에요.

장담합니다 막 갖다쓰다보면 봅니다.

반응형

+ Recent posts