El resultado de este ejemplo lucirá así:

Empecemos.
Empecemos como en el ejemplo Hola Mundo. Incluimos los archivos de cabecera de Irrlicht y un archivo de cabecera adicional para ser capaces de pedirle al usuario que elija un tipo de driver usando el interprete de comandos.
#include <irrlicht.h > #include <iostream > |
Como ya se ha escrito en el ejemplo "Hola Mundo", en el engine Irrlicht se puede encontrar todo en el namespace "Irr". Para deshacernos del irr:: en el frente del nombre de cada clase, le decimos al compilador que nosotros usaremos ese namespace de ahora en adelante y no tendremos que escribir ese irr::.
Hay otros 5 sub namespaces "core", "scene", "video", "io" y "gui". A diferencia del ejemplo "Hola Mundo" , no colocamos "using namespace" para esos otros 5 namespaces porque de esta manera vas a poder ver que puede ser encontrado en cada namespace. Pero si te gusta, podes incluir tambien los namespaces como en el ejemplo anterior. Programalo como te guste.
using namespace irr; |
De nuevo, para ser capaces de usar el archivo Irrlicht.DLL, necesitamos linkear con Irrlicht.lib. Podriamos setear esta ocpión en las opciones del proyecto, pero para hacerlo fácil usamos un pragma comment lib.
#pragma comment(lib, "Irrlicht.lib") |
Bien, empecemos. De nuevo, usamos el metodo main() como comienzo, no WinMain(), porque es mas corto de escribir.
int main()
{
|
Como en el ejemplo "Hola Mundo", creamos un IrrlichtDevice con CreateDevice(). La diferencia es que ahora le pedimos al usuario que seleccione que driver acelerado por hardware usar. El dispositivo de software podria ser muy lento al dibujar un mapa Quake 3 enorme, pero solo para divertirnos con eso, hacemos que esa decision tambien sea posible.
// Pregunta al usuario por el driver
video::E_DRIVER_TYPE driverType = video::EDT_DIRECTX9;
printf("Please select the driver you want for this example:\n"\
" (a) Direct3D 9.0c\n (b) Direct3D 8.1\n (c) OpenGL 1.2\n"\
" (d) Software Renderer\n (e) NullDevice\n (otherKey) exit\n\n");
char i;
std::cin >> i;
switch(i)
{
case 'a': driverType = video::EDT_DIRECTX9; break;
case 'b': driverType = video::EDT_DIRECTX8; break;
case 'c': driverType = video::EDT_OPENGL; break;
case 'd': driverType = video::EDT_SOFTWARE; break;
case 'e': driverType = video::EDT_NULL; break;
default: return 1;
}
// crea el dispositivo y termina si la creacion fallo
IrrlichtDevice *device =
createDevice(driverType, core::dimension2d<s32>(640, 480));
if (device == 0)
return 1;
|
Obtenemos un puntero al driver de video y al SceneManager asi no tenemos que escribir siempre device->getVideoDriver() y device->getSceneManager().
video::IVideoDriver* driver = device->getVideoDriver(); scene::ISceneManager* smgr = device->getSceneManager(); |
Para mostrar el mapa del Quake 3, primero necesitamos cargarlo. Los mapas del Quake 3 son empaquetados dentro de archivos .pk3 los cuales no son otra cosa mas que archivos .zip. Entonces agregamos el archivo .pk3 a nuestro FileSystem . Despues de que es agregado podemos leer lo que hay dentro del archivo, como si el contenido estuviera guardado directamente en disco.
device->getFileSystem()->addZipFileArchive("../../media/map-20kdm2.pk3");
|
Ahora podemos cargar el mesh llamando a getMesh(). Obtenemos el puntero devuelto en IanimatedMesh. Como sabes, los mapas del Quake 3 no son realmente animados, solo son un pedazo enorme de greometría estática con algunos materiales adjuntos. De ahí que IanimatedMesh consiste en un solo frame, entonces obtenemos el "primer frame" de la "animación", el cual es nuestro nivel quake y creamos un nodo de escena OctTree con el, usando addOctTreeSceneNode(). El OctTree optimiza la escena un poco, tratando de dibujar solo la geometría que es visible en el momento. Una alternativa del OctTree sería un AnimatedMeshSceneNode el cual dibujaría siempre la geometría completa del mesh, sin optimización. Probá esto: Escribí addAnimatedMeshSceneNode en vez de addOctTreeSceneNode y compará las primitivas dibujadas por el driver de video. ( Hay un metodo getPrimitiveCountDrawed() en la clase IvideoDriver). Notá que esta optimización con el OctTree solo es útil al dibujar meshes grandes que consisten en mucha geometría.
scene::IAnimatedMesh* mesh = smgr->getMesh("20kdm2.bsp");
scene::ISceneNode* node = 0;
if (mesh)
node = smgr->addOctTreeSceneNode(mesh->getMesh(0));
|
Como el nivel no fue modelado alrededor del origen (0,0,0), transladamos un poco el nivel completo.
if (node)
node->setPosition(core::vector3df(-1300,-144,-1249));
|
Ahora solamente necesitamos una cámara que mire hacia el mapa Quake 3. Y queremos crear una cámara controlada por el usuario. Hay cámaras diferentes disponibles en el engine Irrlicht. Por ejemplo la Cámara de Maya la cual puede ser controlada como una cámara en Maya: Rotar con el botón izquierdo del mouse apretado, Zoom con los dos botones apretados, translación con el botón derecho del mouse apretado. Esto puede ser creado con addCameraSceneNodeMaya(). Pero para este ejemplo, queremos crear una cámara con comportamiento como el de las cámaras que hay en los juegos First Person Shotters (FPS).
smgr->addCameraSceneNodeFPS(); |
El cursor del mouse no necesita ser visible, por lo que lo hacemos invisible:
device->getCursorControl()->setVisible(false); |
Ya lo hemos hecho todo, asi que vamos a dibujarlo. Tambien escribimos los frames por segundo actuales y las primitivas dibujadas en el caption de la ventana. La linea "if (device->isWindowActive())" es opcional, pero previene al render del engine de setear la posición del cursor del mouse despues del intercambio de tareas cuando hay otros programas activos.
int lastFPS = -1;
while(device->run())
{
driver->beginScene(true, true, video::SColor(0,200,200,200));
smgr->drawAll();
driver->endScene();
int fps = driver->getFPS();
if (lastFPS != fps)
{
core::stringw str = L"Irrlicht Engine - Quake 3 Map example [";
str += driver->getName();
str += "] FPS:";
str += fps;
device->setWindowCaption(str.c_str());
lastFPS = fps;
}
}
|
Al final, borra el dispositivo Irrlicht.
device->drop(); return 0; } |
Eso es todo. Compilá y juga con el programa.
