Accueil > > > Envi3D/Personnage.cpp
BASE/MOTEUR 3D EN QT/OPENGL (COMPLET ET FONCTIONNEL!) POUR UN TRÈS PROCHAIN JEU 3D
Envi3D/Personnage.cpp
Informations sur ce code source
Bonjour à tous,
Voici un moteur 3D gérant les textures tous formats (supporté par QT) et contient un loader de fichier .obj que j'ai écrit personnellement.
Il permet d'illustrer l'utilisation de deux QGLWidget en même temps et comment se servir de
Fichier : Envi3D/Personnage.cpp
Nombre de lignes : 539 lignes
Afficher ce fichier en plein écran
-
- #include "Personnage.h"
-
-
- #define AVANCER 0
- #define RECULER 1
- #define GAUCHE 2
- #define DROITE 3
- #define SAUT 4
- #define ACCROUPI 5
-
- #define ROTA_SUPP 0.1
- #define ROTA_SUPP_MAX 8
-
- ////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////
- //////////////////////////// CLASSE PERSONNAGE /////////////////////////////
- //////////////////////////////////HERITE DE OBJET///////////////////////////
- ////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////
-
-
- Personnage::Personnage(bool isVisible, Coord3D position, Coord3D cibleCamera, Coord3D orientation, bool possedeCollisionBox, Coord3D diagonaleCollisionBox, bool rotation90degCollisionBox, float vitesseJoueur, float sensivity, QString fichierMesh, QString fichierTexture, bool isTextureUVmap)
- : Objet(isVisible, position, orientation, possedeCollisionBox, diagonaleCollisionBox, rotation90degCollisionBox, "Personnage", fichierMesh, fichierTexture, isTextureUVmap)
- {
- //qDebug() << "Constructeur Personnage";
- _cibleCamera = cibleCamera;
-
- Mouvement[AVANCER] = false;
- Mouvement[RECULER] = false;
- Mouvement[GAUCHE] = false;
- Mouvement[DROITE] = false;
- Mouvement[SAUT] = false;
- Mouvement[ACCROUPI] = false;
-
- joueurAccroupi = false;
- saut.step = 0;//valeur de temps dans les equations horaires du mouvement, augmente de 25 a chaques etape pour finir a 1000, la fin du saut
- saut.enCollision = false;
-
- _vitesse = vitesseJoueur; //pour la vitesse de deplacement
- _sensivity = sensivity;
-
-
- _armeActive = false; //variables pour l'arme
- _rotationSupplementaire = 0;
- _tir = false;
- _etapeTir = 0;
- _munitions = 100;
- donneeArmeModifie=false;
- soundPlayed = false;
- //soundLoadArme = new QSound ("sounds/load_torpedo.wav");
- //soundTirArme = new QSound ("sounds/light_torpedo.wav");
- //QSound::play("sounds/light_torpedo.wav");
-
- _phi = 0;
- _theta = 0;
- ConversionVecteursVersAngles(); //calcul des angles phi et theta qui correspondent au _position et _targetCameraJoueur de début de jeu
-
- _up.X = 0; //vecteur definissant la verticale du monde
- _up.Y = 0;
- _up.Z = 1;
-
- }
-
-
-
- void Personnage::Animate(Objet *listeObjet[], int nombreObjets, int tailleTerrainX, int tailleTerrainY)
- {
- int i=0; //pour les tests de collision
- if (_position.X < 0) //pour ne pas sortir
- _position.X = 0;
- else if (_position.X > tailleTerrainX*4)
- _position.X = tailleTerrainX*4;
-
- if (_position.Y < 0)
- _position.Y = 0;
- else if (_position.Y > tailleTerrainY*4)
- _position.Y = tailleTerrainY*4;
-
-
- if (Mouvement[AVANCER])
- {
-
- _position.X += _forward.X * _vitesse;
- //debut test collision
- i=0;
- _collision = false;
- while (i<nombreObjets && _collision==false)
- {
- if (listeObjet[i]->getPossedeCollisionBox() == true) //on verifie qu'il a une box
- _collision = test_Collision(_position, _collisionBox, listeObjet[i]->getPosition(), listeObjet[i]->getCollisionBox());
- i++;
- }//Fin test collision
-
- if (_collision == true)
- {
- _position.X -= _forward.X * _vitesse;
- }
-
-
-
- _position.Y += _forward.Y * _vitesse;
- //debut test collision
- i=0;
- _collision = false;
- while (i<nombreObjets && _collision==false)
- {
- if (listeObjet[i]->getPossedeCollisionBox() == true)
- _collision = test_Collision(_position, _collisionBox, listeObjet[i]->getPosition(), listeObjet[i]->getCollisionBox());
- i++;
- }//Fin test collision
-
- if (_collision == true)
- {
- _position.Y -= _forward.Y * _vitesse;
- }
-
- }
- if (Mouvement[RECULER]) //volontairement pas de test de collision au recul, c'est tjrs util...
- {
- _position.X -= _forward.X * _vitesse;
- _position.Y -= _forward.Y * _vitesse;
- }
- if (Mouvement[GAUCHE])
- {
- _position += _left * _vitesse;
- //debut test collision
- i=0;
- _collision = false;
- while (i<nombreObjets && _collision==false)
- {
- if (listeObjet[i]->getPossedeCollisionBox() == true) //on verifie qu'il a une box
- _collision = test_Collision(_position, _collisionBox, listeObjet[i]->getPosition(), listeObjet[i]->getCollisionBox());
- i++;
- }//Fin test collision
-
- if (_collision == true)
- {
- _position -= _left * _vitesse;
- }
- }
- if (Mouvement[DROITE])
- {
- _position -= _left * _vitesse;
- //debut test collision
- i=0;
- _collision = false;
- while (i<nombreObjets && _collision==false)
- {
- if (listeObjet[i]->getPossedeCollisionBox() == true) //on verifie qu'il a une box
- _collision = test_Collision(_position, _collisionBox, listeObjet[i]->getPosition(), listeObjet[i]->getCollisionBox());
- i++;
- }//Fin test collision
- if (_collision == true)
- {
- _position += _left * _vitesse;
- }
- }
-
-
- if (Mouvement[ACCROUPI] == true)
- {
- if ((joueurAccroupi == false) && (Mouvement[SAUT] == false))
- {
- _position.Z -= 2;
- joueurAccroupi = true;
- }
- }
-
- if (Mouvement[ACCROUPI] == false)
- {
- if (joueurAccroupi == true)
- {
- _position.Z += 2;
- joueurAccroupi = false;
- }
- }
-
- ////////////////////////////GESTION DU SAUT////////////////////////////
-
- if ((Mouvement[SAUT] == true) || (saut.enCollision))
- {
- if ((Mouvement[SAUT] == true) && (saut.enCollision)) //on etait deja sur un objet et on a sauté à nouveau
- {
- saut.step = 0; //on initialise un nouveau saut
- saut.enCollision = false;
- }
-
- if (saut.step == 0)
- {
- //qDebug() << "Saut";
- saut.altitudeInitial = _position.Z;
- saut.altitudeVoulu = _position.Z+7 ;
- DeterminerConstanteSaut(saut.altitudeInitial, saut.altitudeVoulu); //calcul vitesseInitiale et acceleration initiale
- saut.altitude = saut.altitudeInitial;
- //qDebug() << "step = 0.00 | Altitude = " << saut.altitude;
- }
- //Dans le saut, l'equation du mouvemet ne depend que de l'acceleration (constante), la vitesse initiale (que l'on vient de calculer), l'altitude ini et le temps ecoulee
- //formule de mecanique ; z(t) = 0,5*a*t² + v(t0)*t+z(t0)
- saut.altitudePrecedente = _position.Z;
- saut.altitude = 0.5*saut.acceleration*(saut.step*saut.step) + saut.vitesseBase*saut.step+saut.altitudeInitial;
- //qDebug() << "step = " << saut.step << " | Altitude = " << saut.altitude ;
- //qDebug() << "altitude_debug = " << (4.9000*saut.step);
- _position.Z = saut.altitude;
-
- saut.step += 25; //le saut est parametré pour que saut.step = 500 soit la moitié du saut et saut.step=1000 soit la fin du saut
-
- //debut test collision
- i=0;
- _collision = false;
- while (i<nombreObjets && _collision==false)
- {
- if (listeObjet[i]->getPossedeCollisionBox() == true) //on verifie qu'il a une box
- _collision = test_Collision(_position, _collisionBox, listeObjet[i]->getPosition(), listeObjet[i]->getCollisionBox());
- i++;
- }
- //Fin test collision
-
- if ((_collision==true)&&(saut.step>500)) //quand on a saute sur un objet
- {
- //qDebug() << "step = " << saut.step << " | Altitude = " << saut.altitude ;
- _position.Z = saut.altitudePrecedente;
- saut.enCollision = true;
- Mouvement[SAUT] = false;
- saut.step -= 25;
-
- }
- //et maintenant quand on tombe sans sauter de l'objet, on parametre un nouveau saut, mais juste la partie de la descente
- else if ((_collision==false)&&(saut.enCollision==true)&&(_position.Z>0))
- {
- //qDebug() << "Chute libre";
- saut.enCollision=false;
- Mouvement[SAUT] = true;
- saut.altitudeInitial = 0;
- saut.altitudeVoulu = _position.Z;
- DeterminerConstanteSaut(saut.altitudeInitial, saut.altitudeVoulu); //calcul vitesseInitiale et acceleration initiale
- saut.altitude = saut.altitudeInitial;
- saut.step=500; //la moitié du saut
- }
- else if (_position.Z<0) //et quand on touche le sol
- {
- _position.Z = 0;
- Mouvement[SAUT] = false;
- saut.enCollision = false;
- saut.step = 0;
- }
- }
- ////////////////////////////////////////////////////////////////////////
-
- //qDebug() << "Animate";
- ConversionAnglesVersVecteurs(); //recalcule les coordonnees du vecteur de direction du regard a partir des angles _phi et _theta
- _cibleCamera.X = _forward.X + (_position.X +1); //comme on a bouge, on recalcule la cible fixee par la camera
- _cibleCamera.Y = _forward.Y + (_position.Y +1); // en ajustant pour car la camera n'est pas exactement a la position du jour
- _cibleCamera.Z = _forward.Z + (_position.Z +6); // mais decalé de (1,1,6)
-
- _left = _up.crossProduct(_forward); //recalcule le vecteur perdendiculaire au vecteur up et target pour se deplacer vers la gauche ou la droite
- _left.normalize();
-
- }
-
- bool Personnage::test_Collision(Coord3D positionObjet1, Coord3D boxObjet1, Coord3D positionObjet2, Coord3D boxObjet2)
- {
- if((positionObjet2.X >= positionObjet1.X + boxObjet1.X) // trop à droite
- || (positionObjet2.X + boxObjet2.X <= positionObjet1.X) // trop à gauche
- || (positionObjet2.Y >= positionObjet1.Y + boxObjet1.Y) // trop en bas
- || (positionObjet2.Y + boxObjet2.Y <= positionObjet1.Y) // trop en haut
- || (positionObjet2.Z >= positionObjet1.Z + boxObjet1.Z) // trop derrière
- || (positionObjet2.Z + boxObjet2.Z <= positionObjet1.Z)) // trop devant
- return 0;
- else //si il y a collision
- {
- return 1;
- }
- }
-
- void Personnage::ConversionAnglesVersVecteurs() //tranforme les coordonnees_phi et _theta en vecteur qui donne la direction de la camera
- {
- _forward.Z = cos(_phi*M_PI/180);
- float r_temp = sin(_phi*M_PI/180);
- _forward.X = r_temp*cos(_theta*M_PI/180);
- _forward.Y = r_temp*sin(_theta*M_PI/180);
-
- //qDebug() << "_forward : X = " << _forward.X << " | Y = " << _forward.Y << " | Z = " << _forward.Z;
- }
-
-
-
- void Personnage::ConversionVecteursVersAngles() //tranforme les coordonnees X,Y,Z en _phi et _theta
- {
- //Calcul des angles à partir des coordonnees X,Y,Z :
- //Une coordonnee spherique est de forme (r, _phi, _theta)
- //Attention avec les coordonnees spherique (r,theta,phi) on a phi langle a partir de laxe z
- //et theta langle a partir de laxe x
- //r = racine( x² + y² + z² )
- //_phi = arcos ( Z / r)
- //_theta = arcos ( X / racine(X²+Y²) )
- //-La librairie <cmath> utilise les radians, il faut donc convertir a chaque fois les degres
-
- _forward.X = _cibleCamera.X - (_position.X+1);
- _forward.Y = _cibleCamera.Y - (_position.Y+1);
- _forward.Z = _cibleCamera.Z - (_position.Z+5); //la camera est positionnée à 5 du sol et décalé de (1,1), il faut en prendre compte pour
- //pour le calcul du vecteur forward
-
- /*qDebug() << "premier _forward : X = " << _forward.X << " | Y = " << _forward.Y << " | Z = " << _forward.Z;
- qDebug() << "position camera =" << _position.X << _position.Y << _position.Z;
- qDebug() << "target camera =" << _cibleCamera.X << _cibleCamera.Y << _cibleCamera.Z:*/
-
- float r = sqrt(pow(_forward.X,2) + pow(_forward.Y,2) + pow(_forward.Z,2));
- _phi = ( acos(_forward.Z/r) *180/M_PI);
- //qDebug() << "r = " << r;
-
- float r_temp = sqrt(pow(_forward.X,2) + pow(_forward.Y,2));
- if (_forward.Y >= 0)
- _theta = ( (acos(_forward.X/r_temp)) *180/M_PI);
- else
- _theta = - ( (acos(_forward.X/r_temp)) *180/M_PI);
-
-
- }
-
- void Personnage::DeterminerConstanteSaut(float altitudeInitiale, float altitudeVoulu) //calcul l'acceleration et la vitesse (initiale) pour le saut
- {
- /*On a z(t) = 0.5*acceleration² + saut.vitesseBase*t + z(0)
- On cherche l'acceleration et la vitessebase pour que z(t = 0) = z(0)
- z(t = 1000) = z(0)
- z(t = 500) = altitudeVoulu
-
- On obtient le systeme
- ---
- | 500 000*acceleration + 1000*vitesseBase + altitudeInitiale = altitudeInitiale
- | 125 000*acceleration + 500*vitesseBase + altitudeInitiale = altitudeVoulu
- ---
- et donc;
- acceleration = (-2*altitudeVoulu + 2*altitudeInitiale) / 250 000
- vitesseBase = (4*altitudeVoulu - 4*altitudeInitiale) /1000
-
-
- */
- saut.acceleration = (-2*altitudeVoulu + 2*altitudeInitiale) / 250000;
- saut.vitesseBase = (4 * altitudeVoulu - 4*altitudeInitiale) / 1000;
- }
-
- void Personnage::mouvementSouris (int xrel, int yrel)
- {
- _theta += xrel*_sensivity; //on modifie les coordonnees polaire quand on bouge la souris
- _phi -= yrel*_sensivity; //on met un '-' car quand on regarde vers le bas _phi augmente
-
- if (_phi < 10) //On limite les valeurs de _phi, pour prévenir le torticoli :D
- _phi = 10;
- else if (_phi > 170)
- _phi = 170;
-
-
- if (_theta > 180) //Evite d'avoir un angle de rotation lateral (theta donc) qui atteint 2700°
- _theta = -180;
- else if (_theta < -180)
- _theta = 180;
-
- _orientation.Z = _theta;
- ConversionAnglesVersVecteurs(); //et on convertit notre variation d'angle de vue en un vecteur (interpretable par la camera)
- }
-
-
- void Personnage::deplacement (int numDirection, bool valeur)
- {
- if (numDirection <= 5)
- Mouvement[numDirection] = valeur;
- else
- qDebug() << "Erreur 03 ; Mouvement du personnage non-autorisé";
- }
-
-
-
- ////////////GESTION DE L'ARME////////////////////
-
- bool Personnage::gestionArme(Objet *listeObjets[], int nombreObjets)
- {
- if (_armeActive == true) //on a activé l'arme et la vitesse de rotation augmente
- {
- if ((soundPlayed == false)&&(_munitions>=0)) //On lance le son du chargement de l'arme
- {
- //QSound::play("sounds/load_torpedo.wav");
- soundPlayed = true;
- }
- donneeArmeModifie = true; //il faudra mettre à jour les progressBar et les labels de la QMainWindow
- _rotationSupplementaire += ROTA_SUPP;
-
- if (_munitions <= 0) //on desactive l'arme si il n'y a plus de munition
- {
- _armeActive = false;
- }
-
- if (_rotationSupplementaire > ROTA_SUPP_MAX) //on est arrivé à la vitesse de rotation max, donc on lance le tir
- {
- _rotationSupplementaire = ROTA_SUPP_MAX;
- qDebug() << "tir";
- _tir=true;
- _etapeTir = 0;
- listeObjets[0]->setIsVisible(true); //on affiche le projectile
- QSound::play("sounds/light_torpedo_low.wav");
- _munitions -= 5;
- _armeActive = false; //on desactive le chargement de l'arme
-
- }
- }
- else if ((_armeActive == false)&&(_rotationSupplementaire!=0)) //si on arrete de soliciter l'arme, il faut ralentir la rotation
- {
- //if (_tir==false)
- //loadArme.stop();
- _rotationSupplementaire -= ROTA_SUPP; //l'arme ralentit si le chargement est desactivé
- if (_rotationSupplementaire < 0)
- {
- _rotationSupplementaire = 0;
- }
- if ((_toucheArmeActive==true)&&(_rotationSupplementaire <= ROTA_SUPP_MAX*0.7)) //si on garde la souris activé, ça relance l'activation de l'arme
- {
- _armeActive = true;
- }
- }
-
- if (_tir == true)
- {
- if (_etapeTir == 0) //on passe à l'étape 1 pour initialiser le tir
- {
- _etapeTir = 1;
- _origineTir.X = _position.X + 1; //point origine du tir
- _origineTir.Y = _position.Y + 1;
- _origineTir.Z = _position.Z + 3.8;
- listeObjets[0]->setPosition(_origineTir); //on positionne le projectile sur le joueur
- _vecteurTir = _forward; //point sortie tir
- _vecteurTir.Z -= 0.04;
-
- }
- else if (_etapeTir >= 100) //il faut quand meme arreter le tir au bout d'un moment si le projectile n'a rien rencontré
- {
- _tir = false; //on reinitialise le tir
- _etapeTir = 0;
- listeObjets[0]->setIsVisible(false); //on efface le projectile
- listeObjets[0]->setPossedeCollisionBox(false);
- qDebug() << "Fin tir";
-
- }
- else // 0 < _etapeTir < 100
- {
- listeObjets[0]->setPosition(_origineTir + _vecteurTir*_etapeTir*1.5);
- //debut test collision
- int i=1;
- _collision = false;
- while (i<nombreObjets && _collision==false)
- {
- if (listeObjets[i]->getPossedeCollisionBox() == true) //on verifie qu'il a une box
- _collision = test_Collision(listeObjets[0]->getPosition(), listeObjets[0]->getCollisionBox(), listeObjets[i]->getPosition(), listeObjets[i]->getCollisionBox());
- i++;
- }//Fin test collision
- _etapeTir++;
-
- if (_collision==true)
- {
- _tir = false; //on reinitialise le tir
- _etapeTir = 0;
- listeObjets[0]->setIsVisible(false); //on efface le projectile
- //listeObjets[0]->setPossedeCollisionBox(false);
- listeObjets[i-1]->setIsDead(true); //on rend l'objet touché transparent
- listeObjets[i-1]->setPossedeCollisionBox(false);
- qDebug() << "Fin tir";
- }
- }
- }
-
-
- _rotationArme += 2; //la rotation de l'arme habituelle
- _rotationArme +=_rotationSupplementaire; //on ajoute la rotation du à l'activation du tir
- if (_rotationArme>360)
- _rotationArme -= 360;
-
- return donneeArmeModifie;
- }
-
-
- void Personnage::setToucheArmeActive(bool statut)
- {
- _toucheArmeActive = statut;
- _armeActive = statut;
- }
-
- bool Personnage::getStatutTir()
- {
- return _tir;
- }
-
- Coord3D Personnage::getCoordOrigineTir()
- {
- return _origineTir;
- }
-
- Coord3D Personnage::getCoordVecteurTir()
- {
- return _vecteurTir;
- }
-
- int Personnage::getAngleRotationArme()
- {
- return (_rotationArme);
- }
-
- int Personnage::getChargeArme() //renvoie le taux de charge de l'arme
- {
- return (_rotationSupplementaire*100/ROTA_SUPP_MAX);
- }
-
-
- int Personnage::getNiveauMunitions() //renvoie le taux de charge de l'arme
- {
- return (_munitions);
- }
-
- //////////////Fin gestion de l'arme///////////////////////////////
-
-
- void Personnage::setVitesse (float vitesse)
- {
- _vitesse = vitesse;
- }
-
- float Personnage::getVitesse()
- {
- return _vitesse;
- }
-
-
- Coord3D Personnage::getCibleCamera()
- {
- return _cibleCamera;
- }
-
-
-
|