Siamo al settimo articolo, sull’argomento: direi che si può procedere spediti. Questa volta, vogliamo vedere cosa succede se esageriamo un pochetto con la grafica 3D. Creeremo un cubo composto a sua volta da 1000 cubi differenti, perché vogliamo tirare il collo a GDExtension… Non mi dilungo su come debba essere registrata la classe C++: il metodo è sempre lo stesso. Esaminiamo il codice nelle due immagini seguenti, quello GDScript in Fig.16 e quello C++ in Fig.17.


Apro una piccola parentesi, prima di procedere. Abbiamo già detto altrove tra le righe, magari scherzandoci un po’ sopra, che non è scopo di questo tutorial insegnare il C++, linguaggio meno difficile di quanto si dica in giro, ma che ha le sue caratteristiche che lo rendono quello che è, un po’ indigesto alle prime armi. In Fig.17, chi conosce bene il C++, dovrebbe notare una stranezza: in occasione della creazione di nuove classi, c’è una strana funzione all’opera, come nel caso seguente:
MeshInstance3D *mesh_instance = memnew(MeshInstance3D);
Sto parlando di memnew, ovviamente. Solitamente, il C++ prevede l’uso di new, l’operatore standard per la creazione di nuove classi (ma non solo) in memoria dinamica. Da dove viene fuori, allora, memnew? Si tratta, in effetti, di una particolarità di Godot, sempre legata al fatto che, le classi in genere, devono essere seguite anche dal lato IDE e GDScript. memnew, in effetti, si usa esattamente come new, a parte il fatto che è una funzione, invece di un operatore, per cui il tipo di classe che si intende creare va messo tra parentesi tonde. Esiste anche un memdelete che corrisponde al delete canonico e anche per lui vale il fatto che, essendo una funzione, la classe da distruggere deve essere passata tra parentesi. Questi due operatori, oltre a fare lo stesso lavoro di quelli che sostituiscono, fanno altro. Sotto il cofano, si occupano anche di registrare e deregistrare le classi dal database interno di Godot, sempre lui, quello che permette di vedere le classi anche nell’IDE e in GDScript. Quindi, è assolutamente vietato, nel contesto GDExtension, farne a meno.
Piccola postilla: i più attenti si saranno accorti del fatto che ho creato un’istanza mesh per ogni cubo, cosa che si poteva evitare per ottimizzare il codice. I cubi sono tutti uguali, perché non usare la stessa mesh per tutti? Avete capito che stiamo cercando di tirare il collo a GDExtension, vero?
Detto questo, possiamo tornare alla nostra classe Benckmark in GDScript per modificarla come segue:
func _prepare_works_array() -> void:
# Aggiungeremo le varie classi per il benchmark qui
# works.append(BenchmarkLotOfNothing.new())
# works.append(GDBenchmarkLotOfNothing.new())
works.append(Benchmark1000Cubes.new())
works.append(GDBenchmark1000Cubes.new())
Abbiamo commentato le righe del benchmark precedente, per esaminare meglio questo. Bene siamo pronti per lanciarlo e… si accettano scommesse. Dopotutto C++ è molto più veloce di GDScript, no? Cosa potrà mai accadere? Eppure, questo è quello che stampa il benchmark:
— GDScript ha generato 1000 cubi
1000 Cubi su GDScript –> 21718 usec.
— GDExtension ha generato 1000 cubi
1000 Cubi su GDExtension –> 21580 usec.
Benchmark finito!
C’è della kriptonite per il C++, qua dentro… Come lo spieghiamo? Chi mi conosce, sa che continuo a dire che GDScript non è il male che tutti dicono essere. Lanciarsi in GDExtension o peggio in C#, che considero un nonsense pressoché assoluto, non è sempre un buon approccio. Il benchmark è chiaro: entrambi i codici ci hanno messo lo stesso tempo, millisecondo più, millisecondo meno. Il motivo è più semplice di quello che sembra: anche se il lavoro fatto questa volta sembra più complicato del benchmark precedente, ad analizzarlo meglio ci si accorge che l’unica cosa che hanno fatto entrambi i codici, è… dare istruzioni all’engine! In altre parole, se tutto si riduce a dire Godot, per favore fammi 1000 cubi, che tu glielo dica in GDScript o in C++, i cubi se li farà lui internamente!
Il maggior valore intrinseco del linguaggio di programmazione C++, quindi, va a farsi benedire. La stessa cosa succede con C# che, tra l’altro, ha lo svantaggio di portarsi dietro la libreria .NET, che non è proprio leggera. Serve? Abbiamo dimostrato di no. GDScript va benissimo. Tutto questo è vero se si sta alla larga da calcoli e cicli intensi. In altre parole, se succede davvero qualcosa nel nostro codice che superi il mero comando rivolto all’engine, allora il linguaggio farà la differenza, altrimenti… niente. Usate GDScript, ve l’ho già detto. Ora ve l’ho pure dimostrato, ok?
A titolo di curiosità: l’immagine in testa all’articolo è proprio il cubo di cubi che abbiamo creato con il codice, ma che abbiamo anche distrutto. Se volete vederla, potete commentare il benchmark realizzato in C++ per evitare scocciature con il compilatore, e poi commentare anche il ciclo finale del codice di Fig.16.