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.0
f);
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.