Cuando se genera la cuadrícula de un juego match 3, es común que aparezcan tres piezas iguales alineadas desde el inicio, algo que rompe la experiencia del jugador. La solución consiste en verificar cada pieza al momento de crearla y, si genera un match con las piezas ya existentes, destruirla y reemplazarla hasta obtener una combinación válida. Este enfoque garantiza que el tablero siempre arranque limpio y listo para jugar.
¿Cómo separar la creación de piezas en su propia función?
El primer paso es extraer la lógica de creación de piezas de la función SetupPieces y moverla a una función independiente llamada CreatePieceAt [01:10]. Esta función recibe dos parámetros: la posición en X y la posición en Y donde se colocará la pieza.
Un detalle importante es que CreatePieceAt ya no es de tipo void, sino que retorna un componente de tipo Piece [01:35]. Esto permite que, al llamarla desde SetupPieces, se pueda almacenar la referencia de la pieza recién creada en una variable local:
csharp
Piece newPiece = CreatePieceAt(x, y);
De esta forma, la pieza queda disponible para las validaciones posteriores sin duplicar código.
¿Por qué no se puede reutilizar GetMatchByPiece para validar la cuadrícula inicial?
La función GetMatchByPiece busca coincidencias en cuatro direcciones: arriba, abajo, izquierda y derecha. Sin embargo, las piezas se crean desde la esquina inferior izquierda hacia arriba y hacia la derecha [02:30]. Cuando se está colocando una pieza nueva, las posiciones superiores y a la derecha todavía no existen.
Por esta razón se crea una función específica llamada HasPreviousMatches [03:05], que solo busca coincidencias en dos direcciones:
Hacia abajo: usando el vector (0, -1).
Hacia la izquierda: usando el vector (-1, 0).
csharp
bool HasPreviousMatches(int posX, int posY)
{
var downMatches = GetMatchByDirection(posX, posY, new Vector2(0, -1), 2);
var leftMatches = GetMatchByDirection(posX, posY, new Vector2(-1, 0), 2);
El mínimo de coincidencias se establece en dos, ya que junto con la pieza actual sumarían tres, que es la cantidad requerida para un match.
¿Qué es un while loop y por qué es peligroso aquí?
El while loop repite un bloque de código mientras una condición sea verdadera [04:25]. En este caso, mientras HasPreviousMatches devuelva true, el ciclo destruye la pieza actual y crea una nueva en la misma posición.
El riesgo es que, si nunca se encuentra una pieza válida, el ciclo se ejecutaría infinitamente y el programa se congelaría. Para evitarlo se introduce una variable maxIterations con valor de 50 y un contador currentIteration [04:10]. Si el contador supera el máximo, se ejecuta un break que rompe el ciclo de forma segura.
csharp
while (HasPreviousMatches(x, y))
{
ClearPieceAt(x, y);
newPiece = CreatePieceAt(x, y);
currentIteration++;
if (currentIteration > maxIterations) break;
}
El contador se reinicia a cero cada vez que el for avanza a la siguiente posición de la cuadrícula.
¿Cómo funciona ClearPieceAt para eliminar piezas duplicadas?
La función ClearPieceAt [05:35] recibe las coordenadas X e Y, obtiene la referencia de la pieza en esa posición, destruye su game object y luego establece la referencia en el arreglo como null:
csharp
void ClearPieceAt(int x, int y)
{
var pieceToClear = pieces[x, y];
Destroy(pieceToClear.gameObject);
pieces[x, y] = null;
}
Esta misma función se reutiliza dentro de SwapTiles [06:20], reemplazando el código duplicado que existía antes y manteniendo el proyecto más limpio.
¿Cómo verificar que la cuadrícula se genera sin matches?
Una forma práctica de probar el algoritmo es reducir la cantidad de tipos de piezas disponibles en el inspector del objeto Board [07:00]. Con menos variedad, la probabilidad de matches accidentales aumenta drásticamente. Al dejar solo cuatro tipos de piezas y ejecutar el juego, se confirma que el tablero se genera sin ninguna coincidencia previa, validando que la lógica funciona correctamente.
¿Has implementado alguna otra estrategia para evitar matches iniciales en tus proyectos? Comparte tu experiencia en los comentarios.