Generar caramelos sin crear matches accidentales

Clase 20 de 31Curso de Desarrollo de Videojuegos para Móviles con Unity

Resumen

Domina una técnica fiable para rellenar huecos en un tablero match‑3 en Unity sin provocar coincidencias accidentales. Aprenderás a generar un caramelo nuevo por posición con control de vecinos, a evitar referencias no deseadas en listas y a integrarlo con la caída de piezas vía corrutinas para completar la parrilla.

¿Cómo rellenar huecos del tablero sin crear matches?

El manager es responsable del tablero y, por tanto, de rellenar los huecos que quedan cuando los caramelos descienden. La idea central: un método que devuelva el sprite del nuevo caramelo para una coordenada (x, y), filtrando opciones que provoquen un match horizontal o vertical inmediato.

  • Crear un método: devuelve un Sprite, por ejemplo, GetNewCandy(x, y). Genera un único caramelo por posición.
  • Construir una lista temporal con todos los prefabs posibles del juego. Luego, eliminar los que no se pueden colocar por ser vecinos directos.
  • Seleccionar aleatoriamente entre los candidatos válidos con Random.Range.

Ejemplo de implementación en C#:

private Sprite GetNewCandy(int x, int y)
{
    // Clonar la lista de prefabs originales (no referenciarla).
    List<Sprite> possibleCandies = new List<Sprite>();
    possibleCandies.AddRange(prefabsOriginales);

    // Evitar repetir con el vecino de la izquierda.
    if (x > 0)
        possibleCandies.Remove(tablero[x - 1, y].GetComponent<SpriteRenderer>().sprite);

    // Evitar repetir con el vecino de la derecha.
    if (x < xSize - 1)
        possibleCandies.Remove(tablero[x + 1, y].GetComponent<SpriteRenderer>().sprite);

    // Evitar repetir con el vecino de abajo.
    if (y > 0)
        possibleCandies.Remove(tablero[x, y - 1].GetComponent<SpriteRenderer>().sprite);

    // Elegir uno al azar entre los candidatos restantes.
    return possibleCandies[UnityEngine.Random.Range(0, possibleCandies.Count)];
}

¿Por qué copiar listas en vez de referenciarlas?

En programación orientada a objetos, asignar una lista a otra crea una referencia, no una copia. Aquí se necesita una copia para partir de los valores originales y eliminar opciones sin alterar la lista base de prefabs del manager.

  • Evitar efectos colaterales al modificar la lista global.
  • Trabajar con un subconjunto temporal por posición.
  • Mantener los prefabs originales intactos.

¿Qué vecinos se excluyen al generar un caramelo?

Se filtran los vecinos que podrían forzar un tres en raya inmediato. No se comprueba hacia arriba porque el hueco está precisamente en la zona superior tras la caída.

  • Izquierda: si x > 0, eliminar el sprite de x−1, y.
  • Derecha: si x < xSize−1, eliminar el sprite de x+1, y.
  • Abajo: si y > 0, eliminar el sprite de x, y−1.
  • Arriba: no aplica, el hueco está arriba tras el descenso.

¿Cómo integrar la generación con la caída de caramelos?

En el método que hace caer las piezas (por ejemplo, MakeCandyFall), antes se dejaban posiciones en null al desplazar hacia abajo. En lugar de mantener el null, se debe invocar al generador para reponer el caramelo en la parte superior de la columna.

  • Usar ySize como tamaño de la parrilla vertical.
  • Colocar el nuevo caramelo en la fila ySize−1 (arriba del todo).
  • Dejar que las corrutinas hagan descender el caramelo automáticamente.

Fragmento orientativo:

// Donde antes quedaba null, reponer en la fila superior.
tablero[x, ySize - 1] = GetNewCandy(x, ySize - 1);

¿Qué se observa al probar en Unity?

Las pruebas en el editor muestran el flujo funcionando de principio a fin.

  • Las columnas caen y se rellenan con nuevos caramelos.
  • No hay problemas en vertical ni en horizontal al mover piezas.
  • El ojo ve aparecer el nuevo caramelo arriba y, por corrutinas, desciende hasta completar la parrilla.

¿Qué mejora falta: detección de cascadas?

Queda un bug pendiente: tras la caída y el rellenado, el algoritmo no detecta nuevas alineaciones formadas por efecto dominó. Debe ser capaz de:

  • Detectar cuando aparecen tres o más en línea tras una caída.
  • Repetir el proceso de eliminar, caer y rellenar de forma recurrente.
  • Continuar mientras exista alguna posibilidad de elementos alineados.

¿Te gustaría comentar cómo detectarías esas cascadas o qué estructura de control usarías para repetir el chequeo de alineaciones?