Reiniciando el juego

Clase 31 de 34Curso de Desarrollo de Videojuegos Móviles con Unity

Resumen

Cuando un jugador pierde y quiere volver a intentarlo, el juego debe sentirse completamente fresco: una cuadrícula nueva, un marcador en cero y ninguna referencia a la partida anterior. Lograr este reinicio limpio del estado de juego es fundamental para ofrecer una experiencia fluida y profesional. A continuación se explica paso a paso cómo implementarlo en Unity, cubriendo la destrucción de piezas y la actualización de la interfaz de puntos.

¿Cómo destruir la cuadrícula y crear una nueva al reiniciar?

El problema inicial es claro: al presionar play again después del game over, las figuras anteriores permanecen y los puntos no se reinician [0:20]. La solución consiste en condicionar la creación de piezas al estado de juego y destruirlas cuando la partida termine.

Dentro de la clase Board, el primer cambio es envolver la corutina SetupPieces en una validación del estado actual del GameManager [1:05]:

csharp if (GameManager.Instance.GameState == GameManager.GameState.InGame) { StartCoroutine(SetupPieces()); }

De esta forma, las piezas solo se generan cuando el juego está activamente en curso.

¿Cómo suscribirse al evento de cambio de estado?

Para reaccionar a las transiciones entre estados, la clase Board se suscribe al evento OnGameStateUpdated del GameManager [1:18]:

csharp GameManager.Instance.OnGameStateUpdated.AddListener(OnGameStateUpdated);

Y en el método OnDestroy se elimina la suscripción con RemoveListener, una buena práctica que evita referencias a objetos destruidos y posibles errores en memoria.

La función OnGameStateUpdated recibe el nuevo estado como parámetro y ejecuta la lógica correspondiente [1:30]:

csharp private void OnGameStateUpdated(GameManager.GameState newState) { if (newState == GameManager.GameState.InGame) { StartCoroutine(SetupPieces()); } if (newState == GameManager.GameState.GameOver) { ClearAllPieces(); } }

¿Cómo eliminar todas las piezas del tablero?

La función ClearAllPieces recorre toda la cuadrícula usando dos bucles for anidados, uno para el ancho y otro para el alto, y llama a ClearPieceAt en cada coordenada [2:05]:

csharp private void ClearAllPieces() { for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { ClearPieceAt(x, y); } } }

Esta lógica reutiliza la función de eliminación individual que ya existía, lo que mantiene el código limpio y sin duplicaciones.

Una prueba rápida lo confirma: si el estado por defecto del GameManager se cambia a Idle, al dar play no aparece ninguna figura ni corre el temporizador [2:42]. Al regresar el estado a InGame, las piezas se generan, y tras perder, se destruyen correctamente antes de crear una nueva cuadrícula al presionar play again [3:10].

¿Cómo reiniciar el contador de puntos en la interfaz?

El segundo problema es que el marcador de puntos conserva el valor de la partida anterior [3:25]. La solución se aplica en la clase UIPoints.

Además de estar suscrita al evento OnPointsUpdated, ahora también se suscribe a OnGameStateUpdated [3:38]:

csharp GameManager.Instance.OnGameStateUpdated.AddListener(OnGameStateUpdated);

Dentro de esta nueva función, se verifica si el estado es GameOver y se reinician los valores mostrados [4:02]:

csharp private void OnGameStateUpdated(GameManager.GameState newState) { if (newState == GameManager.GameState.GameOver) { displayedPoints = 0; pointsLabel.text = displayedPoints.ToString(); } }

También se añade la desuscripción correspondiente en OnDestroy con RemoveListener para ambos eventos, manteniendo la consistencia con las buenas prácticas mencionadas anteriormente.

¿Cuál es el resultado final del reinicio completo?

Al ejecutar el juego tras estos cambios, el flujo completo funciona sin problemas [4:30]:

  • Las piezas se generan al entrar en estado InGame.
  • Al perder, todas las piezas se destruyen.
  • El contador muestra los puntos obtenidos en la pantalla de game over.
  • Al presionar play again, aparece una nueva cuadrícula con figuras diferentes y el marcador vuelve a cero puntos.

El patrón utilizado aquí, basado en eventos y listeners, permite que cada componente reaccione de forma independiente a los cambios de estado sin crear dependencias directas entre clases. Esto hace que el código sea más modular y fácil de extender.

¿Ya lograste que tu juego se reinicie correctamente? Comparte tu progreso en los comentarios.