TIC-80 – Bow and Arrow #01

0

Dopo l’introduzione a TIC-80, è arrivato il momento di creare il nostro primo gioco: una rielaborazione di Bow and Arrow, classico videogioco in cui il giocatore deve fare più punti possibile tirando frecce a dei palloncini. Un’idea semplice e probabilmente banale, ma che dovrebbe permettere di introdurre nuovi concetti in maniera piuttosto indolore. Parliamo di function(s), table(s) e altri operatori specifici del LUA, e di alcune chiamate API di TIC-80 più complete rispetto a quelle base (ad esempio l’ormai celebre spr).

Iniziamo quindi con l’avviare il nostro TIC-80 e premiamo ESC per accedere al Code Editor: come prima cosa avremo delle variabili, due che saranno costanti per le dimensioni e una che fungerà da “tick” per il nostro gioco, venendo aggiornata nella funzione TIC().

Dopodiché passiamo alla realizzazione degli sprite: semplicemente, tre stati per il nostro personaggio, una freccia, e sotto due frame per il palloncino rosso e due frame per il palloncino giallo. Come vedete, le dimensioni di questi sprite sono doppie rispetto al default 8×8, quindi 16×16: nulla di preoccupante, e il tutto ottenibile tramite rotella del mouse su o giù oppure con la selezione sullo slider in alto a destra, prima delle tab FG/BG. Ovviamente avere sprite di dimensioni più generose permette di inserire più dettagli nella nostra grafica, in questo caso però si andrà a dimezzare il numero di sprite che è possibile avere nel gioco.

image 03-sprites.png

La prima novità di questo gioco è l’utilizzo delle table. Le table possono essere viste come collezioni di elementi (anche eterogenei tra loro) che permettono di mantenere in una struttura iterabile tramite cicli o richiamabile in stile “metodo” variabili e/o altre tabelle. Ad esempio, noi qui andiamo a creare la table “player”, che avrà due proprietà che specificano le coordinate (“x”, “y”) e una che specifica il numero di munizioni (“ammo”) rimaste. Se noi scriviamo “player.x” potremo recuperare/settare il valore di x nella table player.

image 04-player.png

Iniziamo con il disegnare il nostro player! Utilizziamo la funzione spr per disegnare lo sprite con index 256, alle coordinate player.x e player.y. Tutti i parametri che vengono dopo sono sempre opzionali, ma molto utili. Rimando alla documentazione ufficiale per la descrizione completa. I due che ci interessano sono l’ultima coppia di “2”. Questi due parametri specificano che l’area dello spritesheet da disegnare è di due caselle, rispetto alla dimensione di default (8×8). Quindi stiamo disegnando un’area di 16×16 a partire dall’indice 256, ottenendo il risultato desiderato, ovvero la figura intera del nostro protagonista.
Andiamo inoltre a stampare in alto a sinistra le munizioni rimanenti prima del game over.

image 05-draw.png

Prima di eseguire il gioco è necessario salvarlo. Quindi premiamo ESC e nella console scriviamo “save robinhoody”, permettendoci così in futuro di scrivere “load robinhoody” e caricare così il nostro gioco all’interno degli editor.

image 06-save-comp.png

Una volta premuto CTRL+R (o scritto in console “run” e premuto INVIO) questo è quello che si presenterà ai nostri occhi. Abbiamo messo a schermo il nostro player e il numero di munizioni rimasto, e siamo pronti per partire con la realizzazione del gameplay vero e proprio.

image 07-run.png

Dimentichiamoci per un attimo del nostro player e passiamo a concentrarci sui bersagli del nostro gioco, ovvero i palloncini colorati, che partiranno dal basso e saliranno verso l’alto. Creiamo una table vuota, chiamata “ballons”, che conterrà una lista di ballons, ognuno con le proprie coordinate “x” e “y”. Chi ha familiarità con la programmazione OOP potrà notare qualcosa di molto comune, ovvero una collection di object: anche se in LUA questo concetto non esiste, è possibile simularlo con l’utilizzo delle table e delle iterazioni sui loro elementi.

image 09-ballons.png

Spostiamoci in fondo al nostro codice (dopo la funzione TIC()) e andiamo a creare una function che si chiamerà createBallons(). Come intuibile dal nome, questa funzione di occuperà di creare palloncini. Il primo if controlla che la lunghezza (operatore “#” seguito dal nome della tabella) della table ballons non sia uguale o superiore a 20. Se quindi la nostra table ballons conterrà meno di 20 elementi, il codice successivo verrà eseguito. Il successivo if controlla che il resto della divisione del tick del programma per 120, sia 0. Questo controllo ci permette di creare il palloncino ogni 2 secondi (60 x 2 = 120) in quanto la funzione verrà inserita nel corpo principale di TIC(), che gira a 60fps. La creazione di un palloncino è banale, in quanto si tratta, tramite la funzione “table.insert”, di andare ad inserire un nuovo elemento con una sua “x” e una sua “y” all’interno della tabella ballons. Per aiutare la leggibilità ho inizializzato le coordinate in due variabili locali, ma si può scrivere tutto in una sola riga.

image 10-create-ballons.png

Successivamente è il momento di disegnarli, questi palloncini, tramite la funzione drawBallons(). Con la funzione “ipairs” si può andare a ciclare una collection (ottenendo un indice, utile in alcune situazioni). Ecco quindi che per ogni elemento della tabella ballons andremo a richiamare la funzione spr con i soliti parametri per duplicare l’area da disegnare, essendo anche i palloncini in 16×16. L’inizializzazione dell'”index” (variabile locale) ci presenta un modo semplice per animare uno sprite, andando ad agire sul tick del gioco per ottenere uno switch tra i due frame (“t/20%2”) ad una frequenza più rallentata grazie alla divisione per 20 del tick. Quel “*2” che vedete serve a ottenere la giusta area di disegno: visto che il nostro sprite occupa un’area doppia del normale è necessario che anche l’indice venga “spostato” di due posizioni e non solo di una.

image 11-draw-ballons.png

Andiamo a completare questa prima parte con il movimento dei palloncini, andando a implementare processBallons(). Ancora una volta cicleremo sulla table ballons e modificheremo la proprietà “y” dell’elemento corrente (“b”).

image 12-process-ballons.png

Una volta completata anche l’ultima funzione processBallons(), nella funzione TIC() aggiungeremo le chiamate a queste tre funzioni appena scritte come nell’immagine sotto.

image 13-main-ballons.png

Salviamo con CTRL+S ed eseguiamo il codice con CTRL+R. Ecco il risultato!

image 14-run.gif

Alla prossima! 😉

Parte 1 | Parte 2 | Parte 3

Appena cominciato a seguire questa ottima guida, grazie mille per averla realizzata. Mi sto divertendo con TIC-80 🙂

Premendo i tasti F1, F2,… a casaccio ho scoperto anche che con F9 (mi pare) si può fare la registrazione gif 😃
image balloons.gif

PS: i palloncini lampeggiano, ma mi piaceva così e l’ho lasciato xD nella prossima parte fixo.

davcri si F7 imposta la copertina del .tic quando viene usata la funzione surf o sul sito ufficiale, F8 prende uno screen in formato .gif, F9 inizia e poi termina la registrazione e salva una .gif. Unico appunti: le .gif che registra sono molto piccole e anche pesantissime, non so perché! Personalmente uso ScreenToGif 😉

Comunque grande, tieni conto che questa guida è “vecchia” e ho cambiato approccio nel tempo. Sì i palloncini lampeggianti ci possono stare 😂

Cambiato approccio per cosa nello specifico?

davcri le iterazioni sulle liste a partire dal fondo per evitare riferimenti nil, la gestione delle funzioni di update e draw, ad esempio, centralizzando la gestione dell’update per poter facilmente controllare lo stato del gioco… O raggruppando le chiamate necessarie per disegnare la mappa in un unica funzione…
Diciamo che tutte quelle cose che vengono gratis in un engine pre costruito, qui te le fai.
Croce ma anche delizia.

Comments are closed.