목차
1. Scene 관리 시스템
    □ 의도
    □ 설계
2. Scene 관리 구현방법과 상세 설명
    □ IScene 인터페이스
    □ GameManager
    □ 전환 관리
    □ 실제 사용 예시
3. 싱글톤 시스템
    □ 의도
    □ 설계
    □ 개선사항
4. 싱글톤 구현방법과 상세설명

 

📝 Scene 관리 시스템

1. 의도

: 게임의 각 상태 (로비, 인벤토리, 상점 등)를 Scene으로 관리하고, Scene 간의 전환을 관리하기 위해서 

 

2. 설계

□ SceneType라는  Enum을 통해 게임 Scene 타입 정의

□ IScene 인터페이스를 통해 각 Scene을 공통된 타입으로 관리

□ 씬 전환을 GameManager 를 통해 중앙에서 관리

 

📝 Scene 관리 구현방법과 상세 설명 

1. IScene 인터페이스

interface IScene
{
    // 씬에 들어갔을 때 
    public void SceneEntry();

    // 씬에서 메인으로 동작할 로직
    public void SceneMainFlow();
}

: 각 Scene이 필수로 구현해야할 동작을 정의한다.

          □ SceneEntry()

                     ■ Scene에서 초기 화면 구성 등의 기능이 실행된다.

          □ SceneMainFlow()

                       각 Scene에서 필요한 플레이어 입력처리, 상태 업데이트, 화면 출력 등의 기능이 실행된다.

 

2. 📝 GameManager.cs

enum SceneType 
{
    LobbyScene,
    PlayerScene,
    InventoryScene,
    StoreScene,
    RestScene,
    DungeonScene
}

class GameManger : Singleton<GameManger>    
{
    // 씬 저장 리스트 
    private IScene[] gameScene;
    private IScene nextScene;
    private IScene preScene;

    public GameManger() 
    {
        int temp = Enum.GetNames(typeof(SceneType)).Length;
        gameScene = new IScene[temp];

        gameScene[(int)SceneType.LobbyScene]        = LobbyScene.Instance;
        gameScene[(int)SceneType.PlayerScene]       = PlayerManager.Instance;
        gameScene[(int)SceneType.InventoryScene]    = InventoryManger.Instance;
        gameScene[(int)SceneType.StoreScene]        = StoreManager.Instance;
        gameScene[(int)SceneType.RestScene]         = RestScene.Instance;
        gameScene[(int)SceneType.DungeonScene]      = DungeonScene.Instance;

        nextScene = gameScene[0];
    }
}

□  Scene관리를 위한 배열 

           ■ IScene 인터페이스 타입의 배열을 선언 -> 모든 Scene을 하나의 컨테이너에서 관리

            nextScene과 preScene 변수를 통해 Scene 전환 추적 가능 

□   Scene 등록

           ■ SceneType enum의 개수 만큼 배열 크기 동적할당

            enum 값을 인덱스로 활용하여 Scene 인스턴스를 매핑 

 

3. 씬 전환 관리

public void ChangeScene(SceneType type) 
{
    // 지금 씬 = 예전 씬으로
    preScene = nextScene;

    // 현재 씬 지정 
    nextScene = gameScene[(int)type];

    // 현재씬 실행 
    if (preScene != nextScene)
        nextScene.SceneEntry();

    nextScene.SceneMainFlow();
}

□ 전환 로직  

           ■  이전 Scene 기록을 통해 히스토리 관리             

           ■  SceneType enum의 인덱스에 해당하는 Scene을 현재 Scene으로 지정

□ Scene Entry() 실행

           ■  이전 씬과 다른 Scene Type의 Scene인 경우에만 SceneEntry()를 실행

           ■   불필요한 출력 방지 

□ Scene MainFlow() 실행 

           ■  해당 Scnen의 주요 기능 실행 

           ■  입력처리 / 상태 업데이트 / 화면 출력 등을 실행 

 

4. 실행 예시 

 

-📝 LobbyScene.cs

private void ChangeScene(int input) 
{  
    switch (input) 
    {
        case 0:
            // 플레이어 출력 
            PlayerManager.Instance.printPlayer();
            // 로비로 씬 전환 
            GameManger.Instance.ChangeScene(SceneType.LobbyScene);
            break;
        case 1:
            // 인벤토리로 씬 전환 
            GameManger.Instance.ChangeScene(SceneType.InventoryScene);
            break;
        case 2:
            // 상점으로 씬 전환 
            GameManger.Instance.ChangeScene(SceneType.StoreScene);
            break;
        case 3:
            // 던전 씬 전환
            GameManger.Instance.ChangeScene(SceneType.DungeonScene);
            break;
        case 4:
            // 휴식
            GameManger.Instance.ChangeScene(SceneType.RestScene);
            break;
        case 5:
            // 저장 
            GameManger.Instance.SaveData();
            break;
        default:
            Console.WriteLine("잘못된 접근입니다. 다시 로비로 돌아갑니다");

            // Lobby로 돌아가기
            GameManger.Instance.ChangeScene(SceneType.LobbyScene);
            break;

    }
}

□  ChangeScene(int input) 

           ■   사용자 입력(input)에 따라 적절한 Scene으로 이동


📝 Singleton 관리 

1. 의도

: 유니티 프로젝트를 하면서 싱글톤을 상위 클래스로 만들어서 관리한 적이 있는데 편리했던 기억이 있어서 c#에서도 편리할 거라고 예상했다. 

 

2. 설계

□ 제네릭을 사용하여 다양한 타입의 클래스를 생성할 수 있도록 선언

 

3. 개선사항

: 상속을 사용하지 않고 클래스에 static을 붙여 전역에서 사용하는 방법도 가능할 것 같다.

 

📝 Singleton관리 구현방법과 상세 설명 

 

1. 📝 Singleton<T>.cs

class Singleton<T>
    where T : class , new()
{
    private static T instance;

    public static T Instance
    {
        get 
        {
            if (instance == null)
                instance = new T();

            return instance;
        }
    }

}

□ 제네릭 <T>

           ■  다양한 참조 타입의 인스턴스 생성이 가능

           ■  where 제약조건을 통해 <T>는 참조타입 class와 매개변수가 없는 생성자를 가진 클래스만 허용

□ Instance 프로퍼티

           ■  최초 호출 시 인스턴스를 생성하며, 이후에는 동일한 인스턴스를 반환 

 


📝 깃허브

https://github.com/kimYouChae/SpartaCodingClub

 

GitHub - kimYouChae/SpartaCodingClub

Contribute to kimYouChae/SpartaCodingClub development by creating an account on GitHub.

github.com

 


📝 추후

: 저장시스템

: 아이템 구조 or 관리 방법

Interface란 

- 무엇을 해야 하는가에 대한 정의

     - 어떻게 구현할지는 명시하지 않는다.

- 실제로 "어떻게 구현하는가"는 하위 클래스에서 구현.

 

인터페이스의 특징 

1. 접근 제한 한정자를 가질 수 없다. public으로만 선언 가능하다.

: private으로 선언할 수 없다. 

 

2. 필드(변수)를 선언할 수 없다.

 

3. 인터페이스에 선언되는 메서드는 구현부를 가지지 않는다.

internal interface Interface1
{

    public 반환형 메서드이름();
    public 반환형 메서드이름();

    public int myProperty { get; set; }
}

 

c# 8.0 버전은 조금 다르다 그냥 참고만 하자! 

더보기

c# 8.0 버전에는 인터페이스의 메서드가 구현부를 가질 수 있다.

internal interface Interface1
{

    public 반환형 메서드이름 ();

    반환형 메서드이름()
    {
        Console.WriteLine("기본 구현입니다.");
    }

    public int myProperty { get; set; }
}

 

 

4. 클래스는 여러 인터페이스를 상속받을 수 있다.

interface Outerface2 
{
    public void OuterfaceMethod();
}

// 인터페이스 두개를 상속받은 클래스 
public class abcClase : Interface1 , Outerface2
{
        
}

 

5. 상속받은 인터페이스의 메서드를 반드시 구현해야 한다.

: 구현하지 않으면 "인터페이스 멤버를 구현하지 않습니다"라는 오류가 뜬다.

 

6. 인터페이스를 구현한 클래스의 인스턴스는 모두 같은 인터페이스 타입이다.

internal interface Interface1
{

    public void TestFunction();
}

// 인터페이스를 상속받는 클래스 1
public class temp1 : Interface1
{
    public void TestFunction()
    {
        
    }
}

// 인터페이스를 상속받는 클래스 2 
public class temp2 : Interface1
{
    public void TestFunction()
    {

    }
}

 

    static void Main(string[] args)
    {
        Interface1[] inter = new Interface1[2];
        inter[0] = new temp1();
        inter[1] = new temp2();
    }

: temp1과 temp2 클래스는 모두 Interface1이라는 인터페이스를 상속받았으므로 같은 타입이다. 

 

7. 인터페이스 안에는 메서드뿐만 아니라 프로퍼티 / 인덱서 / 이벤트도 가능하다.

출처 : microsoft 공식 c# interface 문서

 

 

8. 인터페이스는 인스턴스를 만들 수 없다.

 

 


추상클래스 vs interface

  추상클래스 abstract class 인터페이스 interface
공통점  
메서드 오버라이딩 하위 클래스는 반드시 메서드를 오버라이딩 해야한다.
인스턴스 인스턴스화 ( ex)new 키워드 사용 ) 불가능 
차이점    
필드 가질 수 있다. 가지지 못한다.
상속 인터페이스와 클래스 모두 상속가능 인터페이스 밖에 상속받지 못함.
생성자 가질 수 있다. 가지지 못한다.
메서드 구현  메서드 구현가능 메서드 구현 불가능

 


인터페이스 명명 규칙 

: 인터페이스 이름은 대문자 "I"로 시작한다.

public interface IAttack
{
    void IAttackMethod();
}

public interface ITracking 
{
    void ITrackinMethod();
}

도움이 된 링크
<interface>

https://learn.microsoft.com/ko-kr/dotnet/csharp/language-reference/keywords/interface

 

interface 키워드 - C# reference

'인터페이스' 키워드를 사용하여 모든 구현 형식이 지원해야 하는 계약을 정의합니다. 인터페이스는 관련되지 않은 형식 집합 간에 공통 동작을 만드는 수단을 제공합니다.

learn.microsoft.com

 

<명명규칙>

https://learn.microsoft.com/ko-kr/dotnet/csharp/fundamentals/coding-style/identifier-names

 

식별자 이름 - 규칙 및 관례 - C#

C# 프로그래밍 언어의 유효한 식별자 이름에 대한 규칙을 알아봅니다. 또한 .NET 런타임 팀과 .NET 문서 팀에서 사용하는 일반적인 명명 규칙을 알아봅니다.

learn.microsoft.com

 

 

+ Recent posts