Como criar um GameManager?
Para criar esse GameManager vamos considerar um jogo de turnos. (Exemplo: Pokemon, Yu-Gi-Oh, Final Fantasy, etc.)
De cara já vamos criar uma classe e chama-la de GameManager. E logo a baixo criaremos um enumeration chamado GameState.
public class GameManager : MonoBehaviour {
}
public enum GameState {
PlayerTurn = 1,
EnemyTurn = 2,
Decide = 3,
Victory = 4,
Lose = 5,
}
O enum GameState vai nos garantir uma leitura mais fácil do nosso código. Além disso, criamos o enum fora da classe porque dessa forma podemos acessa-lo globalmente sem precisar do GameManager.
Para saber qual o GameState atual do seu jogo precisaremos de uma variável que salve esse valor e que possa ser acessada de qualquer lugar. Além disso, criaremos também um singleton para facilitar o acesso de outros arquivos ao GameManager.
public class GameManager : MonoBehaviour {
public static GameManager Instance { get; private set; }
private static GameState _currentState;
[field: SerializeField]
public static GameState CurrentState {
get {
return _currentState;
}
}
private void Awake() {
Instance = this;
}
}
public enum GameState {
PlayerTurn = 1,
EnemyTurn = 2,
Decide = 3,
Victory = 4,
Lose = 5,
}
Após isso, precisamos criar um método para lidar com as trocas e todas as possibilidades de GameState, então criaremos o método ChangeState()
public class GameManager : MonoBehaviour {
public static GameManager Instance { get; private set; }
private static GameState _currentState;
[field: SerializeField]
public static GameState CurrentState {
get {
return _currentState;
}
}
private void Awake() {
Instance = this;
}
public void ChangeState(GameState newState) {
_currentState = newState;
switch (_currentState) {
case GameState.PlayerTurn:
break;
case GameState.EnemyTurn:
break;
case GameState.Victory:
break;
case GameState.Lose:
break;
default:
break;
}
}
}
public enum GameState {
PlayerTurn = 1,
EnemyTurn = 2,
Decide = 3,
Victory = 4,
Lose = 5,
}
Agora que temos já uma boa parte do código feita, precisamos criar os métodos para cada State, então faremos assim.
public class GameManager : MonoBehaviour {
public static GameManager Instance { get; private set; }
private static GameState _currentState;
[field: SerializeField]
public static GameState CurrentState {
get {
return _currentState;
}
}
private void Awake() {
Instance = this;
}
public void ChangeState(GameState newState) {
_currentState = newState;
switch (_currentState) {
case GameState.PlayerTurn:
HandlePlayerTurn();
break;
case GameState.EnemyTurn:
HandleEnemyTurn();
break;
case GameState.Decide:
HandleDecide();
break;
case GameState.Victory:
HandleVictory();
break;
case GameState.Lose:
HandleLose();
break;
default:
Debug.Log("Não faz nada ou joga um erro!");
break;
}
}
private voic HandleLose() {
Debug.Log("Mostra uma UI de DERROTA");
}
private voic HandleVictory() {
Debug.Log("Mostra uma UI de VITÓRIA");
}
private voic HandleDecide() {
Debug.Log("Irá decidir o que acontece depois do turno");
Debug.Log("Caso o jogador esteja morto, vai mudar o estado para GameState.Lose");
Debug.Log("Caso o inimigo esteja morto, vai mudar o estado para GameState.Victory");
Debug.Log("Caso nenhum dos dois estejam mortos o jogo segue para o próximo turno");
}
private voic HandleEnemyTurn() {
Debug.Log("Impede que o jogador jogue nesse turno!");
Debug.Log("Deixa o inimigo jogar nesse turno!");
}
private voic HandlePlayerTurn() {
Debug.Log("Impede que o inimigo jogue nesse turno!");
Debug.Log("Deixa o jogador jogar nesse turno!");
}
}
public enum GameState {
PlayerTurn = 1,
EnemyTurn = 2,
Decide = 3,
Victory = 4,
Lose = 5,
}
E com isso temos um GameManager funcional. Claro que será necessário alguns ajustes a depender do seu jogo, mas temos uma boa base para avançar e continuar o desenvolvimento do projeto.
Um exemplo de uso seria a seguinte possibilidade, imagine que você tem uma UI que mostra as possíveis ações do jogador, e uma dessas ações é encerrar o turno. No onClick desse botão você colocaria o seguinte método.
public void FinishTurn() {
// Estamos mudando o estado para Decide
// Por que esse estado é responsável por saber se o inimigo morreu
// Ou se está vivo, para decidir se o jogo acabou ou se vai para
// O próximo turno
GameManager.Instance.ChangeState(GameState.Decide);
}
Nesse post passamos por alguns detalhes que não me aprofundei muito, porque pretendo fazer outras publicações sobre cada tema, como por exemplo, singletons, enumerations, propriedade auto-implementada, uma ideia de padrões para nomes de variáveis, ideias de como organizar o inspector entre outras coisas.
Quero aproveitar esse espaço para pedir a sua ajuda, esse é a minha primeira publicação aqui, e estou aceitando críticas construtívas, então se tiver algo que você reparou que possa me ajudar a melhorar, se tiver algo a acrescentar ou algo a corrigir, por favor me avise, ficarei muito feliz e agradecido com o feedback.
Bom, é isso, espero que tenha tido alguma utilidade para você e caso tenha dificuldade em algo ficarei feliz em ajudar no que eu puder.
:}
Créditos
Me inspirei bastante nesse vídeo do Tarodev.