Zeek The Geek en ReactJS - Tercera Parte
Tags: react, pwa, games, css3
Published: 2021-01-17 01:14:23

---
title: Zeek The Geek en ReactJS - Tercera Parte
published: true
description: Recreando el clásico juego Zeek the Geek en ReactJS
tags: reactjs, pwa, games, css3
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/2hlpqyuzoa35gc2f6m47.png
---

En la [primera parte](https://dev.to/jorger/zeek-the-geek-en-reactjs-primera-parte-1ch4) de esta serie de artículos, hablamos de la historia del juego original, la motivación del desarrollo de esta nueva versión, sus opciones así como el stack de tecnología utilizada.

En la [segunda parte](https://dev.to/jorger/zeek-the-geek-en-reactjs-segunda-parte-499n) se mostró cada uno de los bloques que componen el juego, así como la interacción que pueden tener éstos con el personaje.

* **URL del juego:** https://zeek.jorge-rubiano.vercel.app/

En esta tercera parte me gustaría hablar acerca de los retos técnicos del juego.

# Movimiento del personaje.

El personaje puede moverse de tres formas como son:

1. Haciendo uso del teclado, a través de las teclas de movimiento.
2. A través del control integrado en el juego.
3. Indicando el punto de destino al cual deberá dirigirse Zeek. 

Los tres tipos pueden ser usados en desktop, mientras en dispositivos móviles se puede hacer uso de las opciones 2 y 3.

{% gist https://gist.github.com/Jorger/9e42ab6c1d0544e32e7e8a480f12b791 %}

Para mover el personaje y por consiguiente a los bloques que Zeek puede mover, se hizo uso de la librería conocida como [react-spring](https://www.react-spring.io/), está librería permite indicar el punto de origen del movimiento así como su punto de destino, una vez se ha completado la animación, se entrega un evento.

Una vez se tiene este evento se puede evaluar el entorno del personaje, esto también aplica a elementos como los dinos, es decir, para los dinos se utilizó la misma lógica, con la diferencia que el movimiento es indicado por el sistema y no por el usuario.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ayef59afh86mmywkan7q.gif)

Uno de los retos en el movimiento del personaje fue validar si el personaje se podría mover o no, por lo que se debía validar el tipo de bloque que existía antes de moverse, pero si el bloque que existía a la posición a la que se quería mover el personaje se podía mover, se debía validar si la posición de ese elemento estaría libre.

{% codesandbox naughty-agnesi-19yt6 %}

Para garantizar que el personaje y el elemento que se esté moviendo finalizan al mismo tiempo, se validó que no se acepta eventos de movimiento antes que finalice el movimiento, esto permitió que sí se hace un cambio de movimiento rápido, Zeek sólo responderá una vez que haya finalizado de moverse.

# Movimiento Zeek indicando el punto de destino.

Como lo indicaba anteriormente uno de los métodos para mover a Zeek, es indicando su punto de destino, para ello se busca la ruta más corta **(más no la más segura)** a seguir, para lograr este objetivo, se hizo uso de la librería [pathfinding](https://www.npmjs.com/package/pathfinding), está librería utiliza una gran variedad de [algoritmos](https://www.npmjs.com/package/pathfinding) para lograrlo, para el juego hice uso de [A* Finder](http://coecsl.ece.illinois.edu/ge423/spring06/Apath/design.htm).

La librería en este caso solicita una [matriz](https://github.com/qiao/PathFinding.js#basic-usage), en la cual se indica que posiciones son disponibles/vacías y cuáles no, una vez realizado este proceso, la librería entregará un array de posiciones indicando la ruta más corta encontrada.

Un ejemplo de ello es el siguiente escenario, a pesar de tener varios caminos, se ha ido por la ruta más corta encontrada por A* Finder.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/waf083mhq2ot83z96gv3.gif)

Gráficamente está búsqueda se puede visualizar de esta forma.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/816uus5ac9jigi8upvzf.gif)

Se puede probar los demás algoritmos de esta librería en esta url: http://qiao.github.io/PathFinding.js/visual/

Como lo comentaba la librería espera una matriz para así entregar la ruta más óptima, más no la más segura, ya que no se valida si en la ruta encontrada existan peligros que puedan eliminar a zeek, aún así hay validaciones que buscan minimizar este peligro, por ejemplo no se puede indicar que el punto de destino sea una flor púrpura o azul.

Una vez que se tiene la ruta se debe indicarle a Zeek los movimientos, como tal zeek sólo recibe direcciones (right, left, down, up), por lo que se debe hacer una conversión de las coordenadas a direcciones, esta acción se realizó a través de la siguiente función.

{% gist https://gist.github.com/Jorger/f5f6a82a4fd165d0b7b3f9be79c89856 %}

Es posible cambiar la dirección del personaje en cualquier momento, es decir, si se le ha indicado la ruta al personaje y se presiona alguna tecla del teclado, esta ruta se cancelará aceptando la última entrada dada.

# Creación de muros

Como tal el juego cuenta con una gran variedad de bloques que son interactivos, bien sea por que desaparecen al contacto con otro bloque (flores amarillas, tesoros, etc) o que el personaje puede mover en el escenario (dinamita, manzanas, cristales mágicos, etc), pero los muros como tal son elementos estáticos, cada elemento en el escenario es un componente como tal por lo que se debe renderizar, en el caso de los muros se debe igualmente renderizar, pero en este caso no hacen acción alguna, más que bloquear.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/3bipdh3hesp3rjjn7con.gif)

Por ello los muros no se renderizan, sino que se crea una imagen, para ello existe un función que recibe el escenario y busca en éste los elementos de tipo muro, a partir de esto crean una imagen haciendo uso de canvas.

{% gist https://gist.github.com/Jorger/777eb727982a541e9752b8b765e731c4 %}

Esto permitió liberar el render del juego de elementos innecesarios, ya que los muros se renderizan como un sólo background, aún así dentro del estado si se valida si existe un muro en una posición, más no se renderizan.

# Animaciones de los bloques.

Como lo había indicado anteriormente los movimientos del personaje y de otros elementos del escenario, se realizaron a través de react-spring, pero para las demás animaciones, como pasos, explosiones y demás se hizo uso de las animaciones de CSS.

{% codesandbox laughing-bose-600nj %}

La animación proviene de un sprite que contiene todos los movimientos necesarios para el juego.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/85520ez00y8hkzbfr58n.png)

Por ejemplo para indicar que el personaje estaba caminando hacía la derecha, se pasaba una clase la cual iniciaba la animación de los pasos, de la misma manera si se deseaba indicar si el personaje estaba durmiendo.

{% gist https://gist.github.com/Jorger/13a99e35525a4d85a6aa42a4385719e5 %}

Como se puede apreciar se hizo uso de variables en CSS, las cuales cambian dinámicamente dependiendo del tipo de estado que tenga el personaje.

Haciendo uso de animaciones en CSS, ayudó a liberar al render del juego.


# Temporizador de bloques.

En el juego existen varios bloques que una vez activados tienen un tiempo para realizar una acción, por ejemplo:

* Al activar una dinamita.
* Al colisionar dos cristales mágicos.
* Al comer una manzana la flor púrpura.
* Al digerir una manzana.

{% gist https://gist.github.com/Jorger/75aa3d6697cb8c1683e38102ff916489 %}

Para manejar estos tiempos, se hizo uso de un custom hook, denominado [useInterval](https://overreacted.io/making-setinterval-declarative-with-react-hooks/), este permitió indicar los tiempos que cada acción debían esperar, este hook sólo se activa sólo cuando se requiere una animación, es decir, si no existe algún elemento que requiera un temporizador useInterval no estará en ejecución.

# Validación explosión dinamita.

El bloque de tipo dinamita, es un bloque interesante, ya que puede eliminar una gran variedad de otros bloques, incluido a Zeek, pero igualmente puede activar otra dinamita, existen escenarios donde esta característica le entrega un tiempo límite para terminar el escenario.

{% gist https://gist.github.com/Jorger/fe8e3a2bec325a6ca9990ea1925045ba %}

Pero para que la dinamita sepa que debe eliminar una vez explote, debe conocer su entorno, además debe estar en reposo, es decir si el personaje está moviendo la dinamita y el tiempo de explosión ha acabado, sólo cuando la animación de movimiento haya acabado explotará y por consiguiente eliminará a Zeek.

# Validación del Láser.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/bgbnxuoy2ck70hhtuh9p.gif)

El láser es un elemento estático, que sólo puede ser eliminado por una dinamita, el láser siempre estará observando a Zeek, si éste se encuentra en su vista lo eliminará, si existe algún elemento entre Zeek y el láser no podrá eliminarlo, para ello desde el editor fue necesario realizar esa acción

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/x47q9pth3jfrilpi2pvj.gif)

En el juego se tuvo que realizar la misma acción, en este caso revisar si la nueva posición del personaje estaba a la "vista" del láser y si no había algún elemento que lo bloqueará, fue necesario hacer una validación especial cuando el elemento de bloqueo es un dino, por la misma naturaleza del mismo, es decir a diferencia de los demás bloques, este está en constante movimiento, por lo que se debía validar no sólo en que posición estaba sino además en qué posición estaría después.

{% gist https://gist.github.com/Jorger/b8e1361eb0c790f8b79d879379c4c355 %}


# Validación movimiento Dino (Piclasops)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/qejgmo0rw5zwws2y9hit.gif)

A diferencia de los demás bloques el Dino, se mueve automáticamente, además de existir la posibilidad de existir varios dinos al mismo tiempo, era necesario validar que un dino no quedará en la misma posición de otro, por lo que se válido que una vez un dino haya seleccionado su próxima posición, los demás dinos tomarían esa posición como bloqueante

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/dk7g9uu1ljkiw9z0vqrq.gif)

Otra validación fue relacionada a los elementos que mueve Zeek, un dino puede ser bloqueado y pasar a un estado estático, no era posible establecer la lógica de establecer una posición bloqueante a un movimiento futuro de un dino, si el elemento que iba a tomar esa posición era un bloque que estaba moviendo Zeek (más no Zeek, por que en este caso moriría), por lo cual fue necesario saber si un bloque futuro estaría en esa posición.

{% gist https://gist.github.com/Jorger/0809ee56dc89722d647754a785bd60a4 %}

______

En esta tercera entrega quería compartir algunos retos técnicos en el desarrollo del juego, como tal es un juego que tiene muchas "partes movibles", fue desafiantes ponerlas en conjunto y que funcionarán como un todo, la validación de movimiento así como las acciones de bloques como los láseres representó un gran reto.

En la [cuarta y última](https://dev.to/jorger/zeek-the-geek-en-reactjs-cuarta-parte-26bm) entrega hablaremos acerca del ambiente de desarrollo utilizado y otras características que tiene el juego.