Creare Videogiochi - Game Developer

Versione completa: Tutorial 17 - Helloworld mobile
Al momento stai visualizzando i contenuti in una versione ridotta. Visualizza la versione completa e formattata.
Tutorial 17: Helloworld mobile

[Immagine: 017shot.jpg]

Questo esempio mostra il classico Hello World in versione per Windows mobile. Compila anche per altre piattaforme. La sola differenza dall'esempio originale è che qui vi serve una GUI, per permettere come minimo di uscire dall'app e un Filesystem, perché cambia in quanto è relativo alla singola piattaforma dell'eseguibile.
Codice PHP:
#include <irrlicht.h>

#if defined ( _IRR_WINDOWS_ )
    #include <windows.h>
#endif

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

#pragma comment(lib, "Irrlicht.lib")

class EventReceiver_basic : public IEventReceiver
{
private:
    
IrrlichtDevice *Device;
public:
    
EventReceiver_basic IrrlichtDevice *device ): Device device ) {}

    
virtual bool OnEvent(const SEventevent)
    {
        if (
event.EventType == EET_GUI_EVENT)
        {
            
s32 id event.GUIEvent.Caller->getID();

            switch(
event.GUIEvent.EventType)
            {
                case 
EGET_BUTTON_CLICKED:
                if (
id == 2)
                {
                    
Device->closeDevice();
                    return 
true;
                } break;
            }
        }

        return 
false;
    }
};

class 
CSampleSceneNode : public ISceneNode
{
    
aabbox3d<f32Box;
    
S3DVertex Vertices[4];
    
SMaterial Material;
public:

    
CSampleSceneNode(ISceneNodeparentISceneManagermgrs32 id)
        : 
ISceneNode(parentmgrid)
    {
        
Material.Wireframe false;
        
Material.Lighting false;

        
Vertices[0] = S3DVertex(0,0,101,1,0SColor(255,0,255,255), 01);
        
Vertices[1] = S3DVertex(10,0,-101,0,0SColor(255,255,0,255), 11);
        
Vertices[2] = S3DVertex(0,20,00,1,1SColor(255,255,255,0), 10);
        
Vertices[3] = S3DVertex(-10,0,-100,0,1SColor(255,0,255,0), 00);
        
Box.reset(Vertices[0].Pos);
        for (
s32 i=1i<4; ++i)
            
Box.addInternalPoint(Vertices[i].Pos);
    }
    
virtual void OnRegisterSceneNode()
    {
        if (
IsVisible)
            
SceneManager->registerNodeForRendering(this);

        
ISceneNode::OnRegisterSceneNode();
    }

    
virtual void render()
    {
        
u16 indices[] = {   0,2,32,1,31,0,32,0,1  };
        
IVideoDriverdriver SceneManager->getVideoDriver();

        
driver->setMaterial(Material);
        
driver->setTransform(ETS_WORLDAbsoluteTransformation);
        
driver->drawIndexedTriangleList(&Vertices[0], 4, &indices[0], 4);
    }

    
virtual const aabbox3d<f32>& getBoundingBox() const
    {
        return 
Box;
    }

    
virtual u32 getMaterialCount()
    {
        return 
1;
    }

    
virtual SMaterialgetMaterial(u32 i)
    {
        return 
Material;
    }   
}; 
Avviamo lo Startup per il nostro Windows Mobile Device
Codice PHP:
IrrlichtDevice *startup()
{
    
// both software and burnings video can be used
    
E_DRIVER_TYPE driverType EDT_SOFTWARE// EDT_BURNINGSVIDEO;

    // create device
    
IrrlichtDevice *device 0;

#if defined (_IRR_USE_WINDOWS_CE_DEVICE_)
    // set to standard mobile fullscreen 240x320
    
device createDevice(driverTypedimension2d<u32>(240320), 16true );
#else
    // on PC. use window mode
    
device createDevice(driverTypedimension2d<u32>(240320), 16false );
#endif      
    
if ( == device )
        return 
0;

    
IVideoDriverdriver device->getVideoDriver();
    
ISceneManagersmgr device->getSceneManager();
    
IGUIEnvironmentguienv device->getGUIEnvironment();

    
// set the filesystem relative to the executable
#if defined (_IRR_WINDOWS_)
    
{
        
wchar_t buf[255];
        
GetModuleFileNameW 0buf255 );

        
io::path base buf;
        
base base.subString 0base.findLast '\\' ) + );
        
device->getFileSystem()->addFileArchive base );
    }
#endif

    
IGUIStaticText *text guienv->addStaticText(L"FPS: 25",
        
rect<s32>(140,15,200,30), falsefalse0100 );

    
guienv->addButton(core::rect<int>(200,10,238,30), 02L"Quit");

    
// add irrlicht logo
    
guienv->addImage(driver->getTexture("../../media/irrlichtlogo3.png"),
                    
core::position2d<s32>(0,-2));
    return 
device;
}
!
int run IrrlichtDevice *device )
{
    while(
device->run())
    if (
device->isWindowActive())
    {
        
device->getVideoDriver()->beginScene(truetrueSColor(0,100,100,100));
        
device->getSceneManager()->drawAll();
        
device->getGUIEnvironment()->drawAll();
        
device->getVideoDriver()->endScene ();

        
IGUIElement *stat device->getGUIEnvironment()->
            
getRootGUIElement()->getElementFromId 100 );
        if ( 
stat )
        {
            
stringw str L"FPS: ";
            
str += (s32)device->getVideoDriver()->getFPS();

            
stat->setText str.c_str() );
        }
    }

    
device->drop();
    return 
0;
}
!
int example_customscenenode()
{
    
// create device
    
IrrlichtDevice *device startup();
    if (
device == 0)
        return 
1// could not create selected driver.

    // create engine and camera
    
EventReceiver_basic receiver(device);
    
device->setEventReceiver(&receiver);
    
    
IVideoDriverdriver device->getVideoDriver();
    
ISceneManagersmgr device->getSceneManager();
    
IGUIEnvironmentguienv device->getGUIEnvironment();


    
smgr->addCameraSceneNode(0vector3df(0,-40,0), vector3df(0,0,0));

    
CSampleSceneNode *myNode 
        new 
CSampleSceneNode(smgr->getRootSceneNode(), smgr666);

    
ISceneNodeAnimatoranim 
        
smgr->createRotationAnimator(vector3df(0.8f00.8f));

    if(
anim)
    {
        
myNode->addAnimator(anim);
        
anim->drop();
        
anim 0// As I shouldn't refer to it again, ensure that I can't
    
}

    
myNode->drop();
    
myNode 0// As I shouldn't refer to it again, ensure that I can't

    
return run device );
}

class 
EventReceiver_terrain : public IEventReceiver
{
public:

    
EventReceiver_terrain(IrrlichtDevice *devicescene::ISceneNodeterrainscene::ISceneNodeskyboxscene::ISceneNodeskydome) :
        
Device device ), Terrain(terrain), Skybox(skybox), Skydome(skydome), showBox(true)
    {
        
Skybox->setVisible(true);
        
Skydome->setVisible(false);
    }

    
bool OnEvent(const SEventevent)
    {
        if (
event.EventType == EET_GUI_EVENT)
        {
            
s32 id event.GUIEvent.Caller->getID();

            switch(
event.GUIEvent.EventType)
            {
                case 
EGET_BUTTON_CLICKED:
                if (
id == 2)
                {
                    
Device->closeDevice();
                    return 
true;
                } break;
            }
        }

        
// check if user presses the key 'W' or 'D'
        
if (event.EventType == irr::EET_KEY_INPUT_EVENT && !event.KeyInput.PressedDown)
        {
            switch (
event.KeyInput.Key)
            {
            case 
irr::KEY_KEY_W// switch wire frame mode
                
Terrain->setMaterialFlag(video::EMF_WIREFRAME,
                        !
Terrain->getMaterial(0).Wireframe);
                
Terrain->setMaterialFlag(video::EMF_POINTCLOUDfalse);
                return 
true;
            case 
irr::KEY_KEY_P// switch wire frame mode
                
Terrain->setMaterialFlag(video::EMF_POINTCLOUD,
                        !
Terrain->getMaterial(0).PointCloud);
                
Terrain->setMaterialFlag(video::EMF_WIREFRAMEfalse);
                return 
true;
            case 
irr::KEY_KEY_D// toggle detail map
                
Terrain->setMaterialType(
                    
Terrain->getMaterial(0).MaterialType == video::EMT_SOLID ?
                    
video::EMT_DETAIL_MAP video::EMT_SOLID);
                return 
true;
            case 
irr::KEY_KEY_S// toggle skies
                
showBox=!showBox;
                
Skybox->setVisible(showBox);
                
Skydome->setVisible(!showBox);
                return 
true;
            default:
                break;
            }
        }

        return 
false;
    }

private:
    
IrrlichtDevice *Device;
    
scene::ISceneNodeTerrain;
    
scene::ISceneNodeSkybox;
    
scene::ISceneNodeSkydome;
    
bool showBox;
}; 
L'avvio della funzione main è analogo a quello degli altri esempi. Chiediamo all'utente quale renderer desideri usare e lo avviamo. Stavolta gestiamo anche i parametri avanzati.
Codice PHP:
int example_terrain()
{
    
// create device
    
IrrlichtDevice *device startup();
    if (
device == 0)
        return 
1// could not create selected driver. 
Primo, aggiungiamo le classiche cose nella scena: Un logo di irrlicht, un piccolo testo di aiuto, una camera controllata dall'utente ed disabilitiamo il cursore del mouse.
Codice PHP:
video::IVideoDriverdriver device->getVideoDriver();
    
scene::ISceneManagersmgr device->getSceneManager();
    
gui::IGUIEnvironmentenv device->getGUIEnvironment();

    
//set other font
    //env->getSkin()->setFont(env->getFont("../../media/fontlucida.png"));

    // add some help text
    
env->addStaticText(
        
L"Press 'W' to change wireframe mode\nPress 'D' to toggle detail map\nPress 'S' to toggle skybox/skydome",
        
core::rect<s32>(5,250,235,320), truetrue0, -1true);

    
// add camera
    
scene::ICameraSceneNodecamera =
        
smgr->addCameraSceneNodeFPS(0,100.0f,1.2f);

    
camera->setPosition(core::vector3df(2700*2,255*2,2600*2));
    
camera->setTarget(core::vector3df(2397*2,343*2,2700*2));
    
camera->setFarValue(42000.0f);

    
// disable mouse cursor
    
device->getCursorControl()->setVisible(false); 
Ecco il nodo di scena per il tereno: lo aggiungiamo come un qualsiasi altro nodo di scena usando ISceneManager::addTerrainSceneNode(). L'unico parametro che usiamo è il nome del file della heightmap usata. Una heightmap è una semplice texture a scale di grigi. Il nodo la caricherà e ci creerà un terreno 3D.
Per rendere il terreno più grande cambiamo i valori di scala a (40, 4.4, 40). Poiché non abbiamo nessuna luce dinamica nella scena disabilitiamo l'illuminazione, impostiamo il file terrain-texture.jpg come texture principale e detailmap3.jpg come texture secondaria, per i dettagli. Per ultimo impostiamo i valori di scala per le texture, la prima la ripetiamo una sola volta in modo che copra tutto il terreno esattamente, la seconda la riduciamo in modo che si ripeta sul terreno per 20 volte.
Codice PHP:
// add terrain scene node
    
scene::ITerrainSceneNodeterrain smgr->addTerrainSceneNode(
        
"../../media/terrain-heightmap.bmp",
        
0,                  // parent node
        
-1,                 // node id
        
core::vector3df(0.f0.f0.f),     // position
        
core::vector3df(0.f0.f0.f),     // rotation
        
core::vector3df(40.f4.4f40.f),  // scale
        
video::SColor 255255255255 ),   // vertexColor
        
5,                  // maxLOD
        
scene::ETPS_17,             // patchSize
        
4                   // smoothFactor
        
);

    if ( 
terrain )
    {
        
terrain->setMaterialFlag(video::EMF_LIGHTINGfalse);

        
terrain->setMaterialTexture(0,
                
driver->getTexture("../../media/terrain-texture.jpg"));
        
terrain->setMaterialTexture(1,
                
driver->getTexture("../../media/detailmap3.jpg"));
        
        
terrain->setMaterialType(video::EMT_DETAIL_MAP);

        
terrain->scaleTexture(1.0f20.0f);
        
//terrain->setDebugDataVisible ( true ); 
Per abilitare le collisioni con il terreno creiamo un triangle selector. Se volete conoscere cosa fanno i triangle selectors date un'occhiata al tutorial delle collisioni. Il terrain triangle selector lavora insieme al terreno. Per dimostrarlo creiamo un collision response animator e attacchiamolo alla camera, in modo da impedire alla camera di attraversa il terreno stesso.
Codice PHP:
// create triangle selector for the terrain 
        
scene::ITriangleSelectorselector
            
smgr->createTerrainTriangleSelector(terrain0);
        
terrain->setTriangleSelector(selector);

        
// create collision response animator and attach it to the camera
        
scene::ISceneNodeAnimatoranim smgr->createCollisionResponseAnimator(
            
selectorcameracore::vector3df(60,100,60),
            
core::vector3df(0,0,0),
            
core::vector3df(0,50,0));
        
selector->drop();
        
camera->addAnimator(anim);
        
anim->drop(); 
Se vi serve accedere ai dati del terreno lo potete fare con la seguente porzione di codice.
Codice PHP:
scene::CDynamicMeshBufferbuffer = new scene::CDynamicMeshBuffer(video::EVT_2TCOORDSvideo::EIT_16BIT);
        
terrain->getMeshBufferForLOD(*buffer0);
        
video::S3DVertex2TCoordsdata = (video::S3DVertex2TCoords*)buffer->getVertexBuffer().getData();
        
// Work on data or get the IndexBuffer with a similar call.
        
buffer->drop(); // When done drop the buffer again.
    

Per permettere all'utente di cambiare tra la modalità wireframe e la normale creiamo un'istanza di event receiver e indichiamolo ad Irrlicht. In più aggiungiamo uno skybox già usato in molti altri esempi e uno skydome, da poter commutare tra loro mediante il tasto 'S'.
Codice PHP:
// create skybox and skydome
    
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPSfalse);

    
scene::ISceneNodeskybox=smgr->addSkyBoxSceneNode(
        
driver->getTexture("../../media/irrlicht2_up.jpg"),
        
driver->getTexture("../../media/irrlicht2_dn.jpg"),
        
driver->getTexture("../../media/irrlicht2_lf.jpg"),
        
driver->getTexture("../../media/irrlicht2_rt.jpg"),
        
driver->getTexture("../../media/irrlicht2_ft.jpg"),
        
driver->getTexture("../../media/irrlicht2_bk.jpg"));
    
scene::ISceneNodeskydome=smgr->addSkyDomeSceneNode(driver->getTexture("../../media/skydome.jpg"),16,8,0.95f,2.0f);

    
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPStrue);
    
// create event receiver
    
EventReceiver_terrain receiverdeviceterrainskyboxskydome);
    
device->setEventReceiver(&receiver);

    return 
run device );
}
int example_helloworld()
{
    
// create device
    
IrrlichtDevice *device startup();
    if (
device == 0)
        return 
1// could not create selected driver.

    
IVideoDriverdriver device->getVideoDriver();
    
ISceneManagersmgr device->getSceneManager();
    
IGUIEnvironmentguienv device->getGUIEnvironment();

    
IAnimatedMeshmesh smgr->getMesh("../../media/sydney.md2");
    if (!
mesh)
    {
        
device->drop();
        return 
1;
    }
    
IAnimatedMeshSceneNodenode smgr->addAnimatedMeshSceneNodemesh ); 
Per rendere la mesh più carina cambiamo il suo materiae. Disabilitiamo l'illuminazione perché tanto non abbiamo luci dinamiche, altrimenti diventerebbe tutta nera. Quindi impostiamo il loop sul frame dell'animazione a quello predefinito STAND. E per ultimo applichiamo la texture alla mesh. Senza di essa la mesh verrebbe mostrata monocolore.
Codice PHP:
if (node)
    {
        
node->setMaterialFlag(EMF_LIGHTINGfalse);
        
node->setMD2Animation(scene::EMAT_STAND);
        
node->setMaterialTexture0driver->getTexture("../../media/sydney.bmp") );
    } 
Per avere, da subito, lo sguardo rivolto alla nostra mesh piazziamo la camera nello spazio 3d in posizione (0, 30, -40). Da qui la camera è girata verso la direzione (0,5,0), che è approssimativamente il punto dove si trova il nostro modello md2.
Codice PHP:
smgr->addCameraSceneNode(0vector3df(0,30,-40), vector3df(0,5,0));
    
EventReceiver_basic receiver(device);

    
device->setEventReceiver(&receiver);
    return 
run device );
}

#if defined (_IRR_USE_WINDOWS_CE_DEVICE_)
    #pragma comment(linker, "/subsystem:WINDOWSCE /ENTRY:main") 
#elif defined (_IRR_WINDOWS_)
    #pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif
int main()
{
    
example_helloworld ();
    
example_customscenenode();
    
//example_terrain();


Versione scaricabile da QUI