Students Save 30%! Learn & create with unlimited courses & creative assets Students Save 30%! Save Now
Advertisement
  1. Game Development
  2. Platformer
Gamedevelopment

Construyendo un Beat 'Em Up en Game Maker, Parte 1: Movimiento del Jugador, Ataques y Enemigos Básicos

by
Difficulty:IntermediateLength:LongLanguages:

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

En los días del barrio Arcade y los primeros días de los juegos de consola, los juegos Beat 'Em Up eran uno de los géneros más populares. Nacidos del matrimonio de las plataformas y el Juego de la Lucha, los Beat 'Em Ups eran combates basados en juegos de acción donde el jugador luchaba contra hordas de enemigos mientras progresaba a través de ambientes mayormente horizontales.

En los juegos modernos, los clásicos de Beat 'Em Up, como Turtles In Time y X-Men el juego de arcade han sido reemplazados por 3D Brawlers como Shadow of Mordor y Arkham Knight, la evolución AAA de estos clásicos que consumen todo el trimestre.

En esta serie de artículos, vamos a mirar atrás y explorar cómo hacer un juego clásico de Beat 'Em Up.

Preparándose

Antes de seguir adelante, hablemos de las habilidades necesarias para el tutorial. El juego que estamos creando se desarrollará en Game Maker Studio Pro, que está disponible de forma gratuita en el sitio web de YoYo Games.

También debe tener al menos una comprensión básica de GML, el lenguaje de codificación incorporado de Game Maker. Mientras me tomo el tiempo para explicar cómo funciona el código y qué hace todo, hablaremos de algunos conceptos de programación moderadamente avanzados, incluida AI, por lo que será más fácil de entender si ya tiene una base sólida para trabajar.

Además, asegúrese de descargar el archivo zip de los Activos Parte 1 que se incluye en la parte superior de este artículo, ya que incluye los gráficos y sonidos que necesitará para completar este artículo. Este archivo zip también incluye un proyecto Game Maker completo para esta parte del serie, para que pueda consultar si se encuentra con algún problema.

Ahora abra Game Maker y empecemos.

Importación de gráficos

En este artículo vamos a crear un objeto jugador y un objeto enemigo que podemos matar, y le daremos al jugador la capacidad de moverse y atacar. Sin embargo, antes de que podamos hacer algo de eso, necesitamos agregar algunos gráficos que podamos usar para el jugador y el enemigo. Comencemos con la animación Player Idle.

  1. Haga clic derecho en la carpeta Sprites y elija Crear Sprite.
  2. Nombre sprite SPR_PlayerIdle.
  3. Use la opción Cargar Sprite y vaya a los archivos de imagen que descargó para este tutorial.
  4. Elija Activos> Imágenes> Reproductor> PlayerIdle.png. Este es el único cuadro que necesitaremos para esta animación.

Ahora que la imagen se importa, necesitamos establecer el origen. Si echas un vistazo a todas las animaciones del jugador, verás que las imágenes no son todas del mismo tamaño. Esto significa que la posición del personaje tampoco es la misma en cada imagen. Si usamos estas imágenes juntas tal como están, podrían hacer que el personaje cambie de posición a medida que se animan y arrojarán nuestros cuadros delimitadores. En la imagen a continuación, puede ver los primeros cuadros de tres animaciones de jugadores diferentes y cómo se compara su posición.

The first frame from three of the animations overlaid on top of each other for comparison

Si hiciéramos la transición entre estas animaciones sin ajustar los orígenes, la posición del jugador cambiaría claramente de una a la siguiente. Para resolver esto, podemos configurar manualmente el origen para que esté en la misma posición para cada animación, y el reproductor no cambiará.

Al hacer esto, es útil contar con un punto de referencia sobre el personaje para utilizarlo como guía, de modo que pueda saber fácilmente si es necesario ajustar el origen. Para todos los gráficos de los personajes, usaré el punto grande en el cofre como mi punto de referencia. Posicionaré el origen en la parte inferior de la imagen y en el lado izquierdo del punto. Aumenté la saturación en la imagen a continuación para que pueda ver fácilmente a qué me refiero.

An exampleof how the origin should be setup for the images incldued with the tutorial

Para la animación Inactivo, el origen estará en x = 40, y = 117.

Ahora tenemos que importar el resto de los sprites que usaremos en este artículo. Use la tabla a continuación para ver qué imágenes importar, qué nombre debe darle al sprite y dónde debe ubicarse el origen.

Nombre del sprite Imágenes Origen
SPR_PlayerWalking
PlayerWalking1.png,
PlayerWalking2.png,
PlayerWalking3.png,
PlayerWalking4.png,
PlayerWalking5.png,
PlayerWalking6.png
X = 43, Y = 117
SPR_PlayerBasicPunch
PlayerPunchA1.png,
PlayerPunchA2.png,
PlayerPunchA3.png,
PlayerPunchA4.png,
PlayerPunchA5.png
X = 55, Y = 122
SPR_PlayerStrongPunch
PlayerPunchB1.png,
PlayerPunchB2.png,
PlayerPunchB3.png,
PlayerPunchB4.png,
PlayerPunchB5.png
X = 60, Y = 124
SPR_PlayerHit
PlayerHit.png
X = 43, Y = 117

También necesitamos importar algunos de los gráficos de enemigos. Podemos hacer esto de la misma manera. Estas imágenes se encontrarán en la carpeta Recursos> Imágenes> Enemigo estándar.

Nombre del sprite

Imágenes

Posición de origen

SPR_EnemyIdle

RedEnemyIdle.png

X = 40, Y = 117

SPR_EnemyWalking

RedEnemyWalking1.png, RedEnemyWalking2.png, RedEnemyWalking3.png, RedEnemyWalking4.png, RedEnemyWalking5.png, RedEnemyWalking6.png

X = 45, Y = 117

SPR_EnemyHit

RedEnemyHit.png

X = 46, Y = 117

Creando nuestros primeros objetos de juego

Ahora que tenemos todos los gráficos que necesitaremos, comenzaremos a construir nuestro juego creando un objeto Jugador y un objeto Enemigo.

  1. Haga clic con el botón derecho en la carpeta Objetos y elija Crear / Insertar objeto.
  2. Nombre el nuevo objeto OBJ_Player.
  3. Establezca el sprite del objeto en SPR_PlayerIdle.
  4. Use Agregar evento> Crear.
  5. En la pestaña Control, agregue una acción Ejecutar código.
  6. Agregue el siguiente código:

El código que tenemos arriba está estableciendo algunas variables básicas para nuestro objeto Jugador. A medida que desarrollemos nuestro juego, agregaremos más variables, pero veamos lo que tenemos hasta ahora.

Speed es la velocidad de movimiento del jugador, mientras que SpeedMod modificará la velocidad del jugador según los potenciadores y los debuffs.XSpeed y YSpeed se usarán para establecer la velocidad del jugador en cada dirección cuando se muevan. IsAttacking e IsHit nos dicen si el jugador está atacando o golpeando para que podamos evitar que se mueva, y AttackType nos dice qué ataque está usando. Finalmente, MaxHP y CurrentHP hacen un seguimiento de la salud del jugador.

También debe observar las variables OnGround y GroundY. Estas variables no son tan importantes ahora, pero se usarán más adelante cuando agreguemos cosas como Knockback.

Lo último que hace este código es establecer image_speed, que controla qué tan rápido se reproducirán nuestras animaciones.

Mientras estamos en eso, hagamos el objeto Enemigo también.

  1. Haga clic con el botón derecho en la carpeta Objetos y elija Crear / Insertar objeto.
  2. Nombre el nuevo objeto OBJ_Enemy.
  3. Establezca el sprite del objeto en SPR_EnemyIdle.
  4. Use Agregar evento> Crear.
  5. En la pestaña Control, agregue una acción Ejecutar código.
  6. Agregue el siguiente código:

Como puede ver, nuestro Enemigo actualmente es muy similar a nuestro jugador y usa muchas de las mismas variables. La única variable adicional es SideMod, que eventualmente usaremos para la IA de nuestro Enemigo.

Agregando una habitación

Con nuestros objetos básicos de enemigo y jugador configurados, agreguemos un espacio a nuestro juego para que puedan correr.

  1. Haga clic con el botón derecho en la carpeta Habitaciones y elija Crear / Insertar habitación.
  2. Deje el tamaño de la habitación como está por ahora.
  3. Ve a la pestaña Objetos.
  4. Seleccione el OBJ_Player y agréguelo a su habitación en el lado izquierdo.
  5. Selecciona el OBJ_Enemy y agrega algunos enemigos en el lado derecho.

A continuación puede ver cómo se vería la habitación básica, pero está bien si la hace ligeramente diferente a la mía.

Hacia el final de esta serie haremos un nivel más interesante, pero esto debería funcionar por ahora.

An example of a possible layout for the room

Agregar sombras

Antes de agregar movimiento, veamos si podemos mejorar un poco el aspecto del juego. En este momento, las cosas se ven muy planas ya que los personajes están parados frente a un fondo gris uniforme. Podemos solucionar esto agregando sombras debajo de los caracteres para simular la profundidad y hacer que parezca que los personajes están parados en un entorno, en lugar de una habitación gris en blanco.

  1. Abra el objeto Jugador y elija Agregar evento> Dibujar> Dibujar.
  2. En la pestaña Control, agregue una acción Ejecutar código.
  3. Agregue el siguiente código:

Todo lo que hace este código es dibujar un círculo gris oscuro ligeramente transparente debajo del personaje del jugador. Es muy simple, pero cuando lo vemos en el juego, hará mucho para que el personaje se sienta como si estuviera parado en el suelo. Cuando vayas al juego, el personaje debería verse así:

The player character with a shadow implemented

Mucho mejor!

Ahora que el personaje del jugador se ve bien, deberíamos hacer lo mismo con los Enemigos. Siga los mismos pasos para agregar una sombra para los personajes enemigos.

Cuando hayas terminado, si pruebas tu juego, debería verse así:

All of the characters with shadows enabled in-game

Pequeños cambios como este realmente pueden mejorar un juego y ayudarlo a sentirse mucho más interesante. En este caso, las sombras hicieron mucho para ayudar a "vender" el entorno y darle profundidad, incluso si no es perfecto.

Ahora que nuestro juego es un poco más interesante, podemos agregar algo de juego real.

Movimiento del jugador

Hasta ahora hemos configurado nuestros personajes, pero en realidad no les hemos dicho cómo moverse o atacar. Como tu jugador no puede atacar al enemigo desde el otro lado del campo, comenzaremos con el movimiento. Este es un código bastante largo, por lo que vamos a hacerlo de forma incremental y agregarlo pieza por pieza. Agreguemos la primera pieza.

  1. Ve al objeto del jugador.
  2. Use Agregar evento> Paso> Paso.
  3. En la pestaña Control, agregue una acción Ejecutar código.
  4. Agregue el siguiente código:

Todo lo que hace este código es verificar que el HP del jugador sea mayor que 0. Si no lo es, el jugador es destruido.

Ahora agregue este fragmento de código en la parte if de la declaración:

Esta parte del código verifica si se presionan las teclas A o D, y establece la XSpeed del Reproductor según corresponda. Si la tecla A está abajo, la XSpeed del jugador es negativa, lo que significa que se mueven hacia atrás, y si la tecla D está abajo, es positiva, lo que significa que avanzan.

Sin embargo, no podemos avanzar y retroceder.  Necesitamos poder movernos hacia arriba y hacia abajo también, así que agreguemos otra pieza de código para manejar W y S.

Agregue este fragmento de código en la parte if de la declaración, después del fragmento anterior:

Este código hace lo mismo que el anterior, excepto con YSpeed.

Usted podría estar pensando, "Esto es genial, mi personaje está listo para moverse". En realidad, sin embargo, todo lo que hemos hecho hasta ahora es establecer su velocidad, y todavía tenemos que moverlos. Dado que el próximo bloque de código es un poco más largo, vamos a dividirlo en trozos más pequeños. Comencemos agregando una versión restringida para que pueda ver lo que hará.

Agregue este fragmento de código en la parte if de la instrucción, después del fragmento anterior.

Entonces, como pueden ver, vamos a hacer tres cosas.

Primero, movemos físicamente al jugador usando las variables XSpeed y YSpeed; sin embargo, ignoramos el YSpeed si el Jugador no está en el suelo.

A continuación, cambiamos la dirección del sprite del jugador según la dirección en la que el jugador se está moviendo. De esta manera, si el jugador se mueve hacia la izquierda, están mirando hacia la izquierda, y si se mueven hacia la derecha, están mirando hacia la derecha.

Finalmente, animamos el reproductor para que esté usando el sprite Idle cuando no se mueven y el sprite andante cuando lo están.

Reemplacemos estos comentarios de a uno por vez. Reemplazar el comentario //If the player is on the ground... con el siguiente código:

La declaración if principal de este código verifica si el reproductor está en el suelo. Si lo están, tiene una declaración if interior que determina si el reproductor se mueve diagonalmente, y los ralentiza para evitar que se muevan más allá de lo que lo estaban si se movían en una de las direcciones cardinales. Si el jugador no está en el suelo, solo se considera su movimiento X.

A continuación, reemplace //Change the direction of... comentario con el siguiente código:

Este código es mucho más simple que el último bloque. Todo lo que hace es establecer la Xscale del sprite del jugador según la dirección en la que se mueven. La razón por la que verificamos si XSpeed es igual a 0 es que, si no lo hiciéramos, el reproductor tendría 0 píxeles de ancho cada vez que no se movieran.

Finalmente, reemplace // Animate the Player ... comment con el siguiente código:

Esta es otra pieza de código bastante simple. Si tanto XSpeed como YSpeed del Jugador son 0, y el jugador está en el suelo, debe significar que el Jugador no se está moviendo, y establece su animación en Inactivo. De lo contrario, si XSpeed o YSpeed no es igual a 0, el jugador está en el suelo, y no están usando el sprite Walking, establece su animación en Walking.

La parte realmente importante de este código es que verificamos que todavía no están usando la animación caminando antes de que la configuremos como su animación. Si no hiciéramos esto, entonces cada fotograma que el Jugador esté moviendo este código volvería a ser cierto, e intentaría constantemente reiniciar la animación caminando. Al verificar que no estén usando esa animación, evitamos este problema y permitimos que la animación se repita normalmente.

Lo último que necesitamos antes de que nuestro movimiento básico esté completo es agregar este código al final del evento Paso, después de la instrucción if / else:

Este código establece el GroundY para el jugador y establece su profundidad en la pantalla en función de su GroundY. El valor de GroundY se usará cuando el jugador sea derribado o lanzado para hacer un seguimiento de dónde está la sombra del jugador en el suelo y qué altura comenzó. Esta variable también ayuda al jugador a realizar un seguimiento de cuán alto es y cuándo debe golpear el suelo.

La declaración de profundidad después de eso hace que cuanto más alta en la pantalla el jugador obtiene, más atrás se dibujarán. De esta forma, cuando el jugador está corriendo más allá de los enemigos y moviéndose por el campo, siempre se dibujan correctamente en relación con otros objetos / caracteres.

Si vas al juego y comienzas a probar, ahora deberías poder correr alrededor del área del juego con el jugador. Sin embargo, es posible que notes algunos problemas cuando te acercas a los enemigos.

An example of bad depth drawing

La razón por la que la profundidad no está funcionando como describí anteriormente es porque necesitamos agregar una declaración similar al código del Enemigo para que su profundidad también esté configurada correctamente.

  1. Abra el objeto Enemigo y elija Agregar evento> Paso> Paso.
  2. En la pestaña Control, agregue una acción Ejecutar código.
  3. Agregue el siguiente código:

Ahora, si ingresas al juego, verás que la profundidad está funcionando correctamente. Cuando te mueves cerca de los enemigos, debes pasar delante y detrás de ellos correctamente.

The corrected depth drawing

Preparación para ataques: capas

Ahora que nuestro código de movimiento inicial está completo, podemos pasar al ataque. Sin embargo, antes de poder llegar al objeto de ataque real, debemos agregar dos cosas.

Primero, necesitamos una nueva constante que nos diga cuán cerca deben estar los personajes para golpearse entre sí. En un Beat 'Em Up como este, estamos simulando profundidad 3D. Hacemos esto de varias maneras, y una forma es hacer un seguimiento de la profundidad del jugador usando la variable de profundidad como hicimos anteriormente. La otra forma en que lo haremos es definiendo qué tan separados pueden estar dos objetos en el plano Y, antes de que ya no puedan interactuar. De esta forma, incluso si los sprites se superponen / colisionan, las colisiones solo contarán si los personajes están lo suficientemente cerca en el espacio del juego para permitir esa interacción y la perspectiva no causará ningún problema.

Si todavía no está seguro de lo que quiero decir, eche un vistazo a la imagen a continuación:

A collission that should not be considered valid for an attack

En esta imagen, el jugador y el enemigo chocan técnicamente, pero se puede ver desde la perspectiva de que no están lo suficientemente cerca como para interactuar. Al crear una constante llamada LayerSize, podemos establecer la distancia vertical máxima para permitir antes de que dos objetos ya no puedan interactuar.

  1. En la barra lateral debajo de Macros, elija Todas las configuraciones.
  2. En la primera macro, ingrese el nombre LayerSize y establezca el valor en 35.
  3. Presiona Ok.

Este fue un valor que se me ocurrió a lo largo del tiempo, que creí que funcionó bien, pero si quieres puedes jugar con aumentar o disminuir este valor para encontrar algo que funcione mejor para tu juego.

A medida que hacemos nuestros ataques, esta constante ayudará a determinar si los ataques se producen.

Preparándose para Ataques: Enemigos Imponentes

La otra cosa que tenemos que hacer antes de realizar cualquier ataque es configurar la animación de golpe del enemigo, para que reaccionen cuando los ataquemos. Para esto, utilizaremos la animación EnemyHit, que importamos anteriormente, y la variable IsHit.

Primero, ingresaremos al evento de paso y modificaremos el código para que la animación de éxito se use.

  1. Abre OBJ_Enemy.
  2. Seleccione el evento Paso y abra la acción del código.
  3. Agregue el siguiente código al comienzo del evento:

Solo para asegurarse de que este código funciona, ingrese al evento de creación del Enemigo y cambie su variable IsHit a verdadera. Luego ve al juego y echa un vistazo a la animación del Enemigo. Debería ver algo como esto:

The Enemy Hit animation

Si bien la animación de Hit definitivamente está funcionando, probablemente notarás que nunca termina. La razón de esto es porque no tenemos ningún código que restablezca el estado IsHit del enemigo después de una cierta cantidad de tiempo. Entonces, una vez que lo establecemos en verdad, permanece así para siempre.

Para que esto funcione, vamos a configurar una alarma que restablecerá la variable IsHit y volverá a desactivar al enemigo cuando se active. Luego, cada vez que se golpea al enemigo, cada ataque contendrá una declaración que le indicará al enemigo cuánto tiempo debe ser aturdido antes de volver a inactivo, y comenzará la alarma con esa cantidad de tiempo.

  1. Vaya al OBJ_Enemy y elija Agregar evento> Alarma> Alarma 0.
  2. En la pestaña Control, agregue una acción Ejecutar código.
  3. Agregue el siguiente código:

Todo lo que necesita hacer es reiniciar IsHit, y el evento Step se encargará del resto.

Realmente no puedes probar esto para asegurarte de que funciona, pero si agregas el código que aparece a continuación al final del evento Create, deberías ver brevemente lo que acabamos de configurar en la acción cuando comienza el juego por primera vez. Sin embargo, asegúrese de eliminar este código y vuelva a establecer IsHit en falso antes de continuar.

Creando el objeto de ataque

Ahora que tenemos todo el trabajo de preparación fuera del camino, podemos comenzar con los objetos de ataque reales.

Primero, necesitaremos hacer que un objeto de ataque padre contenga todas las estadísticas del ataque, como cuánto daño hace, cómo se ve el hitbox, qué efectos de partículas se deben usar, etc. Haciendo un objeto único para cada ataque es una práctica mejor que forzar a los objetos Player o Enemy a almacenar toda la información relevante, y tener un objeto principal hace que sea mucho más fácil hacerlo. También hace que el código de ataque sea más versátil, y nos permite programar un solo ataque que puede ser utilizado por múltiples personajes.

Para hacer el primer objeto de ataque, siga estos pasos:

  1. Haga clic con el botón derecho en la carpeta Objetos y elija Crear / Insertar objeto.
  2. Nombre el nuevo objeto ATK.
  3. Use Agregar evento> Crear.
  4. En la pestaña Control, agregue una acción Ejecutar código.
  5. Agregue el siguiente código:

La primera línea de código establece la profundidad del ataque de la misma manera que establecemos la profundidad para el jugador. El resto del código, sin embargo, establece algunas variables importantes para el ataque. Veamos qué hacen estas variables. Damage es la cantidad de daño que hace el ataque. StunLength es la cantidad de cuadros que el atleta será aturdido con la variable IsHit. Owner es quien hizo el ataque. Puede ser el Jugador o el Enemigo y evita que los enemigos se lastimen entre sí. DMGFrame nos permite decir cuándo el ataque causará daño.

En Beat 'Em Ups, el tiempo es importante, y los ataques solo deben causar daño si golpean en el momento correcto. Echa un vistazo a este ataque:

An example attack from an Enemy we will implement in a later tutorial

Si recibes daño antes de que caiga la mano del enemigo, te sentirías engañado, ya que parecería que no debería haber dolido todavía. La variable DMGFrame le dice al objeto de ataque qué marco debe causar daño, de modo que se ignoran las colisiones durante cada otro marco. Este tipo de cosas forman la base de todos los juegos de combate basados en el tiempo, desde Turtles in Time hasta Dark Souls, y hacen posible "leer" los ataques de tus oponentes y esquivarlos antes de que golpeen.

Ahora agreguemos el código de colisión para el ataque para que inflija daño cuando golpea.

  1. En el objeto Atk, vaya a Agregar evento> Colisión> OBJ_Enemy.
  2. En la pestaña Control, agregue una acción Ejecutar código.
  3. Agregue el siguiente código:

El código que tenemos arriba se dispara siempre que el ataque colisiona con un objeto enemigo, y usa una simple declaración if para determinar si el ataque impacta. La instrucción if prueba cuatro cosas:

  1. ¿El cuadro actual es igual al cuadro de daño?
  2. ¿La diferencia entre la profundidad del ataque y la profundidad del enemigo es menor que el LayerSize?
  3. ¿El ataque y el enemigo tienen valores Y cercanos? En otras palabras, ¿están ambos en el suelo, o ambos cerca el uno del otro en el aire?
  4. ¿El ataque fue realizado por el jugador? Dado que este evento se aplica a colisiones con enemigos, verificamos que el jugador haya realizado el ataque. Puedes eliminar este control si quieres que los enemigos se lastimen entre ellos.

Si todas estas condiciones son ciertas, entonces el ataque fue exitoso, y el enemigo recibe daño y queda aturdido.

También tenemos que hacer algo similar para las colisiones con el jugador.

  1. En el objeto Atk, vaya a Agregar evento> Colisión> OBJ_Player.
  2. En la pestaña Control, agregue una acción Ejecutar código.
  3. Agregue el siguiente código:

Este es el mismo código que la colisión Enemiga, excepto que comprueba si el ataque fue realizado por el Enemigo, en lugar del jugador, y evita que el jugador reciba daño de sus propios ataques.

Ahora tenemos que hacer un hitbox para el ataque también. Hitboxes es la porción del sprite que se considera "colisible", y se utilizan para garantizar que solo ciertas partes del sprite causen una colisión y causen daño al personaje. Por ejemplo, si vuelvo al ataque del personaje amarillo, solo querría que una porción pequeña, delineada en rojo a continuación, sea colisible.

The portion of the Enemys attack which should damage the Player

Si algo más que ese brazo causaba que el jugador recibiera daño, se sentirían molestos y el juego parecería injusto. Para resolver este problema, puedo usar un hitbox que solo registra esa porción del sprite e ignora todo lo demás.

Puede importar el hitbox para nuestro ataque usando la tabla a continuación. Luego, asigne el hitbox como el sprite del objeto ATK una vez que haya terminado.

Nombre del sprite

Imágenes

Posición de origen

SPR_BasicPunch_Hitbox

BasicPunchHitbox1.png,

BasicPunchHitbox2.png,

BasicPunchHitbox3.png,

BasicPunchHitbox4.png,

BasicPunchHitbox5.png

X = 55, Y = 122

Cuando el jugador ataque, establecerán su sprite en consecuencia, pero usar el sprite de hitbox para el sprite del ATK asegura que solo esa parte de la animación de ataque registrará la colisión.

Lo último que tenemos que hacer para el ataque es asegurarnos de que se destruya cuando finalice el ataque. Si no lo destruimos, el ataque continuará funcionando infinitamente y matará a nuestro enemigo casi de inmediato. Para garantizar que esto no ocurra, vamos a utilizar un evento de fin de animación.

  1. Vaya al objeto ATK y elija Agregar evento> Otro> Fin de animación.
  2. En la pestaña Control, agregue una acción Ejecutar código.
  3. Agregue el siguiente código:

Con este evento, el objeto de ataque se destruirá inmediatamente una vez que haya terminado de ejecutarse, y no se mantendrá para causarnos más problemas más adelante.

Ahora solo tiene que desmarcar la casilla de verificación Visible en el Objeto ATK para que no se pueda ver el hitbox.

Eso completa nuestro objeto base de ataque, pero aún necesitamos construir nuestro primer ataque real al extender el objeto base. Usar el objeto ATK como base para otros ataques hace que sea fácil construir rápidamente una gran variedad de ataques únicos.

  1. Crea un nuevo objeto llamado ATK_BasicPunch.
  2. Establezca Parent en el objeto ATK.
  3. Asigna Sprite SPR_BasicPunch_Hitbox.
  4. Use Agregar evento> Crear.
  5. En la pestaña Control, agregue una acción Ejecutar código.
  6. Agregue el siguiente código:

El golpe básico ahora está técnicamente completo, ya que amplía el objeto ATK y hereda todas las propiedades establecidas en el evento Crear. Sin embargo, si quería que su golpe básico fuera más poderoso o aturdido por un período de tiempo más largo, podría cambiar esas propiedades al volver a establecerlas aquí.

Por ejemplo, podrías usar:

Esto haría que el ataque inflija más daño, pero aturde por menos cuadros.

También puedes usar:

Este código causaría menos daño, pero aturdiría al enemigo por más tiempo.

Puedes modificar las variables base Damage, StunLength e incluso DMGFrame (asegúrate de que este número no sea más de 5, ya que el ataque tiene solo 5 fotogramas) como desees, y haz diferentes variaciones en el mismo tipo. de ataque Sin embargo, no importa lo que haga, asegúrese de que su nuevo ataque tenga el objeto ATK configurado como Principal, y tenga la línea event_inherited () al comienzo de cualquier evento que la clase Parent también utilice.

Hacer que el jugador ataque

Ahora que nuestro ataque ha terminado, nuestro jugador necesita poder usarlo. Para nuestro sistema de combate, vamos a utilizar tres posibles esquemas de control para acomodar a muchos jugadores diferentes.

Vamos a permitir que los jugadores usen IJKL, las 4856 teclas del teclado numérico e incluso las teclas de flecha, como posibles diseños para los botones de ataque. Esto les da a los jugadores la posibilidad de usar cualquier configuración que prefieran en función del tamaño / diseño de su teclado. Además de eso, dado que los tres de esos conjuntos tienen el mismo diseño básico, es fácil hacer que todos funcionen. J, 4 y Flecha izquierda serán ataques ligeros, I, 8 y Flecha hacia arriba serán ataques fuertes, K, 5 y Flecha hacia abajo serán Capturas, y L, 6 y Flecha hacia la derecha serán Especiales.

  1. En el objeto Player, elija Agregar evento> Pulsación de tecla> Cualquier tecla.
  2. En la pestaña Control, agregue una acción Ejecutar código.
  3. Agregue el siguiente código:

Primero, este código verifica si el Reproductor está presionando cualquiera de los botones de Ataque ligeros válidos que discutimos anteriormente, la Flecha hacia la Izquierda, la tecla 4 en el teclado numérico o la tecla J. Si es así, establece AttackType del jugador en un golpe básico. Después de determinar AttackType, verifica que el usuario esté en el suelo y llama al evento de Ataque, si es así.

El evento de Ataque creará el objeto de ataque basado en el ataque que el jugador usó. Puede parecer extraño que hagamos de este un evento separado, ya que nuestro código es muy simple, pero a medida que agreguemos más ataques y finalmente implementemos combos, hará que nuestro código sea mucho más fácil de administrar si estos elementos están separados.

  1. En el objeto Player, elija Agregar evento> Otro> Definido por el usuario> Usuario 2.
  2. En la pestaña Control, agregue una acción Ejecutar código.
  3. Agregue el siguiente código:

Este código es bastante simple, aunque al principio parece complejo.

Primero, hacemos un objeto temporal para almacenar el ataque en sí mismo. Entonces, siempre y cuando el jugador no haya sido golpeado, y no esté Muerto, determinaremos qué ataque se está usando, estableceremos la animación y crearemos un objeto de ataque de ese tipo. Finalmente, si se creó un objeto de ataque, establece al jugador que atacará, establece la dirección y la velocidad del ataque para que coincida con la del jugador, y establece el valor de Propietario del ataque de manera adecuada.

En este punto, podemos ingresar al juego y probar este ataque. Si te acercas al Enemigo y usas uno de los botones de ataque ligero, deberías ver al jugador atacar y el Enemigo es golpeado.

Sin embargo, es posible que notes un problema. No importa cuánto espere, la animación del Reproductor nunca apaga la animación de ataque, a pesar de que el Enemigo ya no está recibiendo daño. También notará que ya no puede moverse.

Este es el mismo problema que tratamos anteriormente con el Enemigo y su animación de éxito. Al igual que con Enemy, debemos configurar un sistema que restablezca la variable IsAttacking del jugador cuando finalice el ataque. Vamos a hacer esto con otro evento de fin de animación.

  1. Vaya a OBJ_Player y elija Crear evento> Otro> Fin de animación.
  2. En la pestaña Control, agregue una acción Ejecutar código.
  3. Agregue el siguiente código:

Ahora cuando va al juego, el ataque debería funcionar exactamente como esperaba, y la animación debería finalizar cuando se supone que debe hacerlo.

Agregado sonido

Nuestro ataque funciona bien en el juego, pero no hace un buen trabajo atrayendo al jugador. Parte del problema es que no tenemos ningún efecto de sonido para dar retroalimentación al jugador cuando golpea o falla con un ataque. Vamos a resolver este problema antes de llamar al objeto de ataque completo.

Tendremos que importar dos sonidos para el ataque, un sonido Hit y un sonido Miss. Siga estos pasos para importar el primer sonido.

  1. Haga clic con el botón derecho en la carpeta Sonidos y elija Crear sonido.
  2. Establezca el nombre en SND_BasicPunch1.
  3. Importe el archivo de sonido LightPunch1.wav desde los activos del proyecto.
  4. Establezca la frecuencia de muestreo a 48000.
  5. Establezca la velocidad de bits en 320.
  6. Presiona Ok para guardar tu sonido ...

¡Buen trabajo! Ya ha importado su primer efecto de sonido.

Ahora haremos lo mismo con el sonido Miss.

  1. Haga clic con el botón derecho en la carpeta Sonidos y elija Crear sonido.
  2. Establezca el nombre en SND_MissedPunch.
  3. Importe el archivo de sonido Miss.wav de los activos del proyecto.
  4. Establezca la frecuencia de muestreo a 48000.
  5. Establezca la velocidad de bits en 320.
  6. Presiona Ok para guardar tu sonido.

Ahora que hemos importado nuestros sonidos, necesitamos agregar algunas variables nuevas a nuestro objeto de ataque para que pueda usar los sonidos correctamente.

  1. Entra en OBJ_Attack y abre Create Event.
  2. Agregue el siguiente código al final de la acción Ejecutar código:

Estas tres variables son bastante simples. Las variables HitSound y MissSound nos permiten personalizar los sonidos al azar para cada ataque en su evento de creación, de la misma manera que podemos personalizar las otras propiedades de cada ataque que creamos. La variable Hit nos permite verificar si el ataque fue exitoso antes de reproducir el sonido Miss.

Con las variables en su lugar, necesitamos implementarlas. Primero implementaremos el sonido Hit.

  1. Con OBJ_Attack, abra Colisión con OBJ_Enemy.
  2. Agregue el siguiente código al final de la declaración if que confirma que la colisión es válida:

Todo lo que este código hace es reproducir el HitSound y establecer la variable Hit en verdadero cuando el ataque colisiona con un Enemigo.

También podemos usar el mismo código para el evento de colisión del jugador.

  1. Con OBJ_Attack, abra Collision con OBJ_Player.
  2. Agregue el siguiente código al final de la declaración if que confirma que la colisión es válida:

Finalmente, necesitamos reproducir el sonido Miss si el ataque no golpea nada. A diferencia del sonido Hit, que se reproduce en el momento de la colisión, el sonido Miss solo se reproducirá si el objeto Attack se destruye sin tocar nada, por lo que este sonido deberá reproducirse en un evento Destroy.

  1. Con OBJ_Attack, elija Agregar evento> Destruir.
  2. En la pestaña Control, agregue una acción Ejecutar código.
  3. Agregue el siguiente código:

Como puede ver, todo lo que este código hace es reproducir MissSound si Hit es igual a falso.

Ahora puede ir al juego y probar su ataque por última vez, y los efectos de sonido deberían funcionar perfectamente.

Haciendo un ataque fuerte

Ahora que nuestro ataque Básico está hecho, hagamos un tipo de ataque más, un Ataque Fuerte. Para este ataque, use la tabla siguiente para configurar el hitbox:

Nombre del sprite

Imágenes

Posición de origen

SPR_StrongPunch_Hitbox

StrongPunchHitbox1.png,

StrongPunchHitbox2.png,

StrongPunchHitbox3.png,

StrongPunchHitbox4.png,

StrongPunchHitbox5.png

X = 60, Y = 124

También deberíamos importar un único HitSound para este ataque, ya que se supone que es más poderoso que un ataque estándar.

  1. Haga clic con el botón derecho en la carpeta Sonidos y elija Crear sonido.
  2. Establezca el nombre en SND_StrongPunch1.
  3. Importe el archivo de sonido HeavyPunch1.wav desde los activos del proyecto.
  4. Establezca la frecuencia de muestreo a 48000.
  5. Establezca la velocidad de bits en 320.
  6. Presiona Ok para guardar tu sonido.

Ahora que tenemos todos los activos listos, hagamos el objeto de ataque real.

  1. Crea un nuevo objeto llamado ATK_StrongPunch.
  2. Establezca Parent en el objeto ATK.
  3. Desmarque la casilla de verificación Visible.
  4. Asigna Sprite SPR_StrongPunch_Hitbox.
  5. Use Agregar evento> Crear.
  6. En la pestaña Control, agregue una acción Ejecutar código.
  7. Agregue el siguiente código:

Ahora regrese al objeto Player y añada este código al evento Presionar Teclado> Cualquier tecla después del ataque ligero si es así para que también pueda detectar cuándo el jugador usa ataque fuerte:

Finalmente, vaya a User Defined 2 y agregue este código al final de la declaración if que hace que el objeto Ataque ligero, por lo que también puede hacer el Ataque fuerte. Asegúrese de que esté dentro del if si comprueba si el jugador está muerto:

Tu código ahora debería verse así:

The updated attack code for the Player

Ahora bien, si ingresas al juego, deberías poder usar un Ataque Ligero y un Ataque Fuerte sobre un enemigo. Como puede ver, aunque los dos ataques son esencialmente muy similares, se diferencian por la animación asociada a ellos, sus hitboxes y sus propiedades básicas.

Conclusión

Ahora debería poder editar y remezclar libremente estos ataques como mejor le parezca. En el siguiente artículo veremos cómo los Enemigos tienen la capacidad de defenderse y crear funciones más avanzadas para la cámara.

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.