Tutoriel Irrlicht 19

Souris et manettes de jeux

| Nikolaus Gebhart | Alexandre Laurent |

Traducteur

Neckara

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

Il est basé sur le quatrième exemple : Mouvement qui montrait comment gérer les événements claviers avec Irrlicht. Maintenant, nous allons nous occuper des événements de la souris et des manettes de jeux, si vous avez une manette de jeux connectée et un moteur qui supporte les manettes de jeux tels que les moteurs Windows, Linux et SDL.

Commentez

- Titre : Tutoriel Irrlicht 19

- Auteurs : Nikolaus Gebhart, Alexandre Laurent

- Traducteur : Neckara

- Parution : 18 juin 2013

- Mise à jour : 18 juin 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. Prérequis

- II. Obtention des informations sur le joystick

- III. Traitement des événements

- IV. Conclusion

- V. Remerciements

I - Prérequis

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

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

using namespace irr;

Tout comme nous l'avons fait dans l'exemple 4 : Mouvement, nous stockons l'état de la souris et de la première manette et les mettons à jour quand nous recevons des événements.

class MyEventReceiver : public IEventReceiver
{
public:
// Nous créons une structure pour enregistrer les informations sur l'état de la souris.
struct SMouseState
{
core::position2di Position;
bool LeftButtonDown;
SMouseState() : LeftButtonDown(false) { }
} MouseState;

// Ceci est la méthode que nous devons implémenter.
virtual bool OnEvent(const SEvent& event)
{
// Se rappelle de l'état de la souris.
if (event.EventType == irr::EET_MOUSE_INPUT_EVENT)
{
switch(event.MouseInput.Event)
{
case EMIE_LMOUSE_PRESSED_DOWN:
MouseState.LeftButtonDown = true;
break;

case EMIE_LMOUSE_LEFT_UP:
MouseState.LeftButtonDown = false;
break;

case EMIE_MOUSE_MOVED:
MouseState.Position.X = event.MouseInput.X;
MouseState.Position.Y = event.MouseInput.Y;
break;

default:
// Nous n'utiliserons pas la roulette.
break;
}
}

// L'état de chaque manette connectée nous est envoyé
// à chaque run() du moteur irrlicht. Stockons l'état
// de la première manette, et ignorons les autres.
// Ceci n'est actuellement supporté que sous Windows et Linux.
if (event.EventType == irr::EET_JOYSTICK_INPUT_EVENT
&& event.JoystickEvent.Joystick == 0)
{
JoystickState = event.JoystickEvent;
}

return false;
}

const SEvent::SJoystickEvent & GetJoystickState(void) const
{
return JoystickState;
}

const SMouseState & GetMouseState(void) const
{
return MouseState;
}

MyEventReceiver()
{
}

private:
SEvent::SJoystickEvent JoystickState;
};

II - Obtention des informations sur le joystick

Le receveur d'événements est prêt pour conserver les touches pressées, la réponse actuelle sera faite dans la boucle de rendu, juste avant de dessiner la scène. Donc créons juste un irr::IrrlichtDevice ainsi que le nœud de scène que nous voulons déplacer. Nous créons aussi d'autres nœuds de scènes supplémentaires, pour montrer qu'il y a aussi d'autres façons de déplacer et d'animer des nœuds de scènes.

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

// Crée le moteur.
MyEventReceiver receiver;

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

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

core::array<SJoystickInfo> joystickInfo;
if(device->activateJoysticks(joystickInfo))
{
std::cout << "Joystick support is enabled and " << joystickInfo.size() << " joystick(s) are present." << std::endl;

for(u32 joystick = 0; joystick < joystickInfo.size(); ++joystick)
{
std::cout << "Joystick " << joystick << ":" << std::endl;
std::cout << "\tName: '" << joystickInfo[joystick].Name.c_str() << "'" << std::endl;
std::cout << "\tAxes: " << joystickInfo[joystick].Axes << std::endl;
std::cout << "\tButtons: " << joystickInfo[joystick].Buttons << std::endl;

std::cout << "\tHat is: ";

switch(joystickInfo[joystick].PovHat)
{
case SJoystickInfo::POV_HAT_PRESENT:
std::cout << "present" << std::endl;
break;

case SJoystickInfo::POV_HAT_ABSENT:
std::cout << "absent" << std::endl;
break;

case SJoystickInfo::POV_HAT_UNKNOWN:
default:
std::cout << "unknown" << std::endl;
break;
}
}
}
else
{
std::cout << "Joystick support is not enabled." << std::endl;
}

core::stringw tmp = L"Irrlicht Joystick Example (";
tmp += joystickInfo.size();
tmp += " joysticks)";
device->setWindowCaption(tmp.c_str());

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

III - Traitement des événements

Nous créons un objet en forme de flèche et le déplaçons selon les axes/chapeaux de la manette, ou lui faisons suivre le curseur de la souris.

scene::ISceneNode * node = smgr->addMeshSceneNode(
smgr->addArrowMesh( "Arrow",
video::SColor(255, 255, 0, 0),
video::SColor(255, 0, 255, 0),
16,16,
2.f, 1.3f,
0.1f, 0.6f
)
);
node->setMaterialFlag(video::EMF_LIGHTING, false);

scene::ICameraSceneNode * camera = smgr->addCameraSceneNode();
camera->setPosition(core::vector3df(0, 0, -10));

// Comme dans l'exemple 04, nous allons utiliser un mouvement indépendant du nombre d'images par seconde.
u32 then = device->getTimer()->getTime();
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;

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

if(joystickInfo.size() > 0)
{
f32 moveHorizontal = 0.f; // La fourchette va de -1.f (tout à gauche) à 1.f (tout à droite).
f32 moveVertical = 0.f; // -1.f (tout en bas) à  +1.f (tout en haut).

const SEvent::SJoystickEvent & joystickData = receiver.GetJoystickState();

// Nous recevons une fourchette de valeur analogique complète des axes, et donc nous implémentons notre
// propre zone morte. Ceci est une valeur empirique, depuis que certaines manettes ont plus de gigue ou de glissement
// autour du point central que d'autres. Nous utiliserons 5 % de la fourchette comme zone morte,
// mais généralement, vous voudrez donner à l'utilisateur la possibilité de changer cela.
const f32 DEAD_ZONE = 0.05f;

moveHorizontal =
(f32)joystickData.Axis[SEvent::SJoystickEvent::AXIS_X] / 32767.f;
if(fabs(moveHorizontal) < DEAD_ZONE)
moveHorizontal = 0.f;

moveVertical =
(f32)joystickData.Axis[SEvent::SJoystickEvent::AXIS_Y] / -32767.f;
if(fabs(moveVertical) < DEAD_ZONE)
moveVertical = 0.f;

// L'information POV du chapeau est supportée uniquement par Windows, mais sa valeur
// sera obligatoirement 65535 lorsque non-supporté, donc nous pouvons la vérifier.
const u16 povDegrees = joystickData.POV / 100;
if(povDegrees < 360)
{
if(povDegrees > 0 && povDegrees < 180)
moveHorizontal = 1.f;
else if(povDegrees > 180)
moveHorizontal = -1.f;

if(povDegrees > 90 && povDegrees < 270)
moveVertical = -1.f;
else if(povDegrees > 270 || povDegrees < 90)
moveVertical = +1.f;
}

if(!core::equals(moveHorizontal, 0.f) || !core::equals(moveVertical, 0.f))
{
nodePosition.X += MOVEMENT_SPEED * frameDeltaTime * moveHorizontal;
nodePosition.Y += MOVEMENT_SPEED * frameDeltaTime * moveVertical;
movedWithJoystick = true;
}
}

// Si le nœud de la flèche n'est pas déplacé avec la manette, alors il suit le curseur de la souris.
if(!movedWithJoystick)
{
// Crée un rayon partant du curseur de la souris.
core::line3df ray = smgr->getSceneCollisionManager()->getRayFromScreenCoordinates(
receiver.GetMouseState().Position, camera);

// Ainsi qu'une intersection du rayon avec un plan proche d'un nœud faisant face à la caméra.
core::plane3df plane(nodePosition, core::vector3df(0, 0, -1));
core::vector3df mousePosition;
if(plane.getIntersectionWithLine(ray.start, ray.getVector(), mousePosition))
{
// Nous avons maintenant une position de souris dans un espace 3D; déplaçons-la autour.
core::vector3df toMousePosition(mousePosition - nodePosition);
const f32 availableMovement = MOVEMENT_SPEED * frameDeltaTime;

if(toMousePosition.getLength() <= availableMovement)
nodePosition = mousePosition; // Saute à la position finale
else
nodePosition += toMousePosition.normalize() * availableMovement; // Move towards it
}
}

node->setPosition(nodePosition);

// Active ou désactive l'éclairage selon que le bouton gauche de la souris est pressé ou non.
node->setMaterialFlag(video::EMF_LIGHTING, receiver.GetMouseState().LeftButtonDown);

driver->beginScene(true, true, video::SColor(255,113,113,133));
smgr->drawAll(); // Dessine la scène 3D.
driver->endScene();
}

À la fin, nous supprimons le moteur Irrlicht.

device->drop();

return 0;
}

IV - Conclusion

Vous pouvez désormais traiter les événements souris et de manettes avec Irrlicht.

Dans le prochain tutoriel Gestion de lumières, nous verrons comment utiliser le gestionnaire de lumières d'Irrlicht.

V - Remerciements

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

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