저번주에 만들었던 틱택토를 내부에서 수정하실 것.
지금은 GameManager 코드가 대부분의 일을 하지만, 수정해서 UI 관련된 일만 수행하고
게임의 플레이에 관한 것은 GameLogic을 만들어서 수정하시려고 한다..
GameLogic함수는 굳이 MonoBehaviour를 상속할 필요 없음
GameLogic이 State를 관리하면서
해당 턴에 알맞은 state를 ! Enter, Exit 하면서 진행된다.
public interface IPlayerState
{
void OnEnter(GameLogic gameLogic);
void OnExit(GameLogic gameLogic);
void HandleMove(GameLogic gameLogic, int row, int col);
}
public abstract class BasePlayerState : IPlayerState
{
public abstract void OnEnter(GameLogic gameLogic);
public abstract void OnExit(GameLogic gameLogic);
public abstract void HandleMove(GameLogic gameLogic, int row, int col);
protected abstract void HandleNextTurn(GameLogic gameLogic);
protected void ProcessMove(GameLogic gameLogic, Constants.PlayerType playerType, int row, int col)
{
if (gameLogic.SetNewBoardValue(playerType, row, col))
{
var gameResult = gameLogic.CheckGameResult();
if (gameResult == GameLogic.GameResult.None)
{
HandleNextTurn(gameLogic);
}
else
{
gameLogic.EndGame(gameResult);
}
}
}
}
//직접 플레이 (온라인 싱글 )
public class PlayerState : BasePlayerState
{
}
state로 해 줄 예정.
굳이 인터페이스를 쓸 필요가 없어서 지워주었음
공통된 작업( 게임이 끝났는지 검사하고 다음 턴으로 넘기는 작업) 은 Base에서 진행해주고,
나머지 다른 부분은 각 State에서 진행해준다.
게임의 전체적인 구조는 이렇게 된다.
public void SetState(BasePlayerState state)
{
_currentPlayerState?.OnExit(this);
_currentPlayerState = state;
_currentPlayerState.OnEnter(this);
}
중요한 것은 위 코드 들어가고 나갈때 실행되는 OnExit와 OnEnter를 실행해준다.
public override void OnEnter(GameLogic gameLogic)
{
gameLogic.blockController.OnBlockClickedDelegate = (row, col) =>
{
HandleMove(gameLogic, row, col);
};
}
public override void HandleMove(GameLogic gameLogic, int row, int col)
{
ProcessMove(gameLogic, _playerType, row, col);
}
protected void ProcessMove(GameLogic gameLogic, Constants.PlayerType playerType, int row, int col)
{
if (gameLogic.SetNewBoardValue(playerType, row, col))
{
var gameResult = gameLogic.CheckGameResult();
if (gameResult == GameLogic.GameResult.None)
{
HandleNextTurn(gameLogic);
}
else
{
gameLogic.EndGame(gameResult);
}
}
}
이런 사이클이 있다.
HandleMove에는 각각의 고유한 행동들이 들어가고, ProcessMove에는 공통적인 부분이 들어간다.
이를 통해 다음 턴으로 넘길 것인지, 혹은 게임을 종료할 것인지를 판단한다.
protected override void HandleNextTurn(GameLogic gameLogic)
{
if (_isFirstPlayer)
{
gameLogic.SetState(gameLogic.secondPlayerState);
}
else
{
gameLogic.SetState(gameLogic.firstPlayerState);
}
}
다음 턴으로 넘길 때에는 현재 자신의 상태에 따라 넘긴다.
멤버변수로 선언할 때는 가급적이면 Prviate....힘들다면 Getter만 할 수 있도록
쓰기 전용 메서드는 거의 없다.
보통 같이 있음. (ReadOnly거나)
이런 식으로 기본 구조를 만들어 두면, 확장이 편하다.
AI로 할 떄는 그냥 AI상태에서 할 것만 정의해 주면 된다.
(MinMax알고리즘을 활용해서 하나의 타일을정하고, 그 타일에 SetMarker한다음 다음 턴으로)
public class AIState : BasePlayerState
{
public override void OnEnter(GameLogic gameLogic)
{
// AI 연산
var result = MinimaxAIController.GetBestMove(gameLogic.GetBoard());
if (result.HasValue)
{
HandleMove(gameLogic, result.Value.row, result.Value.col);
}
else
{
gameLogic.EndGame(GameLogic.GameResult.Draw);
}
}
public override void OnExit(GameLogic gameLogic)
{
}
public override void HandleMove(GameLogic gameLogic, int row, int col)
{
ProcessMove(gameLogic, Constants.PlayerType.PlayerB, row, col);
}
protected override void HandleNextTurn(GameLogic gameLogic)
{
gameLogic.SetState(gameLogic.firstPlayerState);
}
}
확장이 매우 편해진 것을 알 수 있다.
이제 멀티플레이 관련으로 코드 진행해서 끝 !
내일부터는 오목이다.
'TIL' 카테고리의 다른 글
[멋쟁이사자처럼 부트캠프 TIL 회고] 03.12 : 오목 만들기 (0) | 2025.03.12 |
---|---|
[멋쟁이사자처럼 부트캠프 TIL회고] Unity 게임개발 0307 : 채팅, 멀티플레이 (0) | 2025.03.07 |
[멋쟁이사자처럼 부트캠프 TIL회고] Unity게임개발 0306 : Parsing, Socket.IO (0) | 2025.03.07 |
[멋쟁이사자처럼 부트캠프 TIL회고] Unity게임개발 3기 0305 : 유니티와 서버 (0) | 2025.03.05 |
[멋쟁이사자처럼 부트캠프 TIL회고] Unity 게임 개발 : 0304 서버 맛보기 (0) | 2025.03.04 |