Aprende a inicializar un tablero tipo Candy Crush en Unity sin tripletes desde el primer fotograma. Aquí verás cómo combinar un doble bucle, comparar vecinos estratégicamente y usar un bucle do-while para garantizar variedad, además de mantener la jerarquía limpia con Board Manager.
¿Cómo evitar tripletes al iniciar el tablero en Unity?
Evitar tres caramelos iguales contiguos desde el inicio mejora el gameplay y evita ventajas injustas. La clave es comparar el caramelo actual con el vecino de abajo y el vecino de la izquierda mientras generas el tablero por columnas de abajo hacia arriba.
Genera por columnas, de abajo a arriba, y luego la siguiente columna.
Compara solo abajo e izquierda: derecha y arriba aún no existen lógicamente.
Usa hasta seis tipos: hay variedad suficiente sin forzar repeticiones.
Controla el flujo con un do-while que reintenta el índice si coincide con un vecino.
¿Qué patrón de recorrido y vecinos usar?
Recorre columnas (x) y luego filas (y) de abajo a arriba.
Compara el id actual con: candies[x-1, y] (izquierda) y candies[x, y-1] (abajo).
Evita comparar fuera de límites: usa x > 0 e y > 0.
¿Cómo se implementa el do-while con Random.Range y prefabs.Count?
Este patrón asegura al menos una asignación y reintenta si hay choque con vecinos. Usa Random.Range y el tamaño de prefabs.Count para elegir un índice válido.
int idx =-1;// identificador provisional// Dentro del doble bucle (x columnas, y filas):do{ idx = Random.Range(0, prefabs.Count);}while((x >0&& idx == candies[x -1, y].GetComponent<Candy>().id)||(y >0&& idx == candies[x, y -1].GetComponent<Candy>().id));// Usa idx para instanciar y configurar el caramelo sin volver a randomizar.var newCandy =Instantiate(prefabs[idx],/* posición y rotación */);// newCandy.GetComponent<SpriteRenderer>().sprite = ... // asigna el sprite si aplica.newCandy.GetComponent<Candy>().id = idx;// asigna el identificador único.candies[x, y]= newCandy;// guarda en la matriz.
¿Cómo asignar el prefab, el sprite y el id sin duplicar?
No vuelvas a llamar a Random.Range tras validar: reutiliza idx.
Con idx obtienes el prefab y su sprite correspondiente.
Asigna el id al componente Candy: es la referencia única para comparar vecinos.
¿Por qué el id y la matriz candies aseguran variedad?
El id único por caramelo es la forma fiable de comparar tipos. La matriz candies[x, y] guarda cada instancia en su posición, permitiendo consultar vecinos ya creados. Así, por construcción, no habrá dos iguales consecutivos en filas o columnas al iniciar.
El id vive en el componente Candy: comparación directa y rápida.
La matriz es la “verdad” del tablero: consulta inmediata de izquierda y abajo.
Con el do-while, solo aceptas un idx si no coincide con vecinos ya existentes.
¿Qué condiciones de borde considerar en la primera columna y fila?
Primera columna: x == 0, no hay vecino a la izquierda.
Primera fila: y == 0, no hay vecino abajo.
Condición booleana compuesta con OR: evalúa coincidencia con izquierda o abajo si x > 0 o y > 0.
¿Cómo ordenar la jerarquía con el Board Manager para trabajar mejor?
Mantener los caramelos como hijos del Board Manager limpia la jerarquía y agiliza el trabajo en el editor. Así despliegas o colapsas todos los hijos desde un solo nodo y localizas más fácil otros objetos como cámara y fondo.
Jerarquía limpia: menos ruido en el panel lateral.
Organización lógica: todo el tablero depende del Board Manager.
Operaciones en lote: mover, activar o desactivar ramas completas.
¿Qué línea de código hace a los caramelos hijos del tablero?
Basta con establecer el padre de la transform del caramelo al transform actual del Board Manager.
newCandy.transform.parent =this.transform;// jerarquiza el caramelo bajo el Board Manager
¿Te gustaría ver otras validaciones iniciales o variantes del patrón de generación? Comparte tus dudas y propuestas en los comentarios.
Para quien haya seguido mis pasos en los ultimos videos, les advierto aqui que ahora tuve que hacer mas cambios por preferencias personales, y que si siguieron lo que les dije antes, muchas cosas van a estar fuera de lugar, si aun asi quieren seguir con mis consejos:
Le quite el BoxCollider2D al background y se lo a;adi al objeto que sera el caramelo per se, cuando hice esto ya no se podia calcular el offset, asi que en vez de acceder al componente BoxCollider, accedo al GetComponent<SpriteRenderer>() que tienen una propiedad que es bounds y esa tiene sus propiedades vectoriales.
Como mis caramelos son prefabs que contienen la animacion y el box collider, y lo que existe en el juego son instancias de los caramelos, no puedo volverlos hijos de un objeto porque corromperia el estado del prefab, asi que decidi que no me molesta tanto que esten los candies en la jerarquia lateral, sin embargo los fondos si los hice hijos del board manager.
Podemos configurar nuestros dulces para que todos sean hijos del Game Object invisible y podamos tener una vista más cómoda en Unity cuando colapsamos el elemento con el script del Board Manager:
Analizando la lógica que se utiliza para evitar un tres en raya, note que también evita el caso en el que sean solo dos caramelos en raya, cosa que si puede ocurrir en juegos de este tipo, cambie el while por el siguiente y este si permite ese caso.
Lo que entendi es que Si el dulce de la izquierda o abajo coincide se va a volver a llamar al "Random.Range(0, prefabs.Count);" para que ponga otro dulce aleatorio?
OK. entonces generamos un bucle que esta garantizado a ejecutarse al menos una vez que lo que hace es generar un numero aleatorio siempre y cuando el identificador del caramelo que esta a nuestra izquierda y abajo no coincida con el identificador del caramelo que estamos generando.
.
Ahora este numero aleatorio generado lo usaremos para elegir el caramelo correspondiente a la hora de crear la matriz con los caramelos asegurándonos que el juego no tenga caramelos repetidos uno cerca del otro.
Sí, porque al asignarle -1, le estás diciendo que todos los candys sean el mismo. Ese menos -1 se había puesto antes como un valor cualuqiera o que no encaja, para luego recodar que había que cambiarlo.
Al agregarle el "this.transform" o simplemente "transform" se asigna el objeto instanciado como hijo de la clase padre que lo esta Instanciando en este caso BoardManager es el padre de cada Candy
Yo agregué otra función para que los Candys tengan un espacio de color oscuro de fondo cada uno y haya un espacio entre ellos que llamé padding y se puede definir en el inspector.
privatevoidCreateBoard(){ spaceCandies =newGameObject[xSize, ySize];PlayerPrefs.SetInt("xSize", xSize);PlayerPrefs.SetInt("ySize", ySize); float startX =this.transform.position.x; float startY =this.transform.position.y;for(int x =0; x < xSize; x++){for(int y =0; y < ySize; y++){// Instanciar y posicionar SPACE CANDYVector3 posCandy =VerificatePos(startX, startY, x, y);GameObject newCandy =Instantiate(spaceCandy, posCandy, spaceCandy.transform.rotation);// Aplicar nombre "Candy x=0 y=1" newCandy.name= string.Format("Space[{0}][{1}]", x, y);// Agregar al array de SPACES spaceCandies[x, y]= newCandy;}}CreatorCandies();}privatevoidCreatorCandies(){ candies =newGameObject[xSize, ySize]; float startX =this.transform.position.x; float startY =this.transform.position.y;for(int x =0; x < xSize; x++){for(int y =0; y < ySize; y++){// Instanciar y posicionar SPACE CANDYVector3 posCandy =VerificatePos(startX, startY, x, y);GameObject newCandy =Instantiate(currentCandy, posCandy, currentCandy.transform.rotation);// Reajusta el Sprite del objeto instanciadoSprite sprite = prefabs[Random.Range(0, prefabs.Count)]; newCandy.GetComponent<SpriteRenderer>().sprite= sprite;// Aplica ID y NOMBRE en base al CandyCandy[] totalCandies =FindObjectsOfType<Candy>();// TEST newCandy.GetComponent<Candy>().id= totalCandies.Length+1; newCandy.name= string.Format("Candy[{0}]", newCandy.GetComponent<Candy>().id); candies[x, y]= newCandy;}}}privateVector3VerificatePos(float startX, float startY, int x, int y){Vector3 posCandy;if(x ==0&& y ==0) posCandy =newVector3(startX +(offset.x* x), startY +(offset.y* y),0);else posCandy =newVector3(startX +(offset.x+ padding)* x, startY +(offset.y+ padding)* y,0);return posCandy;}
No sé como adjuntar imágenes y por eso no lo muestro xd. La función ++VerificatePos++ se encarga de que se aplique el padding entre cada espacio excepto que el espacio actual sea el ++(0, 0)++