IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C++ Discussion :

Jeu de labyrinthe, plusieurs questions sans réponse.


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2012
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2012
    Messages : 11
    Par défaut Jeu de labyrinthe, plusieurs questions sans réponse.
    Bonjour, je débute en C++ et, avec le livre le Guide Complet C++, j'ai créé un jeu de labyrinthe avec hiérarchie de classe, des ennemis et plusieurs map...

    Je suis sous Visual C, voici le liens de projet:
    https://rapidshare.com/files/2694081315/LabyC++.zip

    Le programme ouvre un document texte, composé de 0 et de 1 (0=mur et 1=couloir). Avec quelque autre caractère (j=position de départ du joueur, w= arrivée, s=sortie (car il y a plusieurs map relié entre elle), v= EnnemiVert, r=EnnemiRouge, f=EnnemiFolow).
    Ne répondre qu'a une seul de mes question m'aiderais vachement.
    Tout le projet est sur le liens et vous pouvez déjà tester.

    J'utilise la bibliothèque glut/GL

    Pour le déplacement des ennemi vert/rouge/bleu:

    AU début, un algorithme défini la direction haut/bas/gauche/droite. Puis si il prend a droite, il continue a droite jusqu'au moment ou il y a un mur, puis l'algorithme aléatoire reprend...

    Première chose: si l'on ne met qu'un ennemi, pas de problème, mais si on en met plusieurs, si il y en a un qui est contre un mur, il déclenche l'algotithme aléatoire pour TOUT les ennemis... je voudrai que chaque ennemi se déplace individuellement...

    Deuxième chose: je voudrai que, si l'ennemi avance vers le bas, s'il rencontre un mur, il vérifie d'abord s'il peu aller a droite ou a gauche, si il peux, il va au hasard a droite/gauche, sinon, il repart d'ou il vient.

    Troisième chose: je voudrai que la manière de déplacement que je viens de dire ne marche qu'avec EnnemiVert et EnnemiFolow

    En effet EnnemiRouge se duplique, et pour ne pas compliquer le joueur, cet ennemi ne devrai pas se déplacer beaucoup en parcourant les couloirs ,se déplacer tout le temps aléatoirement évite qu'ils se déplacent trop.


    Quatrième chose: Pour EnnemiFolow maintenant, comme son nom mal orthographié l'indique , s'il est à la portée de vu du joueur (si il est sur la même ligne ou colonne, et qu'il n'y a aucun mur entre le joueur et EnnemiFolow, celui ci fonce vers le joueur en accélérant, et en émettant un son:
    - je sais comment parcourir un fichier, donc le test "si joueur et ennemiFolow" est sur même ligne/colonne c'est bon, mais en plus, vérifier si il y a un mur entre les deux... ça je vois pas...

    - comment accélérer l'ennemi ? (je pourrai, au lieu de varié PosC ou PosL de 2 au lieu de 1, mais alors je ne sais pas comment vérifier s'il y a un mur a plus d'une case de l'ennemie).

    - comment émettre un son ? autre que "\a" ? j'ai un fichier .wav emettant un son approprié, comment l'ouvrir lorsque EnnemiFolow fonce sur le joueur ?


    Voila... ça fait beaucoup de chose, je sais :/ mais je suis débutant et, malgré mes essais je n'arrive a rien...



    Merci.

  2. #2
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 480
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 480
    Par défaut
    Hello,

    Citation Envoyé par Hedg-Hop Voir le message
    Bonjour, je débute en C++ et, avec le livre le Guide Complet C++, j'ai créé un jeu de labyrinthe avec hiérarchie de classe, des ennemis et plusieurs map... Je suis sous Visual C
    Je ne sais pas si c'est un exemple tiré du livre ou si tu as tout écrit toi-même depuis zéro mais félicitations : en ajoutant simplement « #include <cstdlib> » et la fonction « glutInit() », j'ai été en mesure de compiler directement ton programme sous Linux, et il marche !

    Ça aide pour le déboguage. :-)


    AU début, un algorithme défini la direction haut/bas/gauche/droite. Puis si il prend a droite, il continue a droite jusqu'au moment ou il y a un mur, puis l'algorithme aléatoire reprend...

    Première chose: si l'on ne met qu'un ennemi, pas de problème, mais si on en met plusieurs, si il y en a un qui est contre un mur, il déclenche l'algotithme aléatoire pour TOUT les ennemis... je voudrai que chaque ennemi se déplace individuellement...
    Tu utilises une variable nommée « impossible » pour savoir si tu peux ou non effectuer le déplacement, mais cette variable est une variable globale. Tous tes sprites lisent donc la même. Il aurait fallu que « impossible » soit une donnée membre de chaque instance, au même titre que PosC et PosL.

    Deuxième chose: je voudrai que, si l'ennemi avance vers le bas, s'il rencontre un mur, il vérifie d'abord s'il peu aller a droite ou a gauche, si il peux, il va au hasard a droite/gauche, sinon, il repart d'ou il vient.
    Si ton ennemi est dans une impasse, il n'y a qu'une seule voie possible. Celle-là même par où il est arrivé. Donc, dans le fonctionnement actuel, ça devrait déjà fonctionner ainsi. Au pire, il fait du surplace pendant un instant le temps de tomber sur la bonne voie.

    Troisième chose: je voudrai que la manière de déplacement que je viens de dire ne marche qu'avec EnnemiVert et EnnemiFolow

    En effet EnnemiRouge se duplique, et pour ne pas compliquer le joueur, cet ennemi ne devrai pas se déplacer beaucoup en parcourant les couloirs ,se déplacer tout le temps aléatoirement évite qu'ils se déplacent trop.
    Pour cela, il te suffit de surcharger « DeplacementAuto() » pour la classe EnnemiRouge. Après examen, il semble que tu l'aies déjà fait, et que tu rappelles naturellement la fonction-membre de la classe de base.

    Il suffit donc d'y rajouter une clause qui titre systématiquement une nouvelle direction à chaque appel. Tu peux aussi, comme tu l'as fait à côté pour la duplication des ennemis rouges, ajouter une probabilité, de manière à ce que l'ennemi en question conserve quand même sa direction pendant une durée minimum.

    Au passage, l'idée de dupliquer les ennemis rouges est une bonne idée mais telle que tu l'as implémentée, tu risques d'avoir une progression exponentielle du nombre de tes ennemis.

    Quatrième chose: Pour EnnemiFolow maintenant, comme son nom mal orthographié l'indique , s'il est à la portée de vu du joueur (si il est sur la même ligne ou colonne, et qu'il n'y a aucun mur entre le joueur et EnnemiFolow, celui ci fonce vers le joueur en accélérant, et en émettant un son:
    - je sais comment parcourir un fichier, donc le test "si joueur et ennemiFolow" est sur même ligne/colonne c'est bon, mais en plus, vérifier si il y a un mur entre les deux... ça je vois pas...
    Je n'ai pas encore été voir comment tu gères ta grille mais je suppose (et j'espère) que tu la lis en mémoire au départ et une fois pour toutes. De là, si tu sais vérifier s'il y a un mur à proximité d'un personnage, qu'est-ce qui t'empêche de vérifier si il y en a un autre un cran plus loin, puis deux, puis trois, etc. ?

    Pour éviter de consommer inutilement des ressources, tu commences effectivement par vérifier si le joueur et l'ennemi se trouve sur la même ligne ou la même colonne, comme tu l'as dit et, le cas échéant, tu explores case par case l'espace qui les sépare et tu t'arrêtes dès que tu rencontres la première case.

    - comment accélérer l'ennemi ? (je pourrai, au lieu de varié PosC ou PosL de 2 au lieu de 1, mais alors je ne sais pas comment vérifier s'il y a un mur a plus d'une case de l'ennemie).
    Il n'y a pas trente-six manières de le faire : soit tu vérifies deux cases au lieu d'une à chaque fois, soit tu accélères la boucle principale et tu ne rafraîchis les autres ennemis qu'une fois sur deux.

    - comment émettre un son ? autre que "\a" ? j'ai un fichier .wav emettant un son approprié, comment l'ouvrir lorsque EnnemiFolow fonce sur le joueur ?
    Il te faut une autre bibliothèque : OpenAL, par exemple.

    Voila... ça fait beaucoup de chose, je sais :/ mais je suis débutant et, malgré mes essais je n'arrive a rien... Merci.
    Tu as un programme qui marche, c'est déjà beaucoup !
    Bon courage.

  3. #3
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2012
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2012
    Messages : 11
    Par défaut
    Merci Obsidian de ta réponse tardive ! ^^ (non pas tardive parce que tu as été lent a répondre mais parce que c'est la nuit )

    Je programmerais ça demain, je suis sur que ça me sera d'une grande aide.

    Info: Le livre me fait créé le labyrinthe pas à pas simple. Avec ce que j'ai appris j'ai rajouté la quadruple map relié entre elles... j'ai créé beaucoup d'ajustement, comme le déplacement des ennemis, création d'un troisième ennemi etc...

    Tu utilises une variable nommée « impossible » pour savoir si tu peux ou non effectuer le déplacement, mais cette variable est une variable globale. Tous tes sprites lisent donc la même. Il aurait fallu que « impossible » soit une donnée membre de chaque instance, au même titre que PosC et PosL.
    Je n'y avais pas pensé ! merci
    EDIT: une donnée membre CAD ? int impossible(0); dans ennemiBase.h ?Après ça cause ds problèmes dans ennemiBase.cpp...
    Et pour PosC et PosL.. ils sont membre protégé de PersonnageBase.h.. donc normalement on peut les utiliser par les class membre non ?

    Si ton ennemi est dans une impasse, il n'y a qu'une seule voie possible. Celle-là même par où il est arrivé. Donc, dans le fonctionnement actuel, ça devrait déjà fonctionner ainsi. Au pire, il fait du surplace pendant un instant le temps de tomber sur la bonne voie.
    Non tu n'as pas compris:
    Si l'ennemi va par exemple vers le bas, et que il arrive à un mur, imaginons qu'il a le choix entre 3 direction: droite/gauche, et haut(là où il est venu)
    Je voudrai que l'ennemi test d'abord avec l'algorithme droite/gauche. (et pas la d'ou il est venu).
    SI bien sur il est dans une impasse, alors il revient sur ses pas.


    (EnemiRouge) Il suffit donc d'y rajouter une clause qui titre systématiquement une nouvelle direction à chaque appel
    Je voudrai que pour cet ennemi, a chaque déplacement seul ce switch soit appelé:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int hasard rand()%4
    switch(hasard)
    {...} // fait bouger EnnemiRouge completement aléatoirement
    Mais ce switch est dans EnemiBase.cpp, mère de EnnemiRouge, en plus il est dans un if et... je ne sais même plus comment j'ai réussi j'ai beaucoup soufert pour que tout marche et je ne vois vraiment pas comment faire.


    Au passage, l'idée de dupliquer les ennemis rouges est une bonne idée mais telle que tu l'as implémentée, tu risques d'avoir une progression exponentielle du nombre de tes ennemis.
    C'est fait pour ! pour que le joueur termine le niveau le plus rapidement possible !
    PS: comme c'est une quadruple map, le passage d'une map a l'autre repositionne tout les ennemis a leur places du début. Je sais c'est pas très réaliste mais, ça permet de gerer le nombre. et, je ne sais plus ce que j'avais mis comme temps pour la duplication, mais maintenant j'ai mis 1 chance/450 toute les 500 milisec par ennemiRouge.


    EDIT: Pour ennemiFolow, j'ai pensé a faire ça:
    rajouter
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void SuivreJoueur(); // dans EnemiFolow.h
    rajouter dans EnnemiFolow.cpp:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void EnnemiFolow::SuivreJoueur()
    {
          if(Matrice[monJoueur.GetPosC()] []  == Matrice[ENNEMI_FOLOW] []  ||      Matrice [] [monJoueur.GetPosL()]  == Matrice[] [ENNEMI_FOLOW])
           {
                   /* par contre la je ne vois pas faire... "si '0' est entre 'monJoueur' et 'EnnemiFolow' */
            }
    }
    Et apparemment... mon premier if est incorect

  4. #4
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 480
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 480
    Par défaut
    Hello,

    Citation Envoyé par Hedg-Hop Voir le message
    Je n'y avais pas pensé ! merci
    EDIT: une donnée membre CAD ? int impossible(0); dans ennemiBase.h ?Après ça cause ds problèmes dans ennemiBase.cpp...
    Tout d'abord, c'est une bonne chose d'avoir essayé une fois les variables globales pour voir comment elles fonctionnent et utiliser « extern » mais, désormais, il faudra t'en passer définitivement, sauf cas extrêmement particulier (que je ne saurais même pas te détailler à brûle-pourpoint). Voici en partie pourquoi :
    http://www.developpez.net/forums/d93...c/#post5271611

    Sinon, pour le reste, il faut que tu remettes les choses à plat, et éventuellement les réécrives au propre. Le fait de tourner à gauche ou à droite, et de se déplacer vers n'importe lequel des quatre points cardinaux est complètement indépendant, en soi, de la notion de classe et des différentes entités que tu as définies.

    Il faut donc prendre dix minutes pour y réfléchir en dehors de tout le reste et, de là, écrire une méthode propre qui sera utilisée ensuite partout dans ton programme.

    D'abord, tu suis quatre directions potentielles, qui peuvent donc être codées sur exactement deux bits, ce qui te permet d'utiliser les opérateurs logiques comme le modulo, ce qui a quelques avantages : un « & 3 » sera donc équivalent à un « % 4 » lorsque tes nombres sont positifs et dans le cas de « (0 - 1) & 3 », tu remonterais à « 3 » au lieu d'obtenir « -1 ».

    Ensuite, tu peux par exemple prendre le nord comme point de repère puis tourner vers la droite, ce qui donnerait : 1→nord ; 2→est ; 3→sud ; 4→ouest. L'avantage est que la congruence apportée par ton modulo suit le même mouvement circulaire. Tant et si bien que si tu stockes ta direction actuelle dans un entier « d », alors l'expression « (d+1) & 3 » correspondra toujours à un virage à droite, quelque soit ta direction initiale, et « (d-1) & 3 » à un virage à gauche. On comprend également que c'est purement algorithmique et que ce n'est pas lié en soi au C ou au C++.

    Puis, comme chaque ennemi doit suivre sa direction courante jusqu'à ce qu'il rencontre un obstacle, cela veut dire qu'à la base, chaque ennemi a une direction propre. Il faut donc ajouter « int direction » aux données membres de « EnnemiBase », voire même « PersonnageBase ».

    Écris ensuite des méthodes dérivées comme « CaseNord() », « CaseEst() », « CaseSud() », « CaseOuest() » pour récupérer le contenu de la cellule adjacente au personnage de façon absolue et « CaseDevant() », «CaseADroite() », « CaseDerriere() », « CaseAGauche() » pour le faire de manière relative à la direction courante de ton personnage.

    Tu peux également choisir d'écrire une seule méthode pour chaque version et passer la direction en argument : « CaseAbsolue(int d); » et « CaseRelative(int d); ».

    Une fois que tu disposes de ces outils, il est très facile de prendre une décision :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
        if (CaseGauche()!=1 && CaseDroite()!=1) DemiTour

    EDIT: Pour ennemiFolow, j'ai pensé a faire ça:
    rajouter
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void SuivreJoueur(); // dans EnemiFolow.h
    rajouter dans EnnemiFolow.cpp:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void EnnemiFolow::SuivreJoueur()
    {
          if(Matrice[monJoueur.GetPosC()] []  == Matrice[ENNEMI_FOLOW] []  ||      Matrice [] [monJoueur.GetPosL()]  == Matrice[] [ENNEMI_FOLOW])
           {
                   /* par contre la je ne vois pas faire... "si '0' est entre 'monJoueur' et 'EnnemiFolow' */
            }
    }
    Et apparemment... mon premier if est incorect
    En effet, cette expression ne veut rien dire. « ENNEMI_FOLLOW » est censé n'être qu'un code pour vérifier si le contenu d'une case est un ennemi suiveur, mais tu t'en sers comme indice de ligne ou de colonne. En outre, tu peux utiliser des crochets vides dans certains cas seulement lors des déclarations, mais pas à l'évaluation.

    À la place, il faut comparer les deux instances de tes personnages, et vérifier si leurs colonnes respectives sont égales, sinon leurs lignes (si les unes et les autres sont égales entre elles au même moment, ça veut dire que l'ennemi est à la même position que le joueur et qu'il y a donc collision).

    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        if (monJoueur.GetPosC() == ennemi.GetPosC() || monJoueur.GetPosL() == ennemi.GetPosL())
        {}

    Ensuite, il n'y a pas de manière rapide de vérifier ce que tu veux savoir. L'ennemi n'a le joueur en vue que s'il n'y a aucun obstacle entre les deux. Il faut donc écrire une boucle « for » qui coure de C1 à C2 (respectivement L1 ou L2), où C1 est la plus petite des deux colonnes (entre celle du joueur et celle de l'ennemi) plus une unité, pour commencer après le personnage, et C2 la plus grande moins une unité, pour finir avant l'autre (ou la même chose avec les lignes, le cas échéant) et, à chaque tour, tu examines la case correspondante de la matrice. Dès que tu trouves quelque chose qui diffère de « 1 », le test a échoué et ce n'est plus la peine d'aller plus loin. Si, en revanche, la boucle est allée jusqu'à son terme (et donc que l'indice de boucle est supérieur ou égal à C2), alors le « couloir » est bien vide entre les deux personnages et ton ennemi a le joueur en vue.

  5. #5
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2012
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2012
    Messages : 11
    Par défaut
    Salut.

    Pour la variable impossible: si je supprime de main.cpp et que je let met dans EnnemiBase.h, en tant que membre publique, ça me met erreur...

  6. #6
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2012
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2012
    Messages : 11
    Par défaut
    ajouter « int direction » aux données membres de « EnnemiBase
    je met dans les membres public d'EnnemiBase.h c'est bien ça ?


    Écris ensuite des méthodes dérivées comme « CaseNord() », « CaseEst() », « CaseSud() », « CaseOuest() » pour récupérer le contenu de la cellule adjacente au personnage de façon absolue et « CaseDevant() »,
    Méthode dérivée ? je comprend pas dsl... récupérer le contenue des cellule adjacente des ennemis... je ne vois pas...

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. PyGame, quelques questions sans réponses
    Par Ziranium dans le forum Programmation multimédia/Jeux
    Réponses: 6
    Dernier message: 27/04/2011, 19h33
  2. Plusieurs questions sans réponses
    Par laposte dans le forum Servlets/JSP
    Réponses: 3
    Dernier message: 11/06/2010, 16h40
  3. questions sans réponses
    Par miroush dans le forum VB 6 et antérieur
    Réponses: 3
    Dernier message: 08/03/2010, 13h54

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo