Crea un juego de Match 3 en Construct 2 Eliminando los Matches Pre-hechos

En el tutorial anterior finalmente conseguimos que nuestro juego se moviera y agregáramos movimiento a nuestros bloques. Además de eso, creamos un sistema de dificultad rudimentaria para hacer el juego más difícil a medida que el jugador juega más tiempo..

Con estas dos características en el juego, estamos listos para implementar el sistema que eliminará las combinaciones prefabricadas del tablero. Aunque este no es el último artículo de la serie, este es el último sistema importante que debemos implementar, así que siéntase cómodo, porque tenemos nuestro trabajo por delante..


Demostración final del juego

Aquí está una demostración del juego en el que estamos trabajando a lo largo de esta serie:




Arreglos rápidos

Antes de comenzar con la parte principal de este tutorial, quiero tomarme un minuto para solucionar dos problemas que descubrí mientras escribía el tutorial anterior..

Pareo

El primer problema al que me refiero aparece en el escenario que puede ver a continuación:

En esta situación, si arrastra Bloque B sobre el punto verde, debería caer debido a los espacios vacíos debajo del punto, y finalmente aterrizar en el lugar etiquetado do. En la mayoría de los escenarios, esto sucederá y el juego funcionará normalmente, pero en algunos escenarios, el juego detectará un partido en el breve momento en que Bloque B esta al lado del grupo UNA Y terminará destruyendo los tres bloques..

Este problema no es exclusivo de ese escenario anterior y también puede presentarse cuando haces lo mismo en el escenario que he resaltado a continuación..

Si no solucionamos esto, el jugador recibirá crédito y puntos por una cantidad de partidos que nunca pretendieron hacer y también podría confundirse acerca de por qué tantos bloques desaparecen inesperadamente..

Afortunadamente, sin embargo, este es un problema simple de solucionar. Para resolver este problema vamos a crear un nuevo Variable global llamado MatchesPosible que determinará si se pueden hacer coincidencias, y un nuevo Evento que detectará cuando un bloque está "cayendo" y se modificará MatchesPosible para que no se puedan hacer coincidencias mientras esto sucede.

Primero crearemos la Variable Global:

Variable global: MatchesPossible Type = Number Valor inicial = 1

Tu nueva variable debería verse así:

Ahora haremos el Evento que escuchará cuando caiga un bloque:

Evento: Condición: Invertir: Bloque> Se superpone en el desplazamiento Objeto = Bloque Desplazamiento X = 0 Desplazamiento Y = 8 Condición: Bloque> Comparar Y Comparación = Menor o igual Coordenadas Y = SPAWNY Acción: Sistema> Establecer valor Variable = Coincidencia Valor posible = 1

Este evento lo hace para que cuando se encuentre un bloque tenga un espacio vacío debajo de él. MatchesPosible se establece en 1, significando que los partidos no son posibles. También notará que comprueba la posición Y del bloque. Esto es para asegurar que el bloque no esté en la fila más baja de bloques, que siempre tendrá un espacio vacío debajo de él..

A continuación, necesitamos un evento que establece MKatchesPosible de regreso 0 cuando no hay bloques tienen un espacio vacío debajo de ellos. Este segundo evento se basará en otra condición:

Evento: Condición: Sistema> Otra acción: Sistema> Establecer valor Variable = MatchesPossible value = 0

Asegúrese de que este evento siga inmediatamente al primer evento para que la instrucción Else se use correctamente.

Tus dos nuevos eventos deberían verse así:

Finalmente, vamos a agregar una nueva condición a CheckMatches para que se vea MatchesPosible para determinar si se puede hacer un partido. Agregue esta condición a la llamada de la función inicial del CheckMatches Evento.

Condición: Sistema> Comparar variable Variable = MatchesPosible Comparación = Igual a Vale = 0

Con la condición añadida, su CheckMatches El evento ahora debería verse así:

A diferencia de la mayoría de los problemas que hemos encontrado hasta este punto, este problema se presenta de manera bastante inconsistente. Esto significa que realmente no podemos realizar pruebas para ver si solucionamos el problema, solo podemos hacer pruebas para ver si causamos otros problemas. Si juegas al juego ahora, deberías ver que esta condición no ha causado nuevos problemas..

Puntos

El segundo problema que quería solucionar antes de agregar algo nuevo se relaciona con el sistema de Puntos.

Mientras trabajaba en el proyecto para este tutorial, noté que algo que hice causó que el sistema de Puntos se comportara de manera extraña y le diera al jugador cuatro o cinco veces más puntos que deberían obtener para cada partida. Aunque no pude determinar qué cambio hice causó que esto empezara a suceder, encontré que la raíz del problema era que GivePoints La función en realidad se llamaba varias veces ya que los Bloques no se estaban destruyendo de inmediato. Afortunadamente, como nuestro último problema, esto se puede arreglar fácilmente.

Para solucionar esto, vamos a crear una nueva variable que le dirá al sistema si puede dar puntos. Entonces, cuando estemos a punto de usar el GivePoints En la función, también modificaremos la variable para garantizar que el evento solo se active una vez. Finalmente, una vez que se hayan otorgado los puntos, cambiaremos la variable una vez más para que no haya ningún problema la próxima vez que intentemos dar puntos..

Primero, crea una variable global llamada Puntos dados:

Variable global: PointsGiven Type = Number Valor inicial = 0

Tu variable debería gustar esto:

A continuación modificaremos la parte del FindMatches Función que en realidad da los puntos al agregar una nueva condición y dos nuevas acciones..

Condición: Sistema> Comparar variable Variable = PointsGiven Comparación = Igual al valor = 0

Ahora agregue esta acción al principio de la lista de acciones:

Acción: Sistema> Establecer valor Variable = PointsGiven Value = 1

Finalmente, agregue esta acción al final de la lista de acciones:

Acción: Sistema> Establecer valor Variable = PointsGiven Value = 0

El evento ahora debería verse así:

Con estos cambios lo hemos hecho para que el Evento que convoca. GivePoints sólo se ejecutará cuando el Puntos dados variable es 0. Ya que estamos configurando el valor de inmediato 1 cuando iniciamos el Evento, esto evita que el Evento se dispare más de una vez y asegura que el jugador recibirá la cantidad correcta de puntos.

Si ejecuta el juego en este punto, debería recibir la cantidad correcta de puntos por cada partida que haga, incluso si no tenía este problema para empezar..


Eliminando Partidos Pre-hechos

Ahora que hemos eliminado esos arreglos, podemos continuar con la creación del sistema que eliminará las coincidencias que genera el sistema cuando asigna aleatoriamente colores a los bloques que crea..

El problema que tenemos ahora es que, dado que los colores del Bloque son completamente aleatorios, no es raro que comiences el juego y veas que se hagan un montón de partidos de inmediato. Esto es un problema porque puede hacer que los primeros segundos del juego sean muy confusos para alguien que nunca ha jugado antes, y porque le da al jugador puntos que no ganó..

Para resolver el problema, crearemos una función que examinará cada bloque y luego veremos si ese bloque es del mismo color que cualquiera de sus vecinos. Si es del mismo color que uno de sus vecinos, continuará cambiando el color de ese bloque hasta que ya no coincida con ninguno de los bloques que lo rodean..

Para hacer que este sistema funcione, también tendremos que crear múltiples funciones de soporte y eventos, y agregar una nueva variable de instancia a la Bloquear objeto.

Haciendo que funcione

Primero, crea una nueva variable de instancia para el Bloquear objeto:

Variable de instancia: Tipo de ID de bloque = Número Valor inicial = 0

Esta variable es lo que usaremos para identificar fácilmente un bloque, de modo que podamos decir algunas de las funciones que vamos a hacer exactamente a qué bloque queremos ver, independientemente de su posición..

Antes de continuar, también debemos comenzar a utilizar esta variable. Ve a la Al inicio del diseño. Evento que crea los bloques y agrega una nueva acción antes de la acción que aumenta NumBlocks:

Acción: Bloque> Establecer valor Variable de instancia = Valor de BlockID = Bloques numéricos

Tu Evento de desove de bloques ahora debería verse así:

Luego, necesitamos hacer una función que tome la posición X e Y de un bloque y nos diga de qué color es ese bloque:

Evento: Condición: Función> En función Nombre = Sub-Evento "GetBlockColor": Condición: Bloque> Comparar Comparación X = Igual a la coordenada X = Función.Param (0) Estado: Bloque> Comparación Y de comparación = Igual a Y co -ordinate = Function.Param (0) Action: Function> Set return value Value = Block.Color Sub-Event: System> Else Action: Function> Set return value Value = -1

La función debería verse así cuando haya terminado:

Ahora que tenemos una función que nos puede decir el color de cualquier bloque, vamos a crear la función que realmente mirará un bloque y determinará si tiene algún Bloque adyacente que sea del mismo color..

La forma en que funcionará esta función es bastante simple..

  • Primero, pasaremos un ID de bloque en la función.
  • Si actualmente hay un bloque con ese ID de bloque, La función observará los cuatro bloques vecinos y determinará si el bloque que está mirando es del mismo color que cualquiera de sus vecinos..
  • Si encuentra que hay un vecino del mismo color, comenzará a cambiar el color del bloque que está mirando, y continuará cambiando el color hasta que el bloque sea un color diferente al de todos sus vecinos..

Antes de que podamos hacer este Evento, tenemos que hacer una nueva Variable Global. En la función usaremos un bucle While para determinar si el color del bloque necesita ser cambiado. La variable que estamos a punto de crear es la variable que While Loop utilizará para determinar si debe continuar ejecutándose:

Variable global: HasMatchingNeighbor Type = Number Valor inicial = 0

Propina:El evento que vamos a hacer contiene un evento basado en Or. Si nunca ha realizado un Bloque de evento que tenga un atributo O, todo lo que tiene que hacer es hacer el Bloque de evento como lo haría normalmente y luego hacer clic con el botón derecho en el Bloque completo y elegir Hacer 'O' Bloquear. A diferencia de un bloque de evento estándar que requiere que todas las condiciones se llenen antes de que se dispare, un bloque O se disparará si alguna se cumple la condición.

Entonces, hagamos el Evento:

Evento: Condición: Función> En la función Nombre = "RemoveSpawnedMatches" Sub-Evento: Condición: Bloque> Comparar variable de instancia Variable de instancia = Bloqueo de comparación = Igual al valor = Función.param (0) Acción: Sistema> Establecer valor Variable = HasMatchingNeighbor Value = 1 Sub-evento: Condición: Sistema> Mientras Condición: Sistema> Comparar variable Variable = HasMatchingNeighbor Comparison = Igual al valor = 1 Sub-Evento: Condición: Bloque> Comparar instancia de instancia Variable Instancia = Color Comparación = Igual al valor = Función. Llamada ("GetBlockColor", Block.X - (Block.Width + 2), Block.Y) Acción: Bloque> Establecer valor Variable de instancia = Color Valor = piso (Aleatorio (1,7)) Acción: Sistema> Establecer valor Variable = HasMatchingNeighbor Value = 1 Sub-evento: Condición: Sistema> Else Condición: Block> Comparar variable de instancia Variable de instancia = Color Comparison = Igual a Value = Function.Call ("GetBlockColor", Block.X + (Block.Width + 2) , Bloque.Y) Acción: Bloque> Establecer valor Variable de instancia = Valor de color = piso (Aleatorio (1,7)) Acción: Sistema> Establecer valor Variable = HasMatchingNeighbor Value = 1 Sub-evento: Condición: System> Else Condición: Block> Comparar variable de instancia Variable de instancia = Color Comparison = Igual a Value = Function.Call ("GetBlockColor", Block.X, Block.Y - (Block.Width + 2)) Action: Block> Set value Instance variable = Color Value = floor (Random (1,7)) Action: System> Set value Variable = HasMatchingNeighbor Value = 1 Sub-Event: Condition : Sistema> Condición Else: Bloque> Comparar variable de instancia Variable de instancia = Comparación de color = Igual al valor = Función.Call ("GetBlockColor", Block.X, Block.Y + (Block.Width + 2)) Acción: Block> Set valor Variable de instancia = Color Valor = piso (Aleatorio (1,7)) Acción: Sistema> Establecer valor Variable = HasMatchingNeighbor Value = 1 Sub-Evento: Condición: Sistema> Else Acción: Sistema> Establecer valor Variable = HasMatchingNeighbor Value = 0

Su evento debe verse así:


Entonces, ¿cómo funciona esta función exactamente?

Lo primero que hace es buscar un Bloquear con el ID de bloque que el sistema pasó. Cuando localiza eso Bloquear establece el valor de HasMatchingNeighbors a 1 y luego ejecuta el bucle While.

Dado que el bucle While solo se ejecutará cuando HasMatchingNeighbors es 1, ese es el valor al que lo establece. Durante el ciclo While, comprueba si hay un vecino Bloquear a la izquierda, a la derecha, arriba o abajo, es el mismo color que el Bloquear estamos mirando a Si encuentra una coincidencia Bloquear en alguna de estas posiciones, asigna al azar un nuevo color a la Bloquear y luego ejecuta la prueba de nuevo asegurándose HasMatchingNeighbors se establece en 1. Cuando finalmente encuentra un color para el Bloquear que no coincide con ninguno de sus vecinos, cambia el valor de HasMatchingNeighbors a 0 para que el bucle While termine y el programa pueda avanzar.

Ahora necesitamos implementar esta función en el juego; Para ello tendremos que crear dos nuevas variables y dos nuevas funciones. Empecemos por las variables..

Variable global: CheckStartingMatches Type = Number Value = 0
Variable global: Tipo CheckNewestRow = Valor de número = 0

Sus variables deben verse así:

Las dos variables que acabamos de crear se utilizarán para desencadenar los dos eventos que estamos a punto de crear. Los Eventos en sí se utilizarán para recorrer los bloques inmediatamente después de crearlos y enviar cada bloque a la Eliminar parcelas emparejadas función.

La razón por la que no solo estamos llamando al Eliminar parcelas emparejadas La función inmediatamente después de crear el bloque se debe a que la cuadrícula de bloques debe estar completa para que la función funcione correctamente. Entonces, en lugar de solo llamar directamente a la función cuando se hacen los bloques, en lugar de eso, desencadenamos un Evento que puede pasar por los bloques y llamar a la Función por sí solo después de que se genera la cuadrícula.

El primer evento será específicamente para iterar a través del grupo inicial de bloques:

Evento: Condición: Sistema> Comparar variable Variable de instancia = CheckStartingMatches Comparación = Igual al valor = 1 Condición: Sistema> Para Nombre = "Bloques" Inicio índice = 0 Fin de índice = NumBlocks-1 Acción: Función> Llamar a función Nombre = "EliminarSpawnedMatches" Parámetro 0 = loopindex ("Bloques") SubEvento: Condición: Sistema> Comparar dos valores Primer valor = loopindex ("Bloques") Comparación = Igual al segundo valor = NumBlocks-1 Acción: Sistema> Establecer variable Instancia variable = CheckStartingMatches Value = 0

Así es como debería verse tu evento:

El segundo Evento será específicamente para verificar nuevas filas de bloques cuando se realicen:

Evento: Condición: Sistema> Comparar variable Variable de instancia = CheckNewestRow Comparación = Igual al valor = 1 Condición: Sistema> Para Nombre = "Bloques" Índice de inicio = NumBlocks-9 Fin de índice = NumBlocks-1 Acción: Función> Función de llamada Nombre = " RemoveSpawnedMatches "Parameter 0 = loopindex (" Blocks ") SubEvent: Condición: System> Compare dos valores First value = loopindex (" Blocks ") Comparación = Equal to Second value = NumBlocks-1 Action: System> Set variable Variable de instancia = CheckNewestRow Value = 0

Así es como debería verse el segundo Evento:

Implementación

Con estas dos funciones implementadas, ahora solo necesitamos implementarlas. Ve al Evento inicial que hace los bloques, el En inicio de diseño Evento. Vamos a agregar un Sub-evento a esto que le dirá a la CheckStartingMatches Evento para activar.

Subevento: Condición: Sistema> Comparar dos valores Primer valor = índice de bucle ("X") Segundo valor de comparación: 7 Condición: Sistema> Comparar dos valores Primer valor = índice de bucle ("Y") Segundo valor de comparación: 3 Acción: Sistema> Establecer valor Variable de instancia = Valor de CheckStartingMatches = 1

Tu evento ahora debería verse así:

Este subevento escucha cuándo ha finalizado el bucle For anidado y, a continuación, cambia el valor del CheckStartingMatches Variable para activar el evento apropiado..

Ahora vamos a hacer casi el mismo Sub-Evento exactamente y lo adjuntaremos a la SpawnNewBlocks función.

Subevento: Condición: Sistema> Comparar dos valores Primer valor = índice de bucle ("X") Segundo valor de comparación: 7 Acción: Sistema> Establecer valor Variable de instancia = Valor CheckNewestRow = 1

SpawnNewBlocks Ahora debería verse así:

Este subevento hace lo mismo que el anterior, excepto que activa el otro evento que creamos. Si ejecuta el juego en este punto, debería ver que al iniciar el juego ya no se producen coincidencias automáticamente..


Conclusión

En este tutorial, no hicimos demasiados cambios en el juego, pero los que hicimos fueron muy importantes..

En este punto, creo que es mejor que nos detengamos por ahora y guardemos los últimos dos elementos del juego para el siguiente tutorial, donde cubriremos cadenas / combos y la pantalla de Game Over. Esta será la parte final de la serie, por lo que también hablaré sobre algunas mecánicas del juego que no cubriremos en estos tutoriales, y te daré algunos consejos sobre cómo puedes crear esos sistemas por tu cuenta..

Si desea obtener una ventaja en el contenido de la próxima semana, comience a ver cómo podría detectar cuándo debería aparecer la pantalla Game Over, según la posición o la altura de algunos de los bloques. Alternativamente, comienza a pensar en cómo podrías detectar cuando el jugador hace una reacción en cadena que hace que se forme más de un grupo..

Hagas lo que hagas, espero verte aquí la próxima semana para la última entrega de la serie..