Sprites por Hardware – Tutorial 2

Este es un extracto del artículo originariamente publicado en mi web lacavernainformatica.com

Bueno seguro que si ya habéis visto y practicado con la primera entrega, tendréis muchas ganas de seguir avanzando en la Programación del NextBasic. Y es que todavía tenemos muchos más comandos y operaciones que podemos realizar sobre nuestros Sprites.

Sobre todo en este tutorial de Programación de Videojuegos en NextBasic para el Zx Spectrum Next, vamos a ver dos facilidades que nos brinda este nuevo lenguajes.

  • Movimiento automatizado de Sprites.
  • Agrupación de Sprites.

Y os preguntaréis, ¿Y en que nos puede beneficiar el hacer uso de estas características?

Pues vayamos por pasos. El movimiento automatizado nos puede resultar sumamente útil por ejemplo para realizar los movimientos de nuestro personaje, sin necesidad de estar controlando continuamente su posición, como hacíamos en el The Hunting Octopus. O por ejemplo, y como es el caso del juego Darts sobre el que vamos a basar esta explicación, nos permite lanzar un Sprite, en este caso un dardo, y olvidarnos relativamente de él.

 

Darts Basic Videogame
Menú de inicio del juego Darts

 

Otra ventaja, es que al realizarse mediante hardware, no cargamos nuestra CPU con cálculos de posiciones y demás tareas, permitiendo liberar bastante al Zx Spectrum Next de dichos procesos.

 

Y ahora me diréis, muy bien yo le digo que vaya hacia la derecha, pero no controlo exactamente en que posición está, porque no llevo un control de la misma.

Pues para eso podemos hacer uso de dos comandos que veremos en detalle un poco mas adelante, que nos permiten dos cosas. Por un lado podemos preguntar en cualquier momento la posición de un Sprite en particular y por otro lado, podemos saber cuando dos o más Sprites han tenido una colisión. Todo esto repito, mediante Hardware.

 

Darts shot Basic VideoGame
Pantalla de juego de Darts

 

¿Qué os parece? ¿Interesante, verdad?

Pues la otra características que hemos usado en el videojuego Darts, es la de agrupación de Sprites. Ya que nuestra Diana está conformada por la unión de tres de ellos, pero con una ventaja. Una vez unidos, se comportan como uno solo, con lo que los comandos de colisiones, movimientos y posición, los podemos aplicar de manera grupal, con la simplificación que ello conlleva.

Seguro que ya tenéis ganas de saber mas en profundidad como hemos utilizado todas estas nuevas funciones.

¡Pues no esperéis más, pinchad en el vídeo de abajo y descubrirlo!

 

Bueno espero que no os hayáis perdido el vídeo, ahora vamos a analizar las características nuevas una por una para que nos queden las cosas un poco más claras y podáis avanzar en la Programación de Videojuegos en Basic para el Zx Spectrum Next

Si queréis descargados el código fuente completo, así como los Sprites, etc…, ya sabéis que en mi página de GitHub lo podéis descargar todo.

El comando para definir que un Sprite se va a mover mediante movimiento predefinido lo podemos ver aquí abajo.

SPRITE CONTINUE 0, 20 TO 201 STEP dardovel RUN ,128,0 TO 2

En esta sentencia definimos que el Sprite que hemos llamado 0 en nuestro programa se va a desplazar en el eje X desde la posición 20 hasta la 201 con incrementos definidos en la variable dardovel, aquí podíamos haber puesto un número simplemente, y después le indicamos con la sentencia RUN que se va a desplazar inmediatamente. La posición Y la dejamos fija a 128, porque en este caso nos interesa, y luego lo vinculamos a los Sprites reales del 0 hasta el 2.

 

Los tres Sprites nos permiten realizar la animación del Dardo en vuelo

Esto último hará que en cada iteración vaya mostrando un Sprite distinto, en este caso para simular el vuelo del dardo.

Hay otra puntualización que hacer sobre el tema del uso de movimientos automáticos. Necesitamos usar una sentencia para indicarle al Next cuando realizar dicho movimiento.

¿Y diréis, y eso para qué? Bueno, supongamos que tenemos varios Sprites definidos con movimientos automáticos, como es el caso de Darts, es necesario que se muevan de una manera controlada por nosotros para que todos vayan a la par. Si arrancara nada más definirlo, sería un lío controlar la sincronización de todos, cada uno iría a su bola, jajajaja.

Bueno el comando que nos permite realizar esto es:

550 REM damos la orden de moverse a los sprites de tipo automatico
560 SPRITE MOVE

¿Todo claro, verdad?

Pues ahora trataremos los Sprites agrupados. Como hemos dicho, podemos agrupar varios Sprites, haciendo de uno el principal y de los otros sus esclavos (Esta palabra se quiere eliminar de la informática por sus connotaciones…)

Para ello veamos primero los Sprites que vamos a unir.

 

Sprites que conforman la Diana

Nosotros hemos elegido como padre, el Sprite superior y los restantes como su hijos. Para ello tan solo hemos necesitado usar la siguiente sentencia:

350 REM agrupacion de sprites. Refenciamos al sprite 3, el 4 y el 5, haciendo uso del -, y de esta forma todo se agrupa al nivel del 3
360 SPRITE 3,200,0,3,1
370 SPRITE -4,,+16,4,1
380 SPRITE -5,,+32,5,1

Como veis, al usar signos negativos le indicamos al Next que el Sprite 4 y 5, que en este caso los llamamos igual que los Sprites reales de la memoria, son los esclavos del Sprite 3.

De esta forma, cuando realizamos el movimiento automatizado, hacemos solo referencia ya al tercer Sprite.

510 REM movemos automaticaente la agrupacion de sprites de la diana referenciando unicamente al sprite 3
520 SPRITE CONTINUE 3,200,0 TO 200 STEP dianavel RUN ,3

Y además, cuando realizamos el control de colisiones entre la diana y el dardo, cosa que todavía no habíamos explicado, lo hacemos solo referenciando al Sprite 3.

Veamos como podemos revisar las colisiones entre los distintos Sprites con el siguiente código:

530 REM aqui usamos la gestion de colisiones entre el dardo y el grupo de sprite de la diana. Tambien nos quedamos con la posicion de colision en la diana para calcular los puntos que hay que asignar
540 LET col= % SPRITE OVER (0,3,4,4): IF col > 0 THEN LET pos=% SPRITE AT (3,1): GO SUB %680: SPRITE CONTINUE 0, STOP : GO TO %210

Y el comando en cuestión que nos interesa:

% SPRITE OVER (0,3,4,4)

En este caso estamos diciendo, que revise la colisión entre el Sprite 0, nuestro dardo, y únicamente el Sprite 3, pero al estar agrupados, si el dardo colisiona con cualquiera de los otros dos también nos devolverá que ha colisionado. Los otros números indican el Offset que tiene que tener en cuenta para detectar la colisión.

No quiero liar mucho la cosa, así que pensar que el Offset nos permite reducir el área que se debe de tener en cuenta para que una colisión se produzca.

 

Los Sprites que usamos son de 16×16 pixeles

Los Sprites que estamos usando son de 16X16 pixeles, y como veis el dardo, que está centrado apropósito, es bastante más pequeño. Mediante el Offset, simplemente le decimos que reduzca en 4 pixeles tanto de ancho como de alto la detección para una colisión, por lo que la parte en blanco del Sprite del dardo no será efectiva para dicho cálculo.

 

Por último, tan solo nos queda prestar atención al comando que nos permite conocer la posición de un Spite en particular, con respecto al eje de coordenadas.

% SPRITE AT (3,1)

Aquí le indicamos que nos calcule la posición del Sprite 3, recordar que la diana estaba agrupada, en el eje Y. Si quisiéramos consultar el eje X, usaríamos un 0 en vez del 1 del comando. Aquí solo hacer una aclaración, sobre todo con respecto al juego Darts.

El cálculo de posiciones no atiende a las agrupaciones, cosa por otro lado coherente, de manera que en este caso, cuando el dardo colisiona con la diana y le preguntamos que en que posición estaba dicha diana, para poder calcular cuantos puntos ha obtenido el jugador, tendremos que hacer nosotros mismos la extrapolación de posiciones.

¿Qué está diciendo este tio?

Que sí, que es más sencillo de lo que parece. Nosotros podemos saber contra que Sprite ha colisionado realmente, si el 3, el 4 o el 5 realizando ciertos cálculos. Por un lado sabemos que nuestro dardo se ha lanzado desde la coordenada fija en el eje y de 128.

 

 

En este caso sabemos que ha colisionado con el sprite 4, porque al pedir la posición de colisión, nos devuelve que ha colisionado por encima de los 128 de la trayectoria del dardo.

Para realizar el ajuste fino y poder obtener las distintas puntuaciones de la diana, sabiendo que cada sprite es de 16×16 píxeles, podemos ir acotando para saber en que zona ha colisionado.

Por ejemplo, si el dardo hubiera colisionado con el borde inferior de la diana, sabemos que debe de estar casi 48 pixeles por encima del 128 de referencia. Serían unos 16 del Sprite 3 más 16 del Sprite 4 y un aproximadamente otros 16 del Sprite 5. Evidentemente habría que detectar un intervalo entre 48 y 46 para detectar el borde rojo de la diana.

Bueno no quería liaros mucho con la problemática de este cálculo pero nos viene bien para ir dándole al coco.

En fin, pues hasta aquí ha llegado esta entrada, espero que os haya resultado amena y divertida y que os permita seguir avanzando en vuestros desarrollos de Programación de Videojuegos en Basic para el Zx Spectrum Next.

Deja una respuesta

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