본문 바로가기

IndianPoker

[10] 게임 구조 설계 겸 튜토리얼 장면 만들기

서버 제작이 잠시 보류된 상태니, 혼자서도 플레이 할 수 있도록 게임 구조를 만들어보자. 어차피 튜토리얼때문에 만들어야 한다.

우선, 게임은 게임 - 라운드 - 턴의 순서로 포함되어있다.

 

게임이 시작하면 사용할 덱과 카드들을 나눈다.

라운드가 시작하면 이번 라운드에 사용할 카드를 뽑는다. 이 카드가 사용이 끝나면 다음 카드를 뽑고 다음 라운드가 된다.

턴은 한 라운드에서 행동하는 사람이 바뀔 때마다(배팅을 진행할 때마다) 변화한다. 라운드마다 턴은 초기화된다.

 

그러니 우선적으로 필요한 함수는 게임 시작, 라운드 시작, 턴 교체에 대한 함수다. 이 셋을 만들어놓자.

    게임 시작
    public void StartGame()
    {
        InitGame();
    }
    //게임 시작 전 초기화, 덱과 카드, 칩과 배팅 등을 초기화.
    public void InitGame()
    {
        SetDeck();
        SetCards();
    }
    //라운드 시작 전 초기화, 칩과 배팅을 0으로
    public void InitRound()
    {
    	round++;
    }
    //턴이 바뀔 때 할 일. Game - Round - Turn 순서이다.
    public void ChangeTurn()
    {
        turn++;
    }

외부에서 StartGame() 함수를 실행시키면, 게임이 시작한다. 덱을 초기화하고, 카드를 나눠주는 것이다.

 

덱을 초기화하고, 카드를 나눠주면 이제 1라운드의 1턴이 시작된다. 이 턴을 누가 가져갈 것인가? 원래 이런 류의 게임에서는 동전던지기를 통해 순서를 정하는 법이다.

    public void TossCoin() // 게임의 맨 처음 실행.
    {
        myTurn = Random.Range(0, 2) == 0;
        if (myTurn)
        {
            Debug.Log("플레이어 1의 턴으로 시작합니다.");
        }
        else
        {
            Debug.Log("플레이어 2의 턴으로 시작합니다.");
        }
    }

 

순서를 정해주는 토스 코인 함수를 만든다. 이것을 게임 시작때 딱 한 번 던져서 맨 처음의 턴을 정할 것이다. 그 다음 라운드들은 그 전 라운드의 결과로 진행한다. 아직은 턴에 따른 행동이 없으므로, 텍스트로 알려주자.

 

그렇다면 게임의 구조를 순차적으로 보았을 때 입장해서 코인을 던져 턴을 정하는 것까지 완료되었다.

게임 시작 -> 게임 초기화 -> 덱 생성, 플레이어 카드 나눠주기 -> 선 턴 정하기, 까지 완료된 것이다.

 

이제는 각 턴에 해당하는 플레이어와 게임의 행동을 하나씩 구현해서 서로 이어주는 방식으로 구현을 이어나가자.

 

캡슐화를 잘 해서 각 기능을 조금씩 나눠두고, 마지막에 한 번에 액션등을 이용해서 이어나가는 방식으로 진행하자.

목록은 아래와 같다.

 

카드 뽑기(Cards의 0번째 카드가 손에 있는 것으로 취급하므로, 별도 구현 필요없다.)

배팅 전, 기본 테이블 세팅.(죽어도 잃는 기본 칩 설정)

처음 턴을 가진 플레이어의 Bet Phase.

턴을 넘겨받은 플레이어의 Raise Phase.

배팅이 완료된 이후의 승패판정.

 

이런 Bet 시스템과 Raise 시스템은 여러가지 조건이 얽혀서 까다로워지므로, 이름만 적어둔 이후 승패판정을 먼저 건드려보자.

    [SerializeField]
    private Button btnDie;
    [SerializeField]
    private Button btnCall;
    [SerializeField]
    private Button btnCheck;
    [SerializeField]
    private Button btnBbing;
    [SerializeField]
    private Button btnQuarter;
    [SerializeField]
    private Button btnHalf;
    [SerializeField]
    private Button btnDdadang;

Bet과 Raise에 해당하는 버튼들을 Buttons 오브젝트 하위에 넣어 에디터에서 할당해주자. 

Die는 포기, Call은 상대와 똑같은 금액. Check는 배팅 기회를 넘기는 것. Bbing은 최소 단위를 내는 것. Quarter, Half, Ddadang은 테이블 위의 칩의 1/4, 1/2, 동일한 양을 거는 것이다.

 

후에 무한 배팅이 되지 않도록 페이즈 설정을 잊지 말자.

 

턴에 해당하는 행동. 즉,배팅이 끝났다면 승패 판정을 통해 승리와 패배를 구현한다. 

    public void DecideWinLose()
    {
        if (myCards[0] > yourCards[0]) //승리
        {
            Debug.Log("이번 라운드는 당신의 승리!");
        }
        else if (myCards[0] < yourCards[0]) //패배
        {
            Debug.Log("이번 라운드는 당신의 패배...");
        }
        else //무승부
        {
            Debug.Log("이번 라운드는 무승부. 묻고 다음 판으로");
        }
    }

라운드의 종료시마다 각 플레이어가 가진 카드의 0번째 카드를 비교한다.

myCards.RemoveAt(0);
yourCards.RemoveAt(0);

그 이후, 0번째 카드를 지우면 완료. 만약 0번째 카드가 없다면 라운드 진행이 불가능해지기에, 게임의 종료가 되는 로직을 짜면 될 것이다. 

 

이것으로 비교 - 승패판정 로직이 끝났다. 다음은 플레이어의 테이블 칩 이동이다. 

    public void BetChip()
    {
        if(myChips >= myBet)
        {
            myChips -= myBet;
            tableChips += myBet;
        }
        else
        {
            Debug.Log("칩이 부족합니다.");
        }
    }
    public void GetChip()
    {
        myChips += tableChips;
        tableChips = 0;
    }

플레이어의 칩 이동이라고는 했지만, 플레이어끼리 직접적으로 칩을 주고 받지는 않는다. 플레이어는 테이블 위에 칩을 올려놓는 동작과 올려놓은 칩을 모두 가져가는 동작 두개만 존재하면 문제없이 기능한다.

 

그래서 테이블 위에 칩을 올려놓는 BetChip(), 승리해서 테이블 위의 칩을 모두 가져오는 GetChip()을 만들어놓자.

 

이것으로 기본적인 기능의 명시는 끝났다. 그러나 아직 에디터와의 연동이 이루어지지 않았고, 각각의 구체적인 내용과 유기적인 연결이 되지 않은 상태이다.

 

그런고로 다음에는 Battle Scene의 게임 보드를 직접 제작하며 위의 스크립트를 어떻게 배치할 지 고민해보도록 하자.