En esta nueva entrada haremos que Arthur dispare su arma. Para ello veremos como crear un objeto por código, como gestionarlo, y como gestionar un temporizador.


Arthur tiene como modo de defensa la capacidad de lanzar espadas. Solo puede lanzar como máximo dos a la vez, y las espadas vuelan paralelas al suelo. Teniendo esto en cuenta vamos a continuar programando el juego e implementaremos esto.

Copia el archivo spear.png dentro de la carpeta sprites, Crea una nueva hoja de sprites y añade el archivo que acabas de copiar. Crea 4 animaciones, cada una con de la imágenes.

Crear animaciones del arma


Cómo el arma será un elemento que aparecerá en el juego por momentos y luego desparece, vamos a crearlo por código.

Creación del arma por código.

En la sección private añade dos elementos TcastleScene. Añadimos dos elementos, porque uno sera el arma, y el otro será el arma rotada 180. Para poder tener un elemento para cada dirección de disparo

Sprites de las armas

Siguiendo con la idea de tener lo más ordenado posible el código crearemos un procedimiento dónde escribiremos el código necesario para inicializar las armas.

En la sección Private, crea un procedimiento llamado ConfigureWeaponSpriteScene, puedes pulsar control+shift+c para que Lazarus cree el cuerpo del procedimiento automáticamente.

Procedimiento de configuración Sprites

En el procedimiento escribimos el siguiente código.

Básicamente lo hace este código, es crear los elemento que hemos declarado en la sección Private. Es importante que al crearlo le indiquemos el parámetro FreeAtStop de esta manera el motor gráfico será el encargado de liberar de la memoria el objeto cuando le indiquemos que ya no lo usaremos más.

La siguiente línea le asignamos la hoja de sprites que debe cargar. Después le indicamos que animación debe ejecutar, y por último le indicamos que su lo represente a una escala 1,1,1. Esto es que su tamaño original.

Estas tres líneas son iguales, tanto para una arma como para su “homologa” rotada. Pero el arma que usaremos rotada, debemos indicarle que la rote. Esto se hace indicando una rotación, de la misma manera que hicimos con el personaje del juego.

Por último debemos llamar a este procedimiento desde el procedimiento Start.

Declaración ConfigureWeaponsSpriteScene

Para cumplir el resto de las condiciones que se comentaron antes, debemos definir las siguientes variables y temporizador, las cuales las declararemos en la sección private

Variables para gestión disparo

La variable CanShot(1), la usaremos para indicar si se puede disparar. En el caso, por ejemplo, de que ya haya dos espadas en el escenario, esta variable se valdrá falso.

La variable, TimerShot(2), es un temporizador, el cual lo usaremos para temporizar el lanzamiento. Para que el jugador no pulse la tecla de disparo y se disparen múltiples espadas.

Cuando lanzamos una espada, realizamos diversas operaciones, crear el sprite, etc. Para saber que estamos haciendo “la preparación” lo indicamos con la variable Shotting(3).

La variable NumeroDisparos(4), indica cuantas espadas están actualmente en el escenario.

Por último, el procedimiento OnTimerShot(5) es un procedimiento que se será llamado cada vez que se cumpla el tiempo que especificamos en el temporizador. No es necesario que lo escribas ahora esta línea, ya que cuando inicialicemos el temporizador, Lazarus lo creará por nosotros

En procedimiento Onstart, debemos inicializar todas estas variables, y preparar el temporizador

El siguiente código se encarga de ello:

Lo primero es crear el temporizador, que es un objeto de tipo TcastleTimer.

Le asignamos el evento OnTimer, el cual se ejecutará cada vez que el temporizador alcance el valor establecido. Recuerda que tras escribir la línea, su pulsas Ctrl+shift+C, lazarus creará el procedimiento asociado, así como su declaración.

Asignamos a la propiedad InvervalSeconds, el valor 1 que será el intervalo en segundos de nuestro temporizador.

Asignamos las variables booleanas a su estado inicial. Enviamos el temporizador “al fondo” para “congelarlo”. Por último inicializamos la variable NumeroDisparos a cero.

Disparando

Con estas líneas , al iniciar el juego, tendremos todo preparado para empezar a disparar

El siguiente paso es modificar la función FireWeapon

Modificamos la instrucción IF, de manera que tenga en cuenta la variable CanShot sea igual a TRUE y NúmeroDisparos sea menor igual a 2. Además llamamos al procedimiento StartTimerShot, el cual se encarga de iniciar el temporizador.

Crea el procedimiento StartTimeShot, en la sección Private, y escribe el siguiente código dentro de ella.

Este procedimiento cambia la variable CanShot a TRUE y trae “al frente” el temporizador, con lo cual empieza a contar.

En el procedimiento Update, gestionaremos si la función FireWeapon devuelve TRUE. En tal caso debemos lanzar una espada.

Usaremos la variable, declarada en la sección Private, shotting la cual nos indicará si estamos lanzado la espada. En el caso que no sea así, reiniciamos el temporizador para asegurar que empieza a contar desde cero. Ponemos la variable Shotting a TRUE, incrementamos el contador de número de disparos. Y dependiendo hacía donde esté mirando el personaje, creamos un vector de dirección paralelo al eje X. El sentido de este vector está indicado por el signo de su valor en X.

Llamamos al procedimiento Shot (ahora entro en detalles sobre este procedimiento), ya por último indicamos que no se puede disparar cambiando a FALSE y cambiamos la variable Shotting a FALSE para indicar que hemos terminado el proceso de disparo.

La variable CanShot cambiará a TRUE, cuando haya pasado el tiempo que establecimos en el temporizador. Para ello en el evento OnTimerShot que creamos antes, debemos escribir el siguiente código.

En este procedimiento lo primero en “enviar” el temporizador a dormir. Y cambiamos la variable CanShot a True.

Clase TWeapon

Este shot se encarga de realizar el disparo pero depende de la clase Tweapon, la cual será el arma que disparamos y se encargará de desplazarla y calcular cuando debe desaparecer.

La clase Tweapon, la debes declarar al principio de la unidad, justo debajo de dónde declaraste la clase TlevelBonus.

Esta clase desciende, o es hija, de TcastleTransform. Declaramos un constructor, con el argumento Reintroduce, así podemos usar el método Create que ha sido escondido por la clase padre, añadiendo algunos argumentos más. En este método recibe, además del propietario (Aowner), que es obligatorio, un parámetro de tipo TcastleScene, que será nuestra arma.

Por otra parte declaramos el procedimiento Update, el cual será llamada cada vez que se debe actualizar nuestra arma. Este método es llamado automáticamente con el motor gráfico, al ser un objeto de desciende de TcastleTransform hereda esta carácteristica.

La propiedad Rbody, es de tipo TcastleRigiBody, la cual contendrá un RigiiBody, que es el objeto que gestionará las colisiones. Al igual que se lo hemos creado desde el editor de CGE, lo crearemos desde código.

La propiedad MaxDistance, la usaremos para almacenar la distancia máxima que puede recorrer el arma, desde el punto de inicio, que se guarda en la propiedad StartPoint. Al ser un punto en 2D, esta será un vector de tipo TVector2 .

Constructor

Veamos el código del constructor

Observa el código y sus comentarios. Empezamos añadiendo el arma, que hemos recibido por el parámetro WeaponSpriteScene, a la escena. Lo hacemos visible y lo situamos en el origen de coordenadas.

Después creamos el objeto TcastleRigiBody, ajustamos sus propiedades a un entorno 2D, su propiedad Dinamic la ponemos a True, para que su desplazamiento se gestionado por el motor de físicas. La detección de colisión (CollisionDectection) a continuo, la velocidad a cero, en el mismo plano del protagonista, e indicamos que no le afecte la gravedad.

Ya por último, creamos el volumen de colisión o collider.

Con todo esto listo, los añadimos a “comportamientos” de nuestro objeto.

Update

Por otra parte, tenemos el procedimiento Update


En este procedimiento, comprobaremos si la posición actual, restada a la posición de inicio es mayor que FmaxDistance. En tal caso cambiamos las propiedades Visible y Exists a False. Y cambiando la variable RemoveMe, que hemos recibido como parámetro, al valor rtRemoveAndFree, indicamos al motor gráfico que debe borrar este objeto. El motivo de cambiar las variables Visible y Exists a False, es para que mientras no se destruye, no se visible para jugador y al “no existir” no se tendrá en cuenta para futuras colisiones

Procedimiento Shot.

En este procedimiento crearemos un objeto Tweapon, y lo inicializamos con los datos que necesitamos.

Dependiendo de la dirección que indica el parámetro Dirección, crearemos el objeto con un sprite u otro y asignándole e un padre, en este caso es el que hemos pasado por el parámetro WeaponOwner.

Indicamos el punto de inicio, y la distancia máxima que será la mitad de ancho de la cámara. Cuando se alcanza esta distancia estamos fuera de la vista de la cámara.

Ajustamos su posición al origen. Cuando creamos el objeto este estaba en el origen de coordenadas. Ahora lo ponemos dónde nos interesa.

Ya solo nos queda asignar una velocidad, multiplicada por la dirección, así el arma irá hacía un lado u otro.

Ya solo nos queda añadir nuestra arma, al ViewPort, para que el motor gráfico se encargue de gestionarlo.


Actualizar el número de disparos

Para saber en cualquier momento el número de espadas que hay en cada momento, podemos buscar el número de objetos de tipo Tweapon que hay en el Viewport. Para ello vamos a crear un un procedimiento llamado UpdateNumberWeapons el cual lo llamaremos en el procedimiento FireWeapon.

El procedimiento UpdateNumberWeapons recorrerá los elemento que hay en Viewport y obtendrá el total de los que sean de tipo Tweapon actualizando la variable NumeroDisparos.


Modificaremos el procedimiento FireWeapon para que llame a este procedimiento, y dependiendo del valor de la variable NumeroDisparos, devolverá True o False.

Tienes todo el código completo en el Github.

Saludos

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio esta protegido por reCAPTCHA y laPolítica de privacidady losTérminos del servicio de Googlese aplican.

El periodo de verificación de reCAPTCHA ha caducado. Por favor, recarga la página.