In questo articolo finalmente metteremo mano al codice! Verrà illustrata la struttura del motore 3D Irrlicht con una panoramica generale sulle diverse componenti e la struttura minima per far funzionare un’applicazione. Tale struttura sarà la base per la creazione del nostro videogioco. Si presuppone che ci sia un minimo di conoscenza non tanto della programmazione in C++ ma della logica ad oggetti che sta dietro di essa.
Irrlicht
Come anticipato nei precedenti articoli Irrlicht è un motore 3D open source scritto in C++, il quale ci mette a disposizione delle librerie molto potenti per la realizzazione di videogiochi e/o presentazioni 3D. Entrando nello specifico, il motore è articolato in namespace (un namespace non è altro che un raggruppamento di nomi di entità), ecco come è strutturato:
irr – Namespace principale che racchiude tutto ciò che è compreso in Irrlicht
irr::core – Namespace che racchiude tutti gli elementi e funzioni che costituiscono il cuore del motore tipo le funzioni sui vettori, piani ecc.
irr::gui – Namespace che racchiude tutti gli elementi che compongono e gestiscono la GUI (Graphic user interface)
irr::io – Namespace che gestisce l’input e l’output di dati, legge e scrive files di testo o XML, archivi zip ecc.
irr::scene – Namespace che gestisce la scena, carica le mesh, i nodi, le billboard ecc.
irr::video – Namespace che gestisce tutte le operazioni atte alla resa video (rendering) della scena.
se alcuni di questi termini non vi suonassero familiari non vi preoccupate, verranno approfonditi man mano; l’importante è capire che per ogni cosa che dobbiamo fare c’è una funzione da utilizzare e queste funzioni sono suddivisi nei Namespace sopracitati.
Ora invece analizziamo i principali elementi che compongono il motore, alcuni sono essenziali e senza di essi non si può utilizzare Irrlicht.
irr::IrrlichtDevice – questa è la classe principale, tramite questa si può accedere praticamente a tutto e non possiamo usare molteplici istanze di questa classe, solo una.
irr::video::IVideoDriver – questa classe è l’interfaccia al driver che si occupa di eseguire tutte le funzioni grafiche sia 2D che 3D, tutti i rendering e le manipolazioni di texture vengono realizzate qui.
irr::scene::ISceneManager – questa classe gestisce tutti i nodi, le mesh e le telecamere della scena da rendere.
Passiamo al codice!
Analizziamo ora il listato di questo programma che si occupa di caricare una mesh (modello 3D) ed inquadrarlo con una telecamera di tipo FPS (First person shooter), il tutto utilizzando ovviamente le classi di Irrlicht.
#include "irrlicht.h" using namespace irr; #pragma comment(lib, "irrlicht.lib") int main() { // inizializzo il device impostando risoluzione 1024x720 usando DirectX9 IrrlichtDevice *device = createDevice(video::EDT_DIRECT3D9, core::dimension2d<u32>(1024,720)); // Creo driver video::IVideoDriver* driver = device->getVideoDriver(); // Creo il gestore di scena scene::ISceneManager* scenemgr = device->getSceneManager(); // Tramite il device imposto il titolo della finestra device->setWindowCaption(L"Irrlicht tutorial by softgame.it"); // Aggiungo alla scena la mesh scene::ISceneNode* node = scenemgr->addMeshSceneNode(scenemgr->getMesh("take.x")); // Se caricata correttamente la mesh procedo al caricamento della texture e // disabilito il lighting *1, setto la posizione di partenza a -100 per ogni asse if (node) { node->setMaterialTexture(0, driver->getTexture("milwalll.bmp")); node->setMaterialFlag(video::EMF_LIGHTING, false); node->setPosition(core::vector3df(-100, -100, -100)); } // Aggiungo una camera di tipo FPS (si controlla tramite mouse e frecce) // Gli indico il target da inquadrare con le coord. scenemgr->addCameraSceneNodeFPS(); scenemgr->getActiveCamera()->setTarget(core::vector3df(-100, -100, -100)); // Ciclo principale dove viene renderizzata la scena while(device->run() && driver) { driver->beginScene(true, true, video::SColor(255,0,0,255)); scenemgr->drawAll(); driver->endScene(); } // Cancello il device prima di uscire device->drop(); return 0; }
Il codice è commentato riga per riga, di seguito voglio aggiungere alcune considerazioni generali e alcune precisazioni sulle prime 3 righe.
#include "irrlicht.h" using namespace irr; #pragma comment(lib, "irrlicht.lib")
La prima riga include il file di intestazioni (.h Header file irrlicht).
Nella seconda dichiariamo l’utilizzo del namespace irr, questo ci semplifica la scrittura del codice, difatti per utilizzare una qualsiasi entità inclusa in questo namespace possiamo ora omettere irr. Esempio concreto per indicare quale video driver debba utilizzare ho scritto:
video::EDT_DIRECT3D9
e non
irr::video::EDT_DIRECT3D9
e così via per tutte le altre entità.
Nella terza riga abbiamo specificato al linker di dover utilizzare la liberia irrlicht.lib.
L’oggetto caricato è solo la base del nostro piccolo carro armato. Riguardo l’illuminazione potete leggere nei commenti che al caricamento della mesh il lighting è stato disabilitato, questo perchè non avendo inserito nessuna luce, sarebbe risultato completamente buio. Le luci le aggiungeremo successivamente.
Il codice di questo primo listato è stato scritto in modo procedurale e non ad oggetti, questo per ridurre al minimo i files e le istruzioni, nei prossimi articoli lo riscriveremo in modo da utilizzare i vantaggi della programmazione ad oggetti.
Sorgente e archivio file multimediali
Il listato di codice che abbiamo visto in questo articolo lo potete scaricare qui, mentre di seguito il link a tutti i media: le mesh, le texture e i file sonori che ci serviranno per portare avanti il nostro piccolo progetto.
Se avete configurato bene il vostro ambiente di sviluppo come indicato nel precedente articolo, non dovete fare altro che creare un nuovo progetto (salvatelo dove preferite sul vostro PC), tipologia: Win32 console vuoto, aggiungete il listato chiamando il file main.cpp e procedete alla compilazione, il compilatore vi creerà una sottocartella Debug dove troverete il file eseguibile (.exe), per far funzionare il tutto dovete copiare il file irrlicht.dll dalla sottocartella bin\Win32-VisualStudio della libreria Irrlicht e dovete anche scompattare ed aggiungere i file che abbiamo utilizzato nell’esempio ovvero: take.X e milwalll.bmp. Ora facendo partire l’eseguibile dovrebbe visualizzarsi correttamente il nostro oggetto grazie ad Irrlicht come da screenshot:
La telecamera che abbiamo usato è del tipo FPS (first person shooter), di conseguenza la si può utilizzare tramite mouse e frecce direzionali.
Articolo precedente: Creare un videogioco: 2 Configurazione ambiente di lavoro
Articolo successivo: Creare un videogioco: 4 Componiamo la scena