Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Game Development
  2. Tile-Based Games
Gamedevelopment

Unidad Azulejo 2D 'Sokoban' Juego

by
Difficulty:BeginnerLength:LongLanguages:

Spanish (Español) translation by James (you can also view the original English article)

Final product image
What You'll Be Creating

En este tutorial exploraremos un enfoque para crear un sokoban o empujador de cajas usando lógica basada en azulejo y una matriz bidimensional para datos de nivel del juego. Estamos utilizando la unidad para el desarrollo con C# como lenguaje. Por favor descargar los archivos fuente con este tutorial a seguir.

1. El Juego de Sokoban

Puede haber algunos que no han jugado una variante del juego Sokoban. La versión original puede ser incluso mayor que algunos de ustedes. Por favor revise la página wiki de algunos detalles. Esencialmente, tenemos un carácter o elemento controlados por el usuario que tiene que empujar cajas o elementos similares en su mosaico de destino.

El nivel consiste en una rejilla cuadrada o rectangular de azulejos donde un azulejo puede ser uno no transitable o caminar. Podemos caminar sobre las tejas caminables y empujar las cajas sobre ellos. Especiales azulejos transitables estaría marcados como azulejos del destino, que es donde el cajón debe descansar finalmente para completar el nivel. El carácter generalmente se controla mediante un teclado. Una vez que todos los cajones de acceder a una ficha de destino, el nivel es completo.

Desarrollo basado en el azulejo esencialmente significa que nuestro juego está compuesta por un número de fichas en forma predeterminada. Un elemento de datos de nivel representa cómo los azulejos tendrían que ser repartidos para crear nuestro nivel. En nuestro caso, usaremos una mosaico basado en cuadrícula. Puede leer más sobre juegos basados en azulejo aquí en Envato Tuts+.

2. Preparar el Proyecto Unity

Vamos a ver cómo nos hemos organizado nuestro proyecto de unidad para este tutorial.

El Arte

Para este proyecto tutorial, no está utilizando los activos externos del arte, pero utiliza a las primitivas de sprite creadas con la versión 2017.1 la última unidad. La imagen de abajo muestra cómo nosotros podemos crear sprites en forma diferentes dentro de la unidad.

How to create sprites within United 20171

Usaremos el sprite Cuadrado para representar una sola baldosa en nuestra red de nivel de sokoban. Utilizaremos el sprite del Triángulo para representar a nuestro personaje, y se utilice el sprite de Círculo para representar un cajón, o en este caso una bola. Los azulejos de suelo normal son blancos, mientras que los azulejos de destino tienen un color diferente para destacar.

Los Datos a Nivel

Nos representarán nuestros datos en forma de una matriz bidimensional que proporciona la perfecta correlación entre la lógica y los elementos visuales. Utilizamos un archivo de texto simple para almacenar los datos, que hace más fácil para nosotros editar el nivel fuera de la unidad o cambiar niveles simplemente cambiando los archivos cargados. La carpeta de Recursos tiene un archivo de texto de nivel que tiene nuestro nivel por defecto.

El nivel tiene siete columnas y cinco filas. Un valor de 1 significa que tenemos un suelo de azulejos en esa posición. Un valor de -1 significa que es no transitable del azulejo, mientras que un valor de 0 significa que él es un destino. El valor 2 representa a nuestro héroe, y 3 representa una bola pushable. Mirando los datos, podemos visualizar cómo sería nuestro nivel.

3. Crear un Juego de Sokoban Nivel

Para mantener las cosas simples y que no es una lógica muy complicada, tenemos solamente un solo Sokoban.cs archivo de comandos para el proyecto, y se une a la cámara de la escena. Por favor manténgalo abierto en el editor mientras sigues el resto del tutorial.

Datos de Nivel Especiales

Los datos representados por la matriz 2D se utilizan no sólo para crear la cuadrícula inicial pero también se utilizan en todo el juego de cambios de nivel y progreso. Esto significa que los valores actuales no son suficientes para representar algunos de los Estados de nivel durante el juego.

Cada valor representa el estado de la pieza correspondiente en el nivel. Necesitamos valores adicionales para representar una bola en el mosaico de destino y el héroe en el mosaico de destino, que son respectivamente -2 y -3. Estos valores pueden ser cualquier valor que se asigna en el guión del juego, no necesariamente los mismos valores que hemos usado aquí.

Análisis del Archivo de Texto de Nivel

El primer paso es cargar los datos en un array 2D desde el archivo de texto externo. Utilizamos el método ParseLevel para cargar el valor de string y dividirlo para rellenar nuestro array 2D de leveldata.

Al analizar, determinamos el número de filas y columnas de que nuestro nivel tiene rellenar nuestro levelData.

Nivel de Dibujo

Una vez tengamos nuestros datos, podemos sacar nuestro nivel en la pantalla. Utilizamos el método CreateLevel para hacer justamente eso.

Para nuestro nivel, hemos creado un valor tileSize de 50, que es la longitud del lado de un azulejo cuadrado en nuestra cuadrícula de nivel. Bucle a través de nuestra matriz 2D y determinar que el valor almacenado en cada uno de los i y j los índices de la matriz. Si este valor no es una invalidTile (-1) creamos un nuevo GameObject llamado tile. Atribuimos un componente SpriteRenderer para tile y asignar el Sprite correspondiente o el Color dependiendo del valor en el índice de matriz.

Colocando el hero o la ball, tenemos que primero crear un azulejo de la tierra y crear a continuación estos azulejos. Como el héroe y la bola que deba ser superponer el azulejo de suelo, le damos su SpriteRenderer un mayor sortingOrder. Todas las fichas se asignan un localscale de tileSize así que son 50x50 en nuestra escena.

Mantener seguimiento del número de bolas en nuestra escena utilizando la variable ballCount, y debe existir el mismo o un mayor número de fichas de destino en nuestro nivel para hacer posible la finalización del nivel. La magia sucede en una sola línea de código donde determinamos la posición de cada mosaico que utiliza el método GetScreenPointFromLevelIndices (int row, int col).

La posición mundial de un azulejo se determina multiplicando los índices de nivel con el valor de tileSize. La variable middleOffset se utiliza para alinear el nivel en el centro de la pantalla. Observe que el valor de la fila se multiplica por un valor negativo para apoyar el eje de la y invertida en la unidad.

4. Sokoban Lógica

Ahora que hemos mostrado nuestro nivel, vamos a proceder a la lógica del juego. Tenemos que escuchar para entrada de tecla del usuario y mover al héroe basado en la entrada. La tecla determina una dirección correcta del movimiento, y el hero tiene que moverse en esa dirección. Hay varios escenarios a tener en cuenta una vez que hemos determinado la necesaria dirección del movimiento. Digamos que el azulejo junto al héroe en esta dirección es tileK.

  • ¿Hay un azulejo en la escena en esa posición, o está fuera de nuestra red?
  • ¿Es tileK un azulejo transitable?
  • ¿TileK ocupa una bola?

Si la posición de tileK está fuera de la red, lo no hacemos necesidad de hacer nada. Si tileK es válido y es transitable, necesitamos pasar de héroe a esa posición y actualizar nuestra levelData. Si tileK tiene una bola, entonces debemos de considerar al siguiente vecino en la misma dirección, digamos tileL.

  • ¿Es tileL fuera de la red?
  • ¿Es tileL un azulejo transitable?
  • ¿TileL ocupa una ball?

Sólo en el caso donde tileL es un azulejo transitable, no ocupado debemos movemos el hero y la bola a tileK tileK y tileL respectivamente. Después de movimiento exitoso, debemos actualizar la matriz de leveldata.

Funciones de Apoyo

La lógica anterior significa que tenemos que saber que nuestro héroe está actualmente en el azulejo. También debemos determinar si un cierto azulejo tiene un balón y debe tener acceso a esa bola.

Para facilitar esto, usamos un diccionario llamado a ocupantes que almacena un GameObject como clave y sus índices de array como Vector2 como valor. En el método CreateLevel, nosotros pueblan a los ocupantes cuando creamos hero o ball. Una vez que tenemos el Diccionario poblado, podemos utilizar el GetOccupantAtPosition para volver el GameObject en un índice de matriz determinado.

El método IsOccupied determina si el valor de levelData en los índices siempre representa una bola.

También necesitamos una manera de comprobar si una determinada posición está dentro de nuestra red y si azulejo es transitable. El método IsValidPosition comprueba los índices nivel pasados como parámetros para determinar si cae dentro de nuestras dimensiones nivel. Comprueba también si tenemos un invalidTile como ese índice en el levelData.

Responder a la Entrada del Usuario

En el método de update de nuestro script juego, revise los eventos KeyUp del usuario y comparar contra nuestras entradas claves almacenadas en la matriz userInputKeys. Una vez determinada la dirección necesaria del movimiento, llamamos al método TryMoveHero con la dirección como parámetro.

El método de TryMoveHero es donde se implementa nuestra lógica juego core explicada al comienzo de esta sección. Por favor revise el siguiente método cuidadosamente para ver cómo se implementa la lógica como se explicó anteriormente.

Para obtener la siguiente posición a lo largo de una dirección determinada en función de una posición siempre, usamos el método GetNextPositionAlong. Es sólo una cuestión de incremento o decremento de los índices de acuerdo a la dirección.

Antes de mover héroe o bola, tenemos claro su posición actualmente ocupada en la matriz de levelData. Esto se hace utilizando el método de RemoveOccupant.

Si nos encontramos con un heroTile o ballTile en el índice dado, tenemos que ponerlo a groundTile. Si nos encontramos con un heroOnDestinationTile o ballOnDestinationTile necesitamos ponerlo a destinationTile.

Finalización de Nivel

El nivel está completo cuando todas las bolas están en sus destinos.

A Completed Level

Después de cada movimiento exitoso, llamamos al método CheckCompletion para ver si el nivel es completado. Bucle a través de nuestra gama de levelData y cuente el número de ocurrencias de ballOnDestinationTile. Si este número es igual al número total de bolas determinado por ballCount, el nivel es completo.

Conclusión

Se trata de una simple y eficiente implementación de lógica sokoban. Puede crear sus propios niveles de alterar el archivo de texto o crear uno nuevo y cambiar la variable levelName para señalar el nuevo archivo de texto.

La implementación actual utiliza el teclado para controlar al héroe. Te invito a probar y cambiar el control a base de tap por lo que podemos soportar dispositivos táctiles. Esto implicaría agregar algún camino 2D encontrando así si te apetece tocar en cualquier azulejo para llevar allí el héroe.

Habrá un seguimiento tutorial donde exploraremos cómo el proyecto actual se puede utilizar para crear versiones de sokoban isométricas y hexagonales con cambios mínimos.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.