Construye un juego de rompecabezas basado en cuadrícula como el buscaminas en Unity Interaction

Continuamos construyendo nuestro juego de rompecabezas basado en cuadrícula conectando los mosaicos entre sí, haciendo que se iluminen con el cursor del mouse y agregando la capacidad de colocar banderas.

En la última parte de este tutorial, creamos un campo de fichas que forman la base de nuestro juego de rompecabezas. En esta parte, lo haremos jugable. Este tutorial sigue directamente desde la última parte, así que lea esto antes de comenzar este.

Iluminación de azulejos hasta en Mouseover

Cuando el ratón está sobre una baldosa, queremos que se ilumine. Esta es una característica genial que brinda acciones incluso simples (como mover el puntero del mouse) retroalimentación instantánea.

Usamos el El ratón por encima() Función para lograr esto. Se llama automáticamente cuando el cursor del mouse se mueve sobre el objeto al que se adjunta el código. Agrega estas variables a la Azulejo guión:

material de var. pública: material; material de var públicoLightup: Material;

Luego, asigne su material de baldosa básica a material espacio. También necesitamos un encender Material, que debe tener el mismo color, pero utiliza un sombreador diferente. Mientras que el material básico puede tener un difuso sombreador ...

… El material lightup podría tener un de espejo sombreado Muchos juegos usan un sombreador de borde adicional para ese efecto también. Esos no vienen con Unity, pero si puedes averiguar cómo obtener uno, puedes usar eso!

No olvide asignar los materiales a la Material Ranuras en la baldosa prefabricada, para que puedan ser utilizadas..

Entonces agrega esto El ratón por encima() función a la Azulejo guión

function OnMouseOver () renderer.material = materialLightup; 

¡Pruébalo! Cuando mueves el cursor del mouse sobre los mosaicos, deberían cambiar su apariencia..

Lo que habrás notado es que los mosaicos cambian su apariencia una vez que el mouse está sobre ellos, pero en realidad no cambia atrás. Para eso, necesitamos usar el OnMouseExit () función:

function OnMouseExit () renderer.material = materialIdle; 

Y voilá; Ahora tenemos fichas que se iluminan y hacen que el juego sea mucho más interesante..

Asignando IDs a Tiles

Para que las fichas se comuniquen entre sí (para saber cuántas minas hay cerca), cada una de ellas debe conocer sus fichas adyacentes. Una forma de lograrlo es usar ID, que se asignarán a cada ficha.

Comience por adaptar el código de mosaico para incluir una CARNÉ DE IDENTIDAD variable. Además, agregue una variable para mantener el número de mosaicos por fila, que usaremos en este cálculo:

ID de var público: int; public var tilesPerRow: int;

Luego modifique el comando de instanciación en el código de cuadrícula para que se parezca al siguiente fragmento de código. (La nueva línea asigna ID a los mosaicos a medida que se crean).

var newTile = Instantiate (tilePrefab, Vector3 (transform.position.x + xOffset, transform.position.y, transform.position.z + zOffset), transform.rotation); newTile.ID = tilesCreated; newTile.tilesPerRow = tilesPerRow;

La primera ficha obtendrá el ID. 0, Al siguiente se le asignará el ID. 1, y así. Puede verificarlos haciendo clic en las fichas durante el tiempo de ejecución y viendo qué número se les ha asignado.

Obtención de azulejos vecinos

Ahora queremos que cada azulejo sepa sobre sus azulejos vecinos. Cuando ejecutamos una acción en un mosaico (como descubrirlo), debemos tener en cuenta los mosaicos vecinos..

En nuestro caso, esto significa contar las minas que están adyacentes a la baldosa que acabamos de descubrir, y posiblemente también descubrir otras baldosas, pero lo veremos más adelante.

Esto también puede usarse para, por ejemplo, verificar si tres o más fichas están una al lado de la otra en un juego de Match-3.

Comience agregando estas variables al script de mosaico:

public var tileUpper: Tile; public var tileLower: Tile; public var tileLeft: Tile; public var tileRight: Tile; public var tileUpperRight: Tile; public var tileUpperLeft: Tile; public var tileLowerRight: Tile; public var tileLowerLeft: Tile;

Estos sostendrán todos los azulejos vecinos. Son públicos para que podamos verificar durante el tiempo de ejecución si se asignaron correctamente..

Desde ahora, cada mosaico tiene una identificación, la cantidad de mosaicos que aparecen en una columna y el acceso a la matriz estática que tiene todos los mosaicos guardados en la columna. Cuadrícula clase, podemos calcular las posiciones de los azulejos vecinos después de que se hayan creado.

Esa parte se ve así:

tileUpper = Grid.tilesAll [ID + tilesPerRow]; tileLower = Grid.tilesAll [ID - tilesPerRow]; tileLeft = Grid.tilesAll [ID - 1]; tileRight = Grid.tilesAll [ID + 1]; tileUpperRight = Grid.tilesAll [ID + tilesPerRow + 1]; tileUpperLeft = Grid.tilesAll [ID + tilesPerRow - 1]; tileLowerRight = Grid.tilesAll [ID - tilesPerRow + 1]; tileLowerLeft = Grid.tilesAll [ID - tilesPerRow - 1];

Con los ID y el número de mosaicos por fila, podemos calcular qué mosaicos están cerca. Supongamos que la baldosa que realiza los cálculos tiene el ID 3, y que hay cinco fichas por fila. La ficha de arriba tendrá el ID. 8 (la identificación del azulejo seleccionado más el número de azulejos por fila); La ficha a la derecha tendrá la identificación. 6 (el ID del mosaico seleccionado más uno), y así sucesivamente.

Desafortunadamente, esto no es suficiente. El código verifica correctamente los números, pero cuando pregunta al allTiles Para devolver los mosaicos, puede solicitar números de índice que están fuera de rango, produciendo una larga lista de errores. 

Para solucionar esto, necesitamos verificar que el índice que solicitamos de la matriz es realmente válido. La forma más eficiente de hacerlo es con un nuevo inBounds () función. Añádelo a la baldosa:

función privada inBounds (inputArray: Array, targetID: int): boolean if (targetID < 0 || targetID >= inputArray.length) devolver falso; si no devuelve verdadero 

Ahora tenemos que verificar que cada mosaico adyacente posible esté dentro de los límites de la matriz que contiene todos los mosaicos, antes de que intentemos obtenerla de la matriz:

if (inBounds (Grid.tilesAll, ID + tilesPerRow)) tileUpper = Grid.tilesAll [ID + tilesPerRow]; if (inBounds (Grid.tilesAll, ID - tilesPerRow)) tileLower = Grid.tilesAll [ID - tilesPerRow]; if (inBounds (Grid.tilesAll, ID - 1) && ID% tilesPerRow! = 0) tileLeft = Grid.tilesAll [ID - 1]; if (inBounds (Grid.tilesAll, ID + 1) && (ID + 1)% tilesPerRow! = 0) tileRight = Grid.tilesAll [ID + 1]; if (inBounds (Grid.tilesAll, ID + tilesPerRow + 1) && (ID + 1)% tilesPerRow! = 0) tileUpperRight = Grid.tilesAll [ID + tilesPerRow + 1]; if (inBounds (Grid.tilesAll, ID + tilesPerRow - 1) && ID% tilesPerRow! = 0) tileUpperLeft = Grid.tilesAll [ID + tilesPerRow - 1]; if (inBounds (Grid.tilesAll, ID - tilesPerRow + 1) && (ID + 1)% tilesPerRow! = 0) tileLowerRight = Grid.tilesAll [ID - tilesPerRow + 1]; if (inBounds (Grid.tilesAll, ID - tilesPerRow - 1) && ID% tilesPerRow! = 0) tileLowerLeft = Grid.tilesAll [ID - tilesPerRow - 1];

Ese bloque de código comprueba todas las posibilidades. También comprueba si una ficha está en el borde del campo. Una baldosa en el borde derecho de la cuadrícula, después de todo, no tiene realmente ninguna baldosa en su Correcto.

¡Pruébalo! Compruebe algunas fichas y vea si ha recuperado todas las fichas adyacentes correctamente. Debe tener un aspecto como este:

Como el mosaico en esta captura de pantalla es un mosaico en el borde derecho del campo, no tiene vecinos a la derecha, arriba a la derecha o abajo a la derecha. Las variables sin mosaicos asignados están correctamente vacías, y una prueba revela que las restantes se asignaron correctamente también.

Finalmente, una vez que nos hemos asegurado de que esto funcione, agregamos todos los mosaicos adyacentes a una matriz, para que podamos acceder a todos ellos de una vez. Necesitamos declarar esta matriz al principio:

public var. adyacentes: Array = new Array ();

Luego puede adaptar cada línea del algoritmo que creamos anteriormente para ingresar cada mosaico vecino en esa matriz, o agregar este bloque después:

if (tileUpper) adyacenteTiles.Push (tileUpper); if (tileLower) adyacenteTiles.Push (tileLower); if (tileLeft) adyacenteTiles.Push (tileLeft); if (tileRight) adyacenteTiles.Push (tileRight); if (tileUpperRight) adyacenteTiles.Push (tileUpperRight); if (tileUpperLeft) adyacenteTiles.Push (tileUpperLeft); if (tileLowerRight) adyacenteTiles.Push (tileLowerRight); if (tileLowerLeft) adyacenteTiles.Push (tileLowerLeft);

Contando Minas Cercanas

Después de que se hayan creado todas las fichas, se hayan asignado todas las minas, y cada ficha haya recuperado sus vecinos, entonces debemos verificar si cada una de estas fichas adyacentes está minada o no.

El código de la cuadrícula ya asigna el número especificado de minas a los azulejos elegidos al azar. Ahora solo necesitamos cada ficha para comprobar sus vecinos. Agregue este código al comienzo de la Azulejo script, para que tengamos un lugar para almacenar la cantidad de minas:

min públicas de forma adyacente: int = 0;

Para contarlos, corremos a través de la matriz en la que previamente agregamos todos los mosaicos vecinos, y verificamos cada entrada para ver si está minada. Si es así, aumentamos el valor de Minas adyacentes por 1.

función CountMines () adyacMines = 0; para cada (var currentTile: Tile in adyacente Tile) if (currentTile.isMined) adyacenteMines + = 1; displayText.text = adyacenteMines.ToString (); si <= 0) displayText.text = ""; 

Esta función también establece el elemento de texto del mosaico para mostrar el número de minas cercanas. Si no hay minas, no muestra nada (en lugar de 0).

Seguimiento del estado de cada mina

Vamos a añadir un estado a cada baldosa. De esta manera, podemos hacer un seguimiento de en qué estado se encuentra actualmente-ocioso, descubierto, o marcado. Dependiendo del estado en el que se encuentre la baldosa, reaccionará de manera diferente. Agrégalo ahora, como lo usaremos en un momento..

public var state: String = "idle";

Agregando Banderas

Queremos poder marcar los azulejos como marcado. Una ficha marcada tiene una pequeña bandera encima. Si hacemos clic derecho en la bandera, volverá a desaparecer. Si todas las fichas minadas se han marcado y no quedan marcas incorrectamente marcadas, el juego se gana.

Comience por crear un objeto de marca y agréguelo al mosaico (encontrará una malla de bandera en los archivos de origen).

También necesitamos una variable para acceder a la bandera. Añade este código:

public var displayFlag: GameObject;

Recuerde que debe arrastrar la bandera que es parte de la baldosa en el displayFlag espacio.

Además, agregue esto a la comienzo() Función del azulejo:

displayFlag.renderer.enabled = false; displayText.renderer.enabled = false;

Esto deshabilitará la bandera y el texto al principio. Más tarde, podemos entonces activar Una bandera, haciéndola visible de nuevo, colocándola efectivamente allí.. Alternativamente, si nosotros descubrir Una baldosa, volvemos a hacer visible el texto..

Colocación y eliminación de banderas

Escribiremos una función que maneje tanto colocar como eliminar banderas:

función SetFlag () si (estado == "inactivo") estado = "marcado"; displayFlag.renderer.enabled = true;  else if (estado == "marcado") estado = "inactivo"; displayFlag.renderer.enabled = false; 

Una vez que haya agregado eso, también agregue el código para manejar un evento de clic. Para ello, adapta el El ratón por encima() Función que ya tenemos para comprobar un clic del mouse:

función OnMouseOver () if (state == "idle") renderer.material = materialLightup; if (Input.GetMouseButtonDown (1)) SetFlag ();  else if (estado == "marcado") renderer.material = materialLightup; if (Input.GetMouseButtonDown (1)) SetFlag (); 

Esto reconocerá un clic derecho (botón 1) y activar el Establecer bandera() función. Entonces activará o desactivará la bandera en el mosaico actual. Pruébalo!

Conclusión

Hemos ampliado nuestro juego de rompecabezas con varias características vitales, lo hemos hecho visualmente más interesante y le hemos dado al jugador la capacidad de afectar el campo de juego..

La próxima vez, agregaremos destapado de fichas, crearemos una interfaz simple y convertiremos esto en un juego adecuado..