Tutoriel Irrlicht 4

Mouvement

| Nikolaus Gebhart | Laurent Alexandre |

Traducteur

Neckara

Ce tutoriel est une traduction de l'anglais des tutoriels officiels d'Irrlicht.

Il montre comment déplacer et animer un nœud de scène. Nous parlerons aussi bien des bases de SceneNodeAnimators que du déplacement manuel des nœuds à l'aide du clavier. Nous allons créer un mouvement indépendant du nombre d'images, ce qui signifie que la distance lors d'un déplacement dépendra de la durée du dernier tour de la boucle Irrlicht.

Vous pouvez aussi regarder les autres exemples d'Irrlicht, l'exemple 19. Souris et Joystick montre comment traiter ces différents types d'entrée.

Commentez

- Titre : Tutoriel Irrlicht 4

- Auteurs : Nikolaus Gebhart, Laurent Alexandre

- Traducteur : Neckara

- Parution : 23 avril 2013

- Mise à jour : 23 avril 2013

- Public visé :

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2013 Neckara. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Receveur d'événements

- II. Création des nœuds

- III. Animation des nœuds

- IV. Conclusion

- V. Remerciements

I - Receveur d'événements

Comme toujours, j'inclus les fichiers d'en-têtes, j'utilise le namespace « irr », et je dis à l'éditeur de liens de lier le fichier .lib.

#ifdef _MSC_VER
// Nous définissons aussi ceci pour ne plus voir l'avertissement de MSVC lors du sprintf().
#define _CRT_SECURE_NO_WARNINGS
#pragma comment(lib, "Irrlicht.lib")
#endif

#include <irrlicht.h>
#include "driverChoice.h"

using namespace irr;

Pour recevoir des événements tels que les entrées souris ou clavier, voire des événements GUI comme « le bouton OK a été cliqué », nous avons besoin d'un objet héritant de irr::IEventReceiver. Il n'y a qu'une seule méthode à surcharger : irr::IEventReceiver::OnEvent(). Cette méthode sera appelée par le moteur à chaque événement qui surviendra. Mais ce qui nous intéresse, c'est de savoir si une touche est maintenue enfoncée ou non, nous allons donc enregistrer l'état de chaque touche.

class MyEventReceiver : public IEventReceiver
{
public:
// Ceci est la méthode que nous devons implémenter
virtual bool OnEvent(const SEvent& event)
{
// Se souvient si la touche est enfoncée ou relâchée
if (event.EventType == irr::EET_KEY_INPUT_EVENT)
KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;

return false;
}

// Ceci est utilisé pour vérifier si une touche est enfoncée
virtual bool IsKeyDown(EKEY_CODE keyCode) const
{
return KeyIsDown[keyCode];
}

MyEventReceiver()
{
for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
KeyIsDown[i] = false;
}

private:
// Nous utilisons ce tableau pour stocker l'état de chaque touche.
bool KeyIsDown[KEY_KEY_CODES_COUNT];
};

Le receveur d'événements pour conserver les touches pressées est prêt, la réponse actuelle sera faite dans la boucle de rendu, juste avant de dessiner la scène.

II - Création des nœuds

Créons donc un irr::IrrlichtDevice et le nœud de scène que nous voulons bouger. Nous créons aussi d'autres nœuds de scène supplémentaires pour montrer qu'il y a différentes possibilités de déplacement et d'animation pour les nœuds de scène.

int main()
{
// demande un pilote à l'utilisateur
video::E_DRIVER_TYPE driverType=driverChoiceConsole();
if (driverType==video::EDT_COUNT)
return 1;

// créer le moteur
MyEventReceiver receiver;

IrrlichtDevice* device = createDevice(driverType,
core::dimension2d<u32>(640, 480), 16, false, false, false, &receiver);

if (device == 0)
return 1; // on ne peut pas créer le pilote sélectionné.

video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();

Créons le nœud qui sera déplacé avec les touches WSAD. Nous créons un nœud sphère qui est une des primitives géométriques du moteur. Nous plaçons le nœud à (0,0,30) et nous lui assignons une texture pour le rendre un peu plus intéressant à regarder. Parce que nous n'avons pas de lumière dynamique dans cette scène, nous désactivons l'éclairage pour chaque modèle (sinon les modèles seraient noirs).

scene::ISceneNode * node = smgr->addSphereSceneNode();
if (node)
{
node->setPosition(core::vector3df(0,0,30));
node->setMaterialTexture(0, driver->getTexture("../../media/wall.bmp"));
node->setMaterialFlag(video::EMF_LIGHTING, false);
}

Maintenant, nous créons un autre nœud, déplaçable en utilisant un animateur de nœuds de scène. Ce dernier modifie le nœud de scène et peut être attaché à n'importe quel nœud de scène comme un nœud de scène de mesh, un panneau, une lumière et même un nœud de scène de caméra. Les animateurs ne sont pas seulement capables de modifier la position d'un nœud de scène, ils peuvent aussi, par exemple, animer les textures d'un objet. Nous créons un nœud de scène de cube et nous l'attachons à l'animateur « fly circle », faisons ensuite voler ce nœud autour de notre nœud de scène de sphère.

scene::ISceneNode* n = smgr->addCubeSceneNode();

if (n)
{
n->setMaterialTexture(0, driver->getTexture("../../media/t351sml.jpg"));
n->setMaterialFlag(video::EMF_LIGHTING, false);
scene::ISceneNodeAnimator* anim =
smgr->createFlyCircleAnimator(core::vector3df(0,0,30), 20.0f);
if (anim)
{
n->addAnimator(anim);
anim->drop();
}
}

Le dernier nœud de scène que nous ajoutons pour montrer les possibilités des animateurs de nœuds de scène est un modèle b3b, qui utilise un animateur « fly straight » pour courir entre différents points.

scene::IAnimatedMeshSceneNode* anms =
smgr->addAnimatedMeshSceneNode(smgr->getMesh("../../media/ninja.b3d"));

if (anms)
{
scene::ISceneNodeAnimator* anim =
smgr->createFlyStraightAnimator(core::vector3df(100,0,60),
core::vector3df(-100,0,60), 3500, true);
if (anim)
{
anms->addAnimator(anim);
anim->drop();
}

III - Animation des nœuds

Pour rendre le modèle plus correct, nous désactivons la lumière, définissons les étapes par lesquelles l'animation devra passer, nous tournons le modèle d'environ 180 degrés et ajustons la vitesse d'animation et la texture. Pour mettre la bonne animation (étapes et vitesse), nous devrions appeler anms->setMD2Animation(scene::EMAT_RUN) pour l'animation de « course », au lieu de setFrameLoop et setAnimationSpeed, mais ceci ne fonctionne qu'avec les animations MD2, or vous devez aussi savoir comment démarrer d'autres animations. Mais il est préférable de ne pas utiliser des nombres magiques(1) pour les paramètres des étapes.

anms->setMaterialFlag(video::EMF_LIGHTING, false);

anms->setFrameLoop(0, 13);
anms->setAnimationSpeed(15);
//      anms->setMD2Animation(scene::EMAT_RUN);

anms->setScale(core::vector3df(2.f,2.f,2.f));
anms->setRotation(core::vector3df(0,-90,0));
//      anms->setMaterialTexture(0, driver->getTexture("../../media/sydney.bmp"));

}

Pour être capable de regarder la scène et de s'y déplacer, nous créons une caméra style FPS et nous cachons le curseur de la souris.

smgr->addCameraSceneNodeFPS();
device->getCursorControl()->setVisible(false);

Ajoutons un logo Irrlicht coloré.

device->getGUIEnvironment()->addImage(
driver->getTexture("../../media/irrlichtlogoalpha2.tga"),
core::position2d<s32>(10,20));

gui::IGUIStaticText* diagnostics = device->getGUIEnvironment()->addStaticText(
L"", core::rect<s32>(10, 10, 400, 20));
diagnostics->setOverrideColor(video::SColor(255, 255, 255, 0));

Nous avons tout fait, dessinons le tout. Nous écrivons aussi le nombre d'images par seconde et le nom du pilote dans le titre de la fenêtre.

int lastFPS = -1;

// Pour créer un mouvement indépendant du nombre d'images par seconde, nous devons savoir
// combien de temps s'est écoulé depuis la dernière image.
u32 then = device->getTimer()->getTime();

// Ceci est la vitesse de mouvement en unités par seconde.
const f32 MOVEMENT_SPEED = 5.f;

while(device->run())
{
// Calcul le temps delta d'une image.
const u32 now = device->getTimer()->getTime();
const f32 frameDeltaTime = (f32)(now - then) / 1000.f; // Temps en secondes
then = now;

Vérifions que les touches W, S, A, D sont maintenues enfoncées et déplaçons le nœud de sphère.

core::vector3df nodePosition = node->getPosition();

if(receiver.IsKeyDown(irr::KEY_KEY_W))
nodePosition.Y += MOVEMENT_SPEED * frameDeltaTime;
else if(receiver.IsKeyDown(irr::KEY_KEY_S))
nodePosition.Y -= MOVEMENT_SPEED * frameDeltaTime;

if(receiver.IsKeyDown(irr::KEY_KEY_A))
nodePosition.X -= MOVEMENT_SPEED * frameDeltaTime;
else if(receiver.IsKeyDown(irr::KEY_KEY_D))
nodePosition.X += MOVEMENT_SPEED * frameDeltaTime;

node->setPosition(nodePosition);

driver->beginScene(true, true, video::SColor(255,113,113,133));

smgr->drawAll(); // dessine la scene 3d
device->getGUIEnvironment()->drawAll(); // dessine l'environnement gui (le logo)

driver->endScene();

int fps = driver->getFPS();

if (lastFPS != fps)
{
core::stringw tmp(L"Movement Example - Irrlicht Engine [");
tmp += driver->getName();
tmp += L"] fps: ";
tmp += fps;

device->setWindowCaption(tmp.c_str());
lastFPS = fps;
}
}

À la fin, supprimons le moteur Irrlicht.

device->drop();

return 0;
}

Voilà, compilons et testons le programme.

IV - Conclusion

Vous pouvez désormais déplacer et animer vos nœuds de scène en utilisant Irrlicht.

Dans le prochain tutoriel « Interface Utilisateur », nous verrons comment créer et utiliser une interface utilisateur avec des fenêtres, des boutons, etc.

V - Remerciements

Merci à Nikolaus Gebhardt de nous permettre de traduire ce tutoriel.

Merci à LittleWhite pour sa relecture technique ainsi qu'à ClaudeLELOUP pour sa relecture orthographique.

(1)Nombre écrit en dur dans le code source d'un programme.