Bonjour ,
Je suis en train de développer en mini FPS et j'ai un problème avec la fonction "s'accroupir" , je ne sais pas comment m'y prendre . J'ai essayé createFlyStraightAnimator mais apparemment ça ne marche pas . Est-ce que vous pouvez me mettre sur la piste ?
Merci d'avance
Hors ligne
Comme ça, je dirais qu'il faut capter l'événement du bouton affecté à la fonction "s'accroupir". Je suppose que tu as mis un animator de collision donc il faut voir s'il y a possibilité de modifier la collision en hauteur. La solution la plus propre serait de créer ta propre cameraFPS en reprenant le code d'irrlicht et en y ajoutant la création de la collision à la création de la camera et la fonction "s'accroupir" dans la KeyMap et en implémentant l'action associée. L'implémentation de la camera est dans "source/CSceneNodeAnimatorCameraFPS.cpp". Pour la keymap et l'enum KEY_ACTION, c'est dans "include/SKeyMap.h". Soit tu modifies le code source d'Irrlicht (ce que je ne ferais pas car c'est à refaire si tu changes de version entre temps), soit tu copies (en changeant les noms de fichier, de classe et d'enum) les fichiers "source/CSceneNodeAnimatorCameraFPS.cpp et .h" et "include/SKeyMap.h".
1/ ajouter EKA_ACCROUPIR à EKEY_ACTION;
2/ ajouter dans le constructeur "KeyMap.push_back(SKeyMap(EKA_ACCROUPIR, irr::KEY_LSHIFT));" (j'ai mis LSHIFT pour l'exemple mais tu mets ce que tu veux);
3/ dans "CSceneNodeAnimatorCameraFPS::animateNode(...)" tu as :
if (CursorKeys[EKA_JUMP_UP]) { const ISceneNodeAnimatorList& animators = camera->getAnimators(); ISceneNodeAnimatorList::ConstIterator it = animators.begin(); while(it != animators.end()) { if(ESNAT_COLLISION_RESPONSE == (*it)->getType()) { ISceneNodeAnimatorCollisionResponse * collisionResponse = static_cast<ISceneNodeAnimatorCollisionResponse *>(*it); if(!collisionResponse->isFalling()) collisionResponse->jump(JumpSpeed); } it++; } }
Inspires t'en pour pour savoir comment accéder à l'animateur de collision et implémenter :
if (CursorKeys[EKA_ACCROUPIR])
{
/// change la hauteur de l'ellipse avec ISceneNodeAnimatorCollisionResponse::setEllipsoidTranslation();
}
J'espère avoir été assez clair, je viens juste de regarder les sources donc c'est plus une piste qu'une solution. En tout cas, le principe est là.
Hors ligne
Salut
Merci pour ta réponse rapide et clair , je m'y met tout de suite
Par contre je ne comprends pas quand tu dis de changer la hauteur de l'ellipse avec ISceneNodeAnimatorCollisionResponse::setEllipsoidTranslation(); , pourrais tu plus m'éclairer à ce sujet ? C'est avec ça qu'on pourra s'accroupir ?
Merci d'avance
Hors ligne
Comme le nom de la fonction l'indique, elle sert à faire translater l'animateur de collision. Si tu changes la valeur de Y dans setEllipsoidTranslation( vector3df(X, Y, Z) ), tu vas faire "coulisser" la collision selon Y et donc ta camera se lèvera ou s'abaissera en conséquence. Maintenant, je n'ai pas essayé donc je ne peux te le garantir mais je pense que ça marchera correctement.
Pour mieux expliquer :
Tu prends setEllipsoidRadius(vector3df(30, 20, 30)).
Si tu as : setEllipsoidTranslation( vector3df(0, 0, 0) ) ton node camera est à 30 du sol (EllipsoidRadius : X et Z donne la hauteur et Y le tour du personnage)
maintenant si tu as : setEllipsoidTranslation( vector3df(0, -50, 0) ) ton node camera est à 30 + 50 du sol car tu as translater de 50 vers le bas ta collision qui a elle-même un rayon de 30 donc ton node est maintenant à 80 du sol.
En fait quand tu décales ta collision ta caméra n'est plus au centre de la collision donc faire aussi attention au comportement.
D'ailleurs utilise plutôt setEllipsoidRadius et tu modifies X et Z en même temps et avec les mêmes valeurs pour modifier la hauteur de collision.
D'ailleurs faut aussi prévoir une fonction pour le remettre debout ton joueur^^.
Dernière modification par johnplayer (03-07-2012 22:12:56)
Hors ligne
Salut
Merci pour ces précisions , je comprend mieux comment ça marche à présent . Pour l'instant j'ai décidé de recompiler Irrlicht pour changer le code source mais je me retrouve confronté a un autre problème , quand je déclare dans le main :
keyMap[10].Action = irr::EKA_ACCROUPIR;
keyMap[10].KeyCode = irr::KEY_LSHIFT;
Et que je compile , Code::Blocks me met comme erreur : error : 'EKA_ACCROUPIR' is not member of 'irr' .
J'ai bien pris le soin de tout recompiler Irrlicht et de reprendre la bilbiothèque statique dans le SDK/lib
Je ne sais pas comment y remédiez , Merci d'avance
Cordialement.
Hors ligne
As-tu déclaré EKA_ACCROUPIR dans l'enum EKEY_ACTION?
Dans include/SKeyMap.h, tu dois avoir :
// Copyright (C) 2002-2011 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h #ifndef __S_KEY_MAP_H_INCLUDED__ #define __S_KEY_MAP_H_INCLUDED__ #include "Keycodes.h" namespace irr { //! enumeration for key actions. Used for example in the FPS Camera. enum EKEY_ACTION { EKA_MOVE_FORWARD = 0, EKA_MOVE_BACKWARD, EKA_STRAFE_LEFT, EKA_STRAFE_RIGHT, EKA_JUMP_UP, EKA_CROUCH, EKA_ACCROUPIR, ///////////////////////////////////////////////// LIGNE A AJOUTER ABSOLUMENT AVANT EKA_COUNT EKA_COUNT, //! This value is not used. It only forces this enumeration to compile in 32 bit. EKA_FORCE_32BIT = 0x7fffffff }; //! Struct storing which key belongs to which action. struct SKeyMap { SKeyMap() {} SKeyMap(EKEY_ACTION action, EKEY_CODE keyCode) : Action(action), KeyCode(keyCode) {} EKEY_ACTION Action; EKEY_CODE KeyCode; }; } // end namespace irr #endif
J'ai marqué la ligne que tu es censé avoir ajoutée avec "///////////////////////////////////////////////// LIGNE A AJOUTER ABSOLUMENT AVANT EKA_COUNT".
Hors ligne
Oui ,j'ai bien rajouter la ligne EKA_ACCROUPIR juste avant EKA_COUNT et ça me met la même erreur , bizarre c'est peut être un problème de lib ou je ne sais quoi oO
Hors ligne
J'allais te dire une connerie^^. Je ne vois pas de quoi ça peut venir. Essai de remplacer EKA_ACCROUPIR par EKA_MOVE_FORWARD pour voir, toujours en gardant le irr:: bien sûr.
Au fait, j'avais pas vu mais tu mets "keyMap[10].Action = irr::EKA_ACCROUPIR; keyMap[10].KeyCode = irr::KEY_LSHIFT; " dans le main?! Tant qu'à modifier les sources mets ton code dans "CSceneNodeAnimatorCameraFPS.cpp".
Dans "CSceneNodeAnimatorCameraFPS.cpp", tu as :
// create key map if (!keyMapArray || !keyMapSize) { // create default key map KeyMap.push_back(SKeyMap(EKA_MOVE_FORWARD, irr::KEY_UP)); KeyMap.push_back(SKeyMap(EKA_MOVE_BACKWARD, irr::KEY_DOWN)); KeyMap.push_back(SKeyMap(EKA_STRAFE_LEFT, irr::KEY_LEFT)); KeyMap.push_back(SKeyMap(EKA_STRAFE_RIGHT, irr::KEY_RIGHT)); KeyMap.push_back(SKeyMap(EKA_JUMP_UP, irr::KEY_KEY_J)); KeyMap.push_back(SKeyMap(EKA_ACCROUPIR, irr::KEY_LSHIFT)); ////////////// c'est ici qu'il faut ajouter la ligne }
Toutes les modifications que tu veux apporter à la caméra seront dans "CSceneNodeAnimatorCameraFPS.h" et "CSceneNodeAnimatorCameraFPS.cpp".
Dernière modification par johnplayer (06-07-2012 20:40:44)
Hors ligne
Oui j'ai déjà mis cette ligne ( KeyMap.push_back(SKeyMap(EKA_ACCROUPIR, irr::KEY_LSHIFT)); ) tu me la dis dans ton premier post et j'avais déjà EKA_MOVE_FORWARD ça marchait . Moi je pense plutôt que le projet ne tiens pas compte de la modification du code source d'Irrlicht , après je sais pas trop faut voir ^^
Dernière modification par jeandu65200 (06-07-2012 20:49:20)
Hors ligne
Quand tu créés ta camera, tu fais comment? Tu créés une KeyMap? Mets ton code que je puisse voir parce que il y a quelque chose que je ne saisis pas.
Et au fait, tu compiles en statique ou tu utilises la dll. Si tu utilises la dll, faut voir si ton projet utilise bien la dernière dll que tu as compilé.
Dernière modification par johnplayer (06-07-2012 21:28:02)
Hors ligne
Salut n'arrivant pas à intégrer la modification du code source , j'ai décidé de le mettre directement dans mon code dans une classe hérité de ICameraSceneNode , que j'appelle dans l'event receiver lorsque la touche CTRL est appuyé .
Voila donc comment j'ai procédé :
Au fait les déclarations de it et de collisionResponse sont dans la déclaration de la classe . Lorsque j'appuie sur la touche CTRL , j'ai bien la caméra qui s'accroupit mais j'ai un autre problème : la caméra ne peut plus bouger , elle ne peut que sauter , je n'arrive pas à y remédier
Merci d'avance.
PS : Quand j'appelle setEllipsoidTranslation() , le programme cesse de fonctionner , bizarre oO
Dernière modification par jeandu65200 (07-07-2012 23:28:52)
Hors ligne
Tu prends tout les animators comme des collision reponse, il faudrait peut-être prendre : ISceneNodeAnimator::getType() et le comparé à (irr::scene::ESCENE_NODE_ANIMATOR_TYPE) ESNAT_COLLISION_RESPONSE. Ainsi, tu ne modifies que l'animator concerné par la modif.
Pas besoin de créer une classe pour ce que tu veux faire.
/// création de la caméra ISceneNodeAnimatorCameraFPS *camera = smgr->addCameraSceneNodeFPS(...); /// création du selector /*je te laisse le faire*/ /// création de la collision irr::scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator( selector, camera, irr::core::vector3df(50,20,50), irr::core::vector3df(0,0,0), irr::core::vector3df(0,30,0)); selector->drop(); camera->addAnimator(anim); anim->drop(); /// dans OnEvent(const SEvent& event) if (event.EventType == EET_KEY_INPUT_EVENT) { if(event.KeyInput.PressedDown) if(event.KeyInput.Key == KEY_LCONTROL ) { const irr::scene::ISceneNodeAnimatorList& animatorCamera = camera->getAnimators(); it = animatorCamera.begin(); while(it != animatorCamera.end()) { if( it->getType() == ESNAT_COLLISION_RESPONSE) /// on ne s'intéresse qu'à l'AnimatorCollisionResponse { collisionResponse = static_cast<irr::scene::ISceneNodeAnimatorCollisionResponse *>(*it); if(!collisionResponse->isFalling()) collisionResponse->setEllipsoidRadius(irr::core::vector3df(30, 20, 30)); /// se baisse } it++; } return true; } else { const irr::scene::ISceneNodeAnimatorList& animatorCamera = camera->getAnimators(); it = animatorCamera.begin(); while(it != animatorCamera.end()) { if( it->getType() == ESNAT_COLLISION_RESPONSE) /// on ne s'intéresse qu'à l'AnimatorCollisionResponse { collisionResponse = static_cast<irr::scene::ISceneNodeAnimatorCollisionResponse *>(*it); if(!collisionResponse->isFalling()) collisionResponse->setEllipsoidRadius(irr::core::vector3df(50, 20, 50));/// se relève } it++; } return true; } }
Bon après comme tu le vois, il y a répétition du code donc une fonction te permettrait de ne pas avoir à appeler ta camera dans le OnEvent :
bool modifyEllipsoidRadius(irr::core::vector3df newradius) { const irr::scene::ISceneNodeAnimatorList& animatorCamera = camera->getAnimators(); it = animatorCamera.begin(); while(it != animatorCamera.end()) { if( it->getType() == irr::scene::ESNAT_COLLISION_RESPONSE) { collisionResponse = static_cast<irr::scene::ISceneNodeAnimatorCollisionResponse *>(*it); if(!collisionResponse->isFalling()) collisionResponse->setEllipsoidRadius(newradius); } it++; } return true; }
Il y a certainement des erreurs, je suis à moitié endormi ^^, je n'ai pas essayé le code parce que je l'ai tapé directement dans mon post. Donc je te laisses corriger.
Hors ligne