Programando Breakout, Arkanoid, Arkanando

Publicado el Martes, 24 de diciembre de 2024

Volví a la programación con DragonRuby y estoy desarrollando un juego al estilo Breakout o Arkanoid. Parte de la inspiración vino de estar jugando y disfrutando increíblemente el juego/documental interactivo Atari 50: The Anniversary Celebration. Es excelente, lo recomiendo. Espero poder conseguir en formato físico otras de las ediciones de este estilo de Digital Eclipse como Llamasoft: The Jeff Minter Story y Tetris Forever.

Volviendo al desarrollo, esta vez decidí ir documentando tipo diario los pasos que iba siguiendo y el proceso mental que me lleva a implementar cada parte del juego. Me sirve en parte para volver atrás e ir viendo cómo pienso y llego a distintas implementaciones. Pero lo mejor de escribir esto es que al intentar explicarlo no sólo lo entiendo mejor, sino que hago un proceso de rubber ducking conmigo mismo y termino corrigiendo cosas que no había pensado tanto como debería.

Lo primero que hice fue agregar la navecita y que se moviera sólo en el eje de la x para los costados. Esto en DragonRuby es casi trivial, de hecho podemos modificar el código que viene de ejemplo y reemplazar el logo de DragonRuby con un sprite hecho en GIMP y limitar el movimiento al eje de las x. Lo que va quedando por refinar y estudiar más adelante es el tema de la aceleración, si varía con ítems, experiencia o qué. Problema para Fernando del futuro.

Después agregué la pelota, que fue el primer desafío matemático . Acá mi cerebro hizo eso que hace a veces de decirme "esto se hace así", y yo le hago caso y de alguna manera funciona. Mi cerebro no me dice enseguida por qué funciona, pero si me pongo a pensarlo un rato y tratar de entenderlo, lo termino entendiendo. Pero no me resulta tan fácil como a mi cerebro.

Lo que hice fue que la pelota apareciera en un valor de y (posición vertical en la pantalla) determinado y fijo, y un valor aleatorio para x. Y acá es donde la magia matemática vino de alguna parte de mi cerebro que entiende estas cosas, y le agregué "dirección x" y "dirección y" con valor -1. Esto es para que la pelota se mueva en la recta y = x en principio, y los signos + y - definen la dirección. Escribiendo esto me di cuenta que el valor de y tenía que ser -1, pero el de x no necesariamente. Así que lo cambié para que elija aleatoriamente entre esos dos. Más adelante voy a tener que refinar un poco para que vaya en una dirección u otra dependiendo cuan cerca aparezca de las paredes a la derecha e izquierda de la pantalla.

Cuando la dirección x es positiva, la pelota se está moviendo a la derecha, negativa a la izquierda. Lo mismo con y, positiva es para arriba, negativa es para abajo. Cuando y llega a 0, perdimos la partida. Cuando llega a la altura de la pantalla (720 en DragonRuby), la dirección y cambia a negativo porque tenemos que hacerla rebotar. Así que siempre es negativa hasta que la tocamos con la paleta o navecita, y ahí cambia a positivo.

Algo genial de DragonRuby, para detectar la colisión entre la paleta o navecita y la pelota, hay una función intersect_rect? que nos hace la vida extremadamente fácil. Hacemos ball.intersect_rect?(spaceship) y nos dice si hay colisión. Ahí cambio la dirección de y de -1  a 1 y la pelota empieza a ir para arriba. No tengo que calcular la colisión a mano.

Hasta acá tenía menos de 70 líneas de código, y eso que en DragonRuby podemos usar mucho hashes para declarar sprites, sólidos y demás. Y yo los escribo multilínea. Las líneas de código no dicen mucho, pero me sigue impresionando lo fácil que fue llegar hasta acá y el poco código que tuve que escribir. DragonRuby es genial.

Después de esto me puse a trabajar en que la trayectoria de la pelota variara de ángulo según qué parte de la navecita la golpeara. En principio no tenía ni idea cómo iba a manipular el ángulo si ni siquiera tengo el valor del ángulo en ningún lado. Pero las matemáticas (o álgebra!?) vienen al rescate. La pelota está siguiendo la trayectoria y = x. Esto hace que se mueva en línea recta siempre en un ángulo de 45°. Así que para variar el ángulo, tenía que variar el valor de x en función de y (¿o viceversa? Hace mucho que terminé la secundaria...). Así que definiendo valores decimales para x e y, varío los ángulos.

Lo otro fue determinar en qué parte de la paleta o navecita hace la colisión la pelota. En principio supuse que habría alguna función auxiliar relacionada a intersect_rect? que me diría en qué coordenadas está la intersección. Pero bastante rápido me di cuenta que no importaba, porque siempre tengo las coordenadas de los dos objectos. Así que escribí una función con una variable que es el valor x de la pelota menos el valor x de la paleta, y eso me da la posición en la paleta de la colisión. Tengo que llamarla cuando hay colisión, y ahí determinar la trayectoria. La idea es que cuando le pegamos con los extremos de la paleta, el ángulo sea más agudo.

Acá estoy seguro que hay un montón de matemáticas que me ayudarían a tener un control mucho más granular de la trayectoria. Pero en principio lo dejé como un ángulo más agudo genérico cuando pega en los extremos de la paleta, y más neutral en el medio. Algo para ir refinando más adelante.

Hasta acá tengo la pelota y la paleta interactuando más o menos como quería:

Me falta agregar toda la lógica de bloques que desaparezcan cuando la pelota los toca, y le modifique la trayectoria también. Le iré agregando más cosas con el tiempo, y con suerte quede con un proyecto terminado. El nombre clave del juego (y probablemente nombre final) es "Arkanando", genial nombre ideado por mi amigo Oye. Viene al pelo porque lo que más jugué de este estilo fue Arkanoid de NES en mi Family 76 en 1. Oye también fue el que me dió el nombre para Fertris, ¡gracias Oye!

Agrego una foto de los primeros apuntes del juego en mi cuaderno de "desarrollo de videojuegos", pensando en el tema de la trayectoria...

Arkanando

Mis apuntes determinando los ángulos y la posición de la pelota en la paleta.

No hay comentarios en este post

Feed de comentarios

Dejar un comentario

Toasty!