Kabosu - Creando cosas
Publicado: 2024-05-06 (actualizado 2024-10-05)
Etiquetas: Juegos, Proyectos, Reto de la Paella
Actualizado el 2024-10-05 para corregir algunos errores ortográficos.
En el artículo anterior explicaba los problemas que tuve con la compilación de Rogule y cómo los solucioné. Aquí voy a contar el proceso posterior de modificar el juego para añadirle paellas que también fue más difícil de lo que pensaba.
Mi siguiente objetivo era averiguar porqué algunos cambios que hacía en el código funcionaban (como cambiar el nombre del juego en sí) y otros no (cambiar el sprite del elfo🧝 por un ninja🥷).
Mi primera hipótesis era que no estaba ejecutando mi código si no algo que estaba en main.js
o shared.js
que tenían casi un mega de JavaScript minimizado totalmente ininteligible. Obviamente esto no era posible porque esos ficheros se regeneran cada vez que se compila Rogule. Llené el código de instrucciones log
y me di cuenta de algo curioso: no se ejecutaba ninguna de las líneas que puse en generator.cljs
y de ui.cljs
solo se mostraban unos pocos mensajes. En cuanto se iniciaba la carga del nivel era como si mi código dejase de existir y se volvía al juego original.
Probé a borrar la caché del navegador, reiniciar el servidor, inspeccionar las conexiones que hacía Firefox al cargar el nivel y muchas cosas más pero no encontraba la causa.
Al final, probé algo que tenía que haber probado desde el principio: cargar el juego desde otro navegador (de hecho, abrí la página desde otro ordenador). Al hacerlo vi al ninja en pantalla y la inmensa cantidad de mensajes de log que había añadido. ¡Un pequeño paso adelante! En el navegador que estaba usando para el desarrollo probé a cargar el juego en una pestaña de incógnito y también salía el ninja. ¿Qué ocurría?
Estaba claro que algo se quedaba guardado en el navegador la primera vez que cargabas el juego y se quedaba ahí aunque cambiaras el código del juego. Yo cargué la página nada más compilar cuando aún estaba el elfo y no había puesto los mensajes de log. Gracias a las herramientas de desarrollador web de Firefox (pulsando F12 en cualquier página) descubrí que Rogule parece almacenar todo el estado del juego incluyendo la lógica en el almacenamiento interno del navegador. Entiendo que es para que si te vas de la página y vuelves a entrar continúe en el punto que lo habías dejado. Además de controlar que solo se pueda jugar una vez al día.
Se guardaba con la clave
["~#'","~:game-state"]
y el contenido es un vector con un montón de símbolos. No me puse a investigar qué era. Simplemente lo borré todo.
Ahora ya podía modificar el código, recompilar y ver mis cambios sin problemas. Solo tenía que borrar el almacenamiento local de la página en el navegador cada vez. Se tarda apenas unos segundos pero requiere unos pocos clicks así que al final lo que hacía era cambiar la URL que usaba para acceder al juego para ir más rápido. El almacenamiento local se guarda por dominio o IP y todas las IPs que empiezan por 127 apuntan al ordenador actual así que simplemente cada vez que quería probar algún cambio sumaba 1...
127.0.0.1:8000/game
127.0.0.2:8000/game
127.0.0.3:8000/game
...
127.0.0.28:8000/game
Por fin me puse a hacer cambios en el juego a diestro y siniestro.
Lo primero fue cambiar los iconos de la comida por paellas. El emoji de paella🥘 se llama realmente "shallow pan of food". Cambié todas las comidas por paellas.
(def forage-items
[{:name "chestnut"
:sprite (load-sprite :shallow-pan-of-food)
:fns {:encounter :add-item-to-inventory}
:value 1}
{:name "mushroom"
:sprite (load-sprite :shallow-pan-of-food)
:fns {:encounter :add-item-to-inventory}
:value 2}
{:name "gem-stone"
:sprite (load-sprite :shallow-pan-of-food)
:fns {:encounter :add-item-to-inventory}
:value 8}
Dejé los nombres originales porque pensé que cambiarlos rompería muchas cosas.
El juego también tiene una poción de recuperar salud que utiliza el emoji "tumbler glass"🥃. No quise repetir la paella en este caso para poder diferenciarla de la comida normal así que lo cambié por un emoji de vaso de leche🥛. En la ayuda explico que realmente es una horchata.
{:name "health"
:sprite (load-sprite :glass-of-milk)
:modal-sprites [(load-sprite :green-heart)]
:fns {:encounter :increase-hp}
:value 2}
Con estos pequeños cambios ya estaba contento pero me puse a pensar qué más podría cambiar y que no costase mucho de programar.
Rogule está limitado a una partida por día. Esto se consigue usando la fecha como semilla para el generador de número aleatorios y solo permitiendo generar un nivel si la semilla actual es distinta a la anterior (es decir, se ha cambiado de día).
(defn reset-game! [old-seed seed]
(seedrandom (str "Rogule-" seed) #js {:global true})
(when (not= old-seed seed)
Quitando la instrucción seedrandom
evité que utilizase la fecha como semilla y cambiando (not= old-seed seed)
por un simple true
conseguí que cada vez que recargaba la página se generase una nueva mazmorra. Vino muy bien durante el desarrollo.
Al terminar una partida diaria de Rogule, el juego te muestra el resultado y te permite compartirlo en redes sociales. Cambié ese sección para quitar los botones de compartir, donar, etc. No quería que la gente fuera publicando cosas de un Rogule no oficial. De paso traduje al castellano la mayor parte de los textos del juego.
[:p "Partidas: " plays]
[:p "Victorias: " (-> (:ascended stats) (/ plays) (* 100) int) "%"]
[:p (str "Racha actual: " (:streak stats))]
[:p (str "Racha máxima: " (:max-streak stats))]])
Ya había dado el juego por concluido pero me acordé del Super 3D Noah’s Ark, un juego de temática cristiana que simplemente es el Wolfenstein 3D con los gráficos cambiados. En vez de estar en un castillo estamos en el Arca de Noé y los enemigos no son nazis a los que hay que disparar si no animales nerviosos por el diluvio a los que hay que tranquilizar disparándoles comida.
Decidí hacer lo mismo con Rogule: renombré el juego a El Arca de Rogulé y cambié todos los enemigos por animales como cabras, cerdos, elefantes, etc. Las armas pasaron a ser jeringuillas💉 con tranquilizantes. Al vencer a un enemigo en vez de una calavera (el emoji llamado "skull and bones"☠️) utilicé el de dormir💤. Para terminar el nivel en vez de llegar a una puerta torii⛩️ sería una cama🛏️.
Las instrucciones del juego fueron actualizadas también.
[:h2 "El Arca de Rogulé"]
[:p "Los animales del arca están nerviosos por el diluvio. Ayúdales a dormir."]
[:p "Usa las flechas para moverte. Pulsa " [:button.key "."] " para descansar."]
[:p "Muévete sobre los objetos y " (tile-mem (load-sprite :goat)) " animales para interactuar."]
[:p "El número de cada animal es el daño que te hacen cuando les intentas dormir."]
[:p "Su barra de sueño aparece cuando les intentas dormir."]
[:p "Recoge todas las " (tile-mem (load-sprite :shallow-pan-of-food)) " que se han caído."]
[:p "Los escudos " (tile-mem (load-sprite :shield)) " te protegen."]
[:p "Los tranquilizantes " (tile-mem (load-sprite :syringe)) " te ayudan a calmar a los animales."]
[:p "Llega a la " (tile-mem (load-sprite :bed) "shrine") " para terminar."]]
Con el cambio a El Arca de Rogulé di por terminado el proyecto aunque hay cosas que se podrían mejorar como por ejemplo:
Cambiar los nombres de los animales y objetos. Dejé los que tenía el juego original por miedo a romper cosas y quizá los podría haber actualizado. Esos nombres solo aparecen si estás jugando con ratón y dejas el cursor encima de un emoji así que no le di demasiada importancia.
{:sprite (load-sprite :goat)
:activation 10
:stats {:xp 8 :hp [15 15]}
:name "the dragon"}
Una modificación interesante que se me ocurrió fue obligar a tranquilizar a todos los animales antes de poder ir a la cama y terminar el nivel. No sería difícil pero al final no lo implementé por no ponerme a aprender cómo funciona el lenguaje Clojure. Me guardo la idea para un futuro.
También estaría bien quitar la recuperación de vida. Si te mueves durante unos 100 pasos recuperas una unidad de vida y esto se puede aprovechar para recuperar toda la energía simplemente moviéndote entre 2 casillas. En mi opinión abusar de esto hace el juego excesivamente fácil y creo que habría que eliminarlo.
Las dos cosas más importantes que he aprendido o recordado durante este ejercicio han sido:
Como desarrollador conviene que el proceso de compilación sea lo más rápido posible. Ahorra mucho tiempo a largo plazo.
Para "reiniciar" completamente una aplicación web no solo hace falta eliminar cookies y caché sino que también hay que borrar lo que haya en el almacenamiento local del navegador.
Quizá otra cosa que he aprendido es que el lenguaje Clojure no parece excesivamente difícil si se tienen unas pequeñas nociones de Lisp o Scheme.