Bonjour,
après avoir tenté plusieurs recherches sur internet (sans grand succès malheureusement),
je souhaite solliciter humblement votre aide afin de palier à un soucis.
J'effectue actuellement un projet dans le cadre de mon DUT informatique,
et mon binôme et moi même avons choisi de développer un jeu sous Irrlicht.
Ça avance pas trop mal, mais un point que je n'ai pas résolu vient entacher tout ceci.
Lorsque je déplace mon personnage avec les touches Z,Q,S,D (au moyen de la classe eventReceiver),
ce dernier effectue une première transition/rotation, fige un court instant, joue l'animation (toujours sur place) puis
se décide enfin à avancer ou tourner.
Second soucis, lorsque je me déplace avec deux touches (exemple Z pour avancer et Q pour tourner à gauche), puis que j'en relâche une (dans le cas échéant Q) l'action de la touche qui reste pressée(donc Z) n'est plus effectuée.
J'ai beau avoir tourné ça dans tous les sens, je ne trouve pas de solution.
Si une âme charitable pouvait jeter un oeil à mon code, je lui en serais grandement reconnaissant !
Mon main
#include <irr/irrlicht.h>
#include "Multijoueurs.h"
using namespace std;
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace gui;
int main()
{
gui::IGUIEnvironment *gui;
//Indique si le bouton jouer à été pressé
bool jouer=false;
//Indique si on joue en solo
bool solo=false;
//Indique si on joue en multijoueurs
bool multijoueurs=false;
//Indique si le bouton lancer serveur à été pressé
bool lancerServeur=false;
//Instance d'une partie en mode multijoueurs
Multijoueurs * modeMulti;
//Initialisation de la scene
IrrlichtDevice *device = createDevice(
video::EDT_OPENGL, // API OpenGL
core::dimension2d<u32>(800,600), // Dimension Fenetre
32, false, true, false, 0); // 2^32 valeur par pixel / plein écran / Stencil buffers / Synchronisation verticale / capteur d'évènement
video::IVideoDriver *driver = device->getVideoDriver(); //Gère le rendu
scene::ISceneManager *sceneManager = device->getSceneManager(); //Initialise la scène
sceneManager->setAmbientLight(irr::video::SColorf(1.f,1.f,1.f,1.f)); //Definie la lumiere ambiante
monEventReceiver * eventRec = new monEventReceiver(device);//Crée un capteur d'événements
device->setEventReceiver(/*&*/eventRec);//Definie le capteur d'événements de la scene
device->getCursorControl()->setVisible(false);//Masque le curseur
device->setWindowCaption(L"Secret of template fantasy 2 : Back to the future of Template's life bis");//Definie le titre de la fenêtre
/* MENU INITIALE */
gui = sceneManager->getGUIEnvironment();
video::ITexture *image = driver->getTexture("Textures/triforce.bmp");
gui::IGUIButton *boutonJouer = gui->addButton(rect<irr::s32>(200,340,600,365),0,-1,L"Jouer");
gui::IGUIButton *boutonMultijoueurs = gui->addButton(rect<irr::s32>(200,370,600,395),0,-1,L"Multijoueurs");
gui::IGUIButton *boutonServeur = gui->addButton(rect<irr::s32>(200,400,600,425),0,-1,L"Lancer serveur");
gui::IGUIButton *boutonQuitter = gui->addButton(rect<irr::s32>(200,430,600,455),0,-1,L"Quitter");
/**/while(device->run()) // Tant qu'on ne ferme pas l'appli /**/
{
driver->beginScene(true,true,video::SColor(0,255,255,255)); // On definit la couleur du fond de scene
if (jouer)//Si on a sélectionné l'option "jouer"
{
if(eventRec->IsKeyDown(irr::KEY_ESCAPE)){
jouer = false;
if(multijoueurs){
multijoueurs = false;
modeMulti->fermerConnexion();
}else{
solo = false;
}
}
if(multijoueurs){
modeMulti->routine();
if(modeMulti->getCamera()) modeMulti->getCamera()->Update();//Mise à jour de la position de la camera
}
if(solo){
}
sceneManager->drawAll();//S'occupe du rendu géré par le scène manager
}else{
device->getCursorControl()->setVisible(true);//On affiche le curseur
//On genere un menu
driver->draw2DImage(image,position2d<irr::s32>(0,0),rect<irr::s32>(0,0,800,600), 0, video::SColor(255,255,255,255), true);
gui->drawAll();//On rafraichit l'image
if (boutonJouer->isPressed())//Si le bouton jouer est appuyé
{
jouer=true;//Jouer passe à vrai
}
if(boutonMultijoueurs->isPressed()){
if(multijoueurs == false){
modeMulti = new Multijoueurs(sceneManager,driver,device,eventRec);
multijoueurs = true;
jouer = true;
}
}
if(boutonServeur->isPressed()){
if(lancerServeur == false){
system("start ../../serveur/Debug/serveur.exe");
lancerServeur = true;
}
}
if (boutonQuitter->isPressed())//Si le bouton quitter est appuyé
{
device->closeDevice();//On ferme la fenêtre
}
}
driver->endScene(); //Affiche le rendu
}
device->drop(); //On libère la memoire
return 0;
}
Ma classe Multijoueurs (où la scène se déroule)
#include "Multijoueurs.h"
Multijoueurs::Multijoueurs(scene::ISceneManager *pSceneManager,video::IVideoDriver *pDriver,IrrlichtDevice *pDevice, monEventReceiver * pEventRec)
{
mSceneManager = pSceneManager;
//Port
this->portServeur = 10000;
//Notre ID
this->my_ID_Joueur = -1;
//ID des autres joueurs
this->un_ID_Joueur = 0;
//Indique si notre personnage marche
this->je_marche = false;
//Indique si un autre personnage marche
this->il_marche = false;
//Ces deux variables permettront de calculer le laps de temps ecoulé entre deux envois de messages
this->tempsActuel = clock();
this->tempsEcouler = clock();
//Création de l'interface serveur
this->client = RakNet::RakPeerInterface::GetInstance();
//Creation d'un packet
this->packet = NULL;
this->mDriver = pDriver;
this->mDevice = pDevice;
eventRec = pEventRec;
//Saisie de l'adresse du serveur
printf("Entrez l'adresse IP du serveur :");
scanf("%s", this->IP_serveur);
connexionAuServeur();
initialisationNiveau();
initialisationPersonnages();
initialisationEclairage();
initialisationCiel();
attenteConnexion();
}
/*************************************************************************************/
Multijoueurs::~Multijoueurs(void)
{
RakNet::RakPeerInterface::DestroyInstance(client);//On detruit le client
}
/*************************************************************************************/
void Multijoueurs::connexionAuServeur(){
//Demarrage du client
this->client->Startup(1,&RakNet::SocketDescriptor(), 1);
this->client->Connect(IP_serveur, portServeur, 0,0);
}
/*************************************************************************************/
void Multijoueurs::initialisationNiveau(){
map = new Carte(mSceneManager,mDriver,"Textures/terrain_heightmap.bmp","Textures/grass.jpg","terrain",core::vector3df(40.f, 4.4f, 40.f));
}
/*************************************************************************************/
void Multijoueurs::initialisationPersonnages(){
for(int i = 0; i < JOUEURS_MAX;i++){
sydney[i] = new Personnages("Textures/sydney.md2","Textures/sydney.bmp",mSceneManager,mDevice,5900,100,6975);
selector = mSceneManager->createOctreeTriangleSelector(sydney[i]->getPersonnage()->getMesh(),map->getCarte(), 128);//Definition des contraintes
//du selector (mesh de l'élément) qui entrera en collision //definition du node avec lequel le mesh entrera en collision
map->getCarte()->setTriangleSelector(selector);
sydney[i]->getPersonnage()->setVisible(false);
selector->drop();
}
}
/*************************************************************************************/
void Multijoueurs::attenteConnexion(){
// On fait une boucle pour la connexion, ici on va attendre de savoir si la connection
// au serveur est OK ou non et attendre de recevoir un ID envoyer par le serveur
// on continue cette boucle temps que notre ID est inferieur à 0.
do
{
packet = client->Receive();
if(packet != NULL)// si oui
{
unsigned char packetID;
//creation de data que l'on est pret a recevoir
RakNet::BitStream dataStream(packet->data, packet->length, false);
// on commence par lire l'ID du paquet que l'on vient de recevoir
dataStream.Read(packetID);
switch(packetID)
{
case ID_CONNECTION_REQUEST_ACCEPTED:
printf("La connexion au serveur a bien ete acceptee\
");
break;
case ID_CONNECTION_ATTEMPT_FAILED:
//on reçois cet ID automatiquement si on arrive pas a ce connecter au serveur
printf("La connexion au serveur a echoue !!!\
");
break;
//le packet qui nous donne notre ID joueur
case PACKET_ID_ID_JOUEUR:
dataStream.Read(my_ID_Joueur);
printf("Reception de l'ID: %d\
", my_ID_Joueur);
sydney[my_ID_Joueur]->getPersonnage()->setVisible(true);
sydney[my_ID_Joueur]->getPersonnage()->setName("joueur");
sydney[my_ID_Joueur]->getPersonnage()->setPosition(vector3df(5900,100,6975));
mCamera = new FollowingCamera(sydney[my_ID_Joueur]->getPersonnage(), mSceneManager,//Creation de la camera
false, // Pour utiliser une position initiale.
selector, // Pour les collisions.
100, // Distance.
50, // Hauteur.
30, // Delta cible.
vector3df(-50,200,-120)); // Position initiale.
mSceneManager->setActiveCamera( mCamera->getCam() );
break;
}
}
}while(my_ID_Joueur < 0);//c'est que l'on a bien reçu notre ID
}
/*************************************************************************************/
void Multijoueurs::routine(){
/*RESEAU*/
//on verifie si on a reçu un packet
packet = client->Receive();
if(packet != NULL)// si oui
{
unsigned char packetID;
//creation de data que l'on est pret a recevoir
RakNet::BitStream dataStream(packet->data, packet->length, false);
// on commence par lire l'ID du paquet que l'on vient de recevoir
dataStream.Read(packetID);
switch(packetID)
{
//un packet qui indique la position des joueurs
case PACKET_ID_DEPLACEMENT:
dataStream.Read(un_ID_Joueur);//on lit l'ID du joueur a qui correspond cette position
dataStream.Read(une_position);//on lit la position
dataStream.Read(une_rotation);//puis la rotation
//bien sur on n'effectue un changement sur la position du joueur
//seulement si c'est pas le notre
if(un_ID_Joueur != my_ID_Joueur)
{ //on place le joueur et on le tourne par rapport au valeur reçu precedement
sydney[un_ID_Joueur]->getPersonnage()->setPosition(une_position);
sydney[un_ID_Joueur]->getPersonnage()->setRotation(une_rotation);
}
break;
//un packet qui indique l'animation des autres joueurs
case PACKET_ID_ANIMATION:
dataStream.Read(un_ID_Joueur);//on lit l'ID du joueur a qui correspond cette position
if(un_ID_Joueur != my_ID_Joueur){
dataStream.Read(il_marche);//on lit si il marche
if(il_marche)
{
sydney[un_ID_Joueur]->getPersonnage()->setMD2Animation(EMAT_RUN);
if(!sydney[un_ID_Joueur]->getPersonnage()->isVisible()){
sydney[un_ID_Joueur]->getPersonnage()->setVisible(true);
}
}
else
{
sydney[un_ID_Joueur]->getPersonnage()->setMD2Animation(EMAT_STAND);
}}
break;
default:
// si on l'ID d'un paquet que l'on a pas referencer on le dit
//ceci n'est pas forcement un probleme !
printf("Reception d'un packet avec un ID inconnu: %i\
", int(packetID));
}
client->DeallocatePacket(packet);//on vide le packet
}
//Si on presse la touche Z ou la touche S
if(eventRec->IsKeyDown(irr::KEY_KEY_Z) || eventRec->IsKeyDown(irr::KEY_KEY_S))
{
//Si l'animation de marche n'etait pas activée
if(!je_marche)
{ //On indique que l'animation est lancée
je_marche = true;
//On envoie un message au serveur pour indiquer qu'on joue l'animation
RakNet::BitStream data;
data.Write(PACKET_ID_ANIMATION);//On indique que c'est une animation
data.Write(my_ID_Joueur);//On ecrit notre ID afin que le serveur sache de qui il s'agit
data.Write(je_marche);//On indique l'etat de l'animation de marche
//On envoie le message au serveur
client->Send(&data, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, RakNet::UNASSIGNED_SYSTEM_ADDRESS, true);
//On detruit l'instance data
data.DestroyInstance;
}
}
else//Si l'on appuie ni sur Z ni sur S
{
//Si l'animation marche est activée
if(je_marche)
{
//On indique que l'animation à cessé
je_marche = false;
//On envoie un message au serveur pour indiquer qu'on ne joue plus l'animation
RakNet::BitStream data;
data.Write(PACKET_ID_ANIMATION);//On indique que c'est une animation
data.Write(my_ID_Joueur);//On ecrit notre ID afin que le serveur sache de qui il s'agit
data.Write(je_marche);//On indique l'etat de l'animation de marche
//On envoie le message au serveur
client->Send(&data, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, RakNet::UNASSIGNED_SYSTEM_ADDRESS, true);
//On detruit l'instance data
data.DestroyInstance;
}
}
tempsEcouler = clock();//Mise a jour du temps ecoulé
if(tempsEcouler - tempsActuel > 30)//Si plus de 30 ms se sont ecoulées
{
RakNet::BitStream data;
data.Write(PACKET_ID_DEPLACEMENT);//On indique que c'est une animation
data.Write(my_ID_Joueur);//On ecrit notre ID afin que le serveur sache de qui il s'agit
une_position = sydney[my_ID_Joueur]->getPersonnage()->getAbsolutePosition();//On recupere notre position
data.Write(une_position);//On l'ecrit dans le packet
une_rotation = sydney[my_ID_Joueur]->getPersonnage()->getRotation();//On recupere notre rotation
//On remet la rotation des axes X et Z a zéro afin de ne pas avoir un personnage dans des positions incoherentes
une_rotation.X = 0;
une_rotation.Z = 0;
data.Write(une_rotation);//On ecrit la rotation dans le packet
//On envoie le message au serveur
client->Send(&data, HIGH_PRIORITY, RELIABLE_ORDERED, 0, RakNet::UNASSIGNED_SYSTEM_ADDRESS, true);
tempsActuel = clock();//On met le temps a jour
}
}
/*************************************************************************************/
void Multijoueurs::initialisationCiel(){
mSky = mSceneManager->addSkyBoxSceneNode(mDriver->getTexture("Textures/irrlicht2_up.jpg"),
mDriver->getTexture("Textures/irrlicht2_dn.jpg"),
mDriver->getTexture("Textures/irrlicht2_lf.jpg"),
mDriver->getTexture("Textures/irrlicht2_rt.jpg"),
mDriver->getTexture("Textures/irrlicht2_ft.jpg"),
mDriver->getTexture("Textures/irrlicht2_bk.jpg"));
}
/*************************************************************************************/
void Multijoueurs::initialisationEclairage(){
mSceneManager->setAmbientLight(irr::video::SColorf(0.5f,0.5f,0.5f,1.0f));
// On crée une lumière diffuse
scene::ILightSceneNode* sun = mSceneManager->addLightSceneNode();
// On specifie la distance que peut atteindre cette lumière
sun->setRadius(100000);
// On specifie la position de la lumière dans la scene
sun->setPosition(core::vector3df(8000, 2000, 8000));
}
/*************************************************************************************/
FollowingCamera* Multijoueurs::getCamera(){
return mCamera;
}
/*************************************************************************************/
void Multijoueurs::fermerConnexion(){
client->CloseConnection(client->GetSystemAddressFromIndex(0),true,0,HIGH_PRIORITY);
}
Ma classe eventReceiver
#include "monEventReceiver.h"
float PI=3.14;
monEventReceiver::monEventReceiver(IrrlichtDevice* device)
{
mDevice = device;
for(int i=0; i<irr::KEY_KEY_CODES_COUNT; i++)
//mKeyState[i] = false;
keyMap[i] = false;
courseActive = false;
}
bool monEventReceiver::OnEvent(const SEvent& event)
{
if (event.EventType == irr::EET_KEY_INPUT_EVENT) {
keyMap[event.KeyInput.Key] = event.KeyInput.PressedDown;
OnPreRender();
return event.KeyInput.PressedDown;
}else{
return false;
}
}
void monEventReceiver::OnPreRender(){
bool retourActionOriginale = true;
core::vector3df positionPersonnage;
core::vector3df rotationPersonnage;
scene::ISceneManager* smgr = mDevice->getSceneManager();
scene::IAnimatedMeshSceneNode* joueur = (scene::IAnimatedMeshSceneNode*)smgr->getSceneNodeFromName("joueur");
scene::ITerrainSceneNode* terrain = (scene::ITerrainSceneNode*)smgr->getSceneNodeFromName("terrain");
if(keyMap[KEY_ESCAPE]){
//mDevice->closeDevice();
}
if (keyMap[irr::KEY_KEY_Z]){//Avancer
facing.set( -cos( joueur->getRotation().Y * PI/180.0f ), 0, sin( joueur->getRotation().Y * PI/180.0f ) );
facing.normalize();
positionPersonnage = joueur->getPosition() - (facing*5.0f) ;
positionPersonnage.Y = terrain->getHeight(positionPersonnage.X,positionPersonnage.Z) + 24;
joueur->setPosition( positionPersonnage );
if(!this->courseActive){
joueur->setMD2Animation(scene::EMAT_RUN);
this->courseActive = true;
}
}
if (keyMap[irr::KEY_KEY_S]){//Reculer
facing.set( cos( joueur->getRotation().Y * PI/180.0f ), 0, -sin( joueur->getRotation().Y * PI/180.0f ) );
facing.normalize();
positionPersonnage = joueur->getPosition() - (facing*5.0f) ;
positionPersonnage.Y = terrain->getHeight(positionPersonnage.X,positionPersonnage.Z) + 24;
joueur->setPosition( positionPersonnage );
if(!this->courseActive){
joueur->setMD2Animation(scene::EMAT_RUN);
this->courseActive = true;
}
}
if (keyMap[irr::KEY_KEY_Q]){//Rotation à gauche
joueur->setRotation(joueur->getRotation() + core::vector3df(0.0f,-5.0f,0.0f));
if(rotationPersonnage.Y >= 360){
rotationPersonnage.Y -= 360;
joueur->setRotation(rotationPersonnage);
}
}
if (keyMap[irr::KEY_KEY_D]){//Rotation à droite
joueur->setRotation(joueur->getRotation() + core::vector3df(0.0f,5.0f,0.0f));
if(rotationPersonnage.Y >= 360){
rotationPersonnage.Y -= 360;
joueur->setRotation(rotationPersonnage);
}
}
if((!keyMap[irr::KEY_KEY_S])&&(!keyMap[irr::KEY_KEY_Z])){
if(courseActive == true){
joueur->setMD2Animation(scene::EMAT_STAND);
this->courseActive = false;}
}
}
bool monEventReceiver::IsKeyDown(EKEY_CODE keyCode) const
{
return keyMap[keyCode];
}
Merci beaucoup par avance

.