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

Projets Discussion :

OpenAWars - Advance wars like


Sujet :

Projets

  1. #1
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    mai 2008
    Messages
    25 947
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : mai 2008
    Messages : 25 947
    Points : 207 568
    Points
    207 568
    Billets dans le blog
    85
    Par défaut OpenAWars - Advance wars like
    Bonjour à tous,

    Voilà, j'arrive avec un nouveau projet. Ici je vais reprendre le principe de fearyourself avec son projet, soit je vais expliquer à peu de chose près, mon avancement et mon code ( vu que ce n'est pas sur qu'il soit documenté ( bouh! ) ).

    Je vais faire ( et j'ai commencé ) un remake de Advance Wars ( qui est sorti sur GameBoy Advance et sur Nintendo DS ) ou encore, pour les plus vieux d'entre nous, une reprise de Famicon Wars ( qui était donc sorti sur Famicon ).
    (Pour les gens qui n'aiment pas la wikipédia ) C'est un jeu de stratégie, au tour par tour qui se joue sur une sorte de plateau ( carte ). On peut avoir jusqu'à 4 adversaires. Chaque tour, nous gagnons des revenus, nous pouvons déployer des unités, déplacer nos unités, attaquer, capturer des usines et autres batiments ( qui donne des revenus, permet de fabriquer des unités, ou même de gagner ). Chaque joueur à un QG. Si celui ci est capturé par l'adversaire, nous perdons. Si nous n'avons plus d'unités sur la carte, nous perdons ( Dans certain cas, si un nombre de tours est dépacé nous perdons ).
    Sur certaines cartes il peut il avoir un brouillard de guerre.

    - Pourquoi ce jeu?

    Simplement car c'est un jeu que j'ai beaucoup aimé et que je voulais faire un projet de jeu vidéo avant la rentrée scolaire .
    De plus, il me semble qu'il n'y ai pas beaucoup de monde ayant voulu le faire ( seul projet notable: customwars ).
    Pourquoi le refaire... au lieu d'aider un projet courant ... c'est qu'il utilise JAVA ( que je ne critique pas ) que je maitrise moins bien, de plus cela bloque la compatibilité avec les plateformes que je cible.

    Donc vous avez compris, ce projet utilise le C++

    - Bibliothèques utilisées?

    Je vais utiliser la SDL car celle-ci est extrèmement portable ( récemment j'ai recontré un codeur, codant sur AmigaOS ).
    En fait, j'ai longtemps hésité, car je voulais apprendre la SFML , qui est très certainement une très bonne bibliothèque ( le créateur est présent sur ce forum, donc je ne peux pas dire de bétises ). Mais comme je l'ai dit, c'est pour garder une extrème portabilité ( que beaucoup de projet ne cherchent pas et n'ont certainement pas besoin ). La deuxième raison est aussi que je veux porter sur GP2X ( une console portable ) et que c'est surement sur cette bête que je vais bosser l'année prochaine ( durant mon année scolaire ).
    ( On remarquera que chercher à travailler sur de telle bêtes n'est que purement théorique, effectivement, un code C++ écrit correctement est portable ( tant que l'on n'utilise pas des fonctions de la bibliothèque de Windows ), les seuls problèmes qui peut arriver ( les problèmes de compilation avec des compilateurs plus strictes ne sont pas pris en compte, car normalement réctifiables très rapidement ) sont les erreurs de segmentation et les fuites de mémoires. Effectivement, sur nos systèmes surpuissant, le système d'exploitation n'est pas toujours regardant et peu laisser passer quelques erreurs ( et puis nous avons pleins de mémoire vive ( n'est ce pas? ) ). Sur des systèmes tel que l'AmigaOS et celui de GP2X, une fuite de mémoire ou une erreur de segmentation peut arriver à freezer complètement le système ( l'utilisateur va vite me détester si je laisse de telles erreurs ).

    Donc:

    SDL -> gestion clavier / souris , ouverture de la fenêtre , affichage
    SDL_image -> Chargement des images et affichage grace au core de la SDL
    SDL_mixer -> Chargements des sons / jouer les sons
    SDL_network -> Ah bon! Il y aura du réseau ( pour l'instant ce n'est pas une priorité )

    OpenGL. Hum, oui je n'ai pas encore parlé d'OpenGL. En fait, tout est faisable avec la SDL ( vu que nous faisons que de la 2D ). Mais l'avantage d'OpenGL, c'est que c'est directement géré par la carte graphique, donc c'est plus rapide. Je vais essayer ( en fait, je n'ai pas encore d'idée pour le faire correctement ) de gérer le dessin à l'aide de la SDL, ou d'OpenGL ( mais tout avec un seul et unique code à part les routines de dessin, bien sur ).

    - Outils?

    Clavier, souris, écran ...
    Plus sérieusement, actuellement j'utilise Visual Studio 2008.
    Sous linux, c'est gcc, make et geany pour l'éditeur.
    J'utiliserai aussi doxygen pour générer la documentation.
    Et finalement, pour faire une compilation multi plateforme avec peu d'embêtement, je vais utilisé autotool/automake qui est un outil sous linux pour généré un script configure qui lui générera des Makefile dépendant de votre configuration.

    - Licence?

    Le code source est complètement ouvert et protégé par la licence GPLv2.

    - Autre?

    Mon projet ( et surtout son code source ) est stocké sur google code.
    Il n'y a pas de raison particulière opur avoir choisi google code, juste que mon précédent projet est aussi stocké là bas.
    J'utilise SVN ( SubVersion ) pour la gestion des versions ( ça, c'est parce que j'ai l'habitude d'utiliser celui là ).

    - Premier design

    Sortons une feuille blanche.
    Mon premier design est loin d'être parfait, mais donne un premier aperçu et surtout une première direction vers quoi aller.
    Les classes de prévues:

    Engine:
    - Window ( ouverture de la fenêtre ... )
    - Renderer ( il devra géré OpenGL et SDL de façon indépendante, du coup il aura les fonctions de base du genre 'drawBackground' 'drawTile' )
    - Camera ( pour les cartes plus grandes que la taille de l'écran ... permet donc le déplacement de la carte )
    - Sprite
    - Animation ( c'est une série de sprite que l'on change selon le temps )
    Game:
    - Map ( il faudra la charger à partir d'un fichier , la dessiner , ou dessiner un aperçu )
    - Cursor ( peut être dans l'engine, c'est un jeu console, donc il y a un curseur )
    - Player ( avec une liste d'unité )
    Units:
    - Unit ( une classe mère, qui défini des actions de base ( dessin / déplacement ) )
    - UnitFactory ( une fabriques d'unités )
    - Building ( pour les batiments, à peu de chose près le même principe que les unités )
    - BuildingFactory ( une fabrique de batiments )
    ResourcesManager:
    - SpriteManager ( on passe le nom d'un fichier, cela nous retourne un pointeur sur les données du fichier, une fois chargée )
    - SoundsManager ( pareil pour les sons )


    Les managers sont importants pour la mémoire. Ils permettent de faire un chargement au tout début du jeu, de toute les ressources, et de ne pas utiliser la mémoire plein de fois pour la même chose ( on charge une seule fois chaque fichier )
    Les Factory sont aussi importantes car elle vont lire les fichiers décrivants les caractéristiques des unités, et juste en passant le nom de l'unité, nous aurons une nouvelle instance de creer.

    Cela permet de faire une meilleure gestion de la mémoire et de tout libérer facilement.

    - Notes de codage

    Les noms des variables pointeurs sont précédés par un 'p'.

    Cela peut ressembler à la notation hongroise, mais c'est le seul point que je reprends de toute la notation.

    Les variables doivent toutes être initialisées à la déclaration ( avec 0 ou NULL, bien souvent ). Cela évite toujours des erreurs ( du moins on les remarques mieux ).

    Voilà, pour un premier aperçu, je pense avoir dit pas mal de chose, donc maintenant, codons!
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  2. #2
    Membre averti
    Homme Profil pro
    Lycéen
    Inscrit en
    novembre 2008
    Messages
    86
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : novembre 2008
    Messages : 86
    Points : 363
    Points
    363
    Par défaut
    Excellent, je me suis justement lancé dans un projet similaire il y a peu

    A la différence que mon futur projet est prévu pour être modulaire, "moddable" et scriptable (en Lua), et qu'il ne vise pas vraiment à recréer AW (dont je suis fan ), mais s'en inspire clairement.
    Pour information, c'est du C++, j'utilise la SFML et boost.

    Enfin, bonne chance à toi

  3. #3
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    mai 2008
    Messages
    25 947
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : mai 2008
    Messages : 25 947
    Points : 207 568
    Points
    207 568
    Billets dans le blog
    85
    Par défaut
    Je me demande si je ne suis pas passer à coté avant de savoir su le projet existait déjà.

    Il faut dire que LUA me tente vraiment, même si je ne me suis jamais penché dessus.
    On va déjà faire en sorte que la carte s'affiche

    Bonne chance à vous aussi
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  4. #4
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    février 2008
    Messages
    308
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Finance

    Informations forums :
    Inscription : février 2008
    Messages : 308
    Points : 620
    Points
    620
    Par défaut
    Je suis moi aussi en train de code un moteur de jeu 2D avec LUA, et je confirme, c'est surpuissant! Je trouve que ça simplifie tout, le contenu des map, les actions faites par le joueur, chargement des niveau et menus, actions des boutons ect... bref tout ce qui est en rapport avec le contenu du jeu. je te conseille donc de t'y intéresser!

  5. #5
    Membre averti
    Homme Profil pro
    Lycéen
    Inscrit en
    novembre 2008
    Messages
    86
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : novembre 2008
    Messages : 86
    Points : 363
    Points
    363
    Par défaut
    Enfin, "existant", c'est vite dit...

    D'autant que ma formule de "tout modulable" (tiles, unités...) je dois coder toute la partie "database" avant même de toucher à la partie graphique (la partie "game" faisant le pont entre les deux)

    Pour en revenir à Lua, oui c'est vraiment énorme, et pour l'embedded (on exécute un scipt depuis le programme C++) 100x mieux que Python. Je n'y suis pas vraiment arrivé avec boost::python, qui ne fournit rien du tout pour cette partie, alors qu'avec luabind c'est ultra-simple (même si maintenant que je comprend mieux la façon de faire des interpréteurs je pourrais me dépatouiller avec boost::python).
    Le seul avantage décisif de Python, c'est le support par défaut de l'unicode (là je vais être obligé de sortir Qt pour traduire facilement...)

  6. #6
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    mai 2008
    Messages
    25 947
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : mai 2008
    Messages : 25 947
    Points : 207 568
    Points
    207 568
    Billets dans le blog
    85
    Par défaut
    Il faut donc que je m'y penche sérieusement.

    Par contre, pensez vous que c'est compatible GP2X et AmigaOS , LUA?

    ------

    Voici le deuxième épisode du développement de OpenAWars.

    Qu'avons nous de nouveau?

    Une Window peut:

    - Ouvrir une fenêtre ( de taille que l'on veut, pleine écran ou pas, opengl ou pas )
    - Réouvrir une fenêtre
    - Récupérer les résolutions disponibles
    - Récupérer la largeur de la fenêtre
    - Récupérer la hauteur de la fenêtre
    - Récupérer le nombre de bits par pixel

    Il y a une fonction interne pour généré les flags que nous allons utilisé pour ouvrir la fenêtre ( entre autre pour le plein écran et OpenGL ).
    J'ai fait une fonction de ce genre, pour éviter à répété plusieurs fois le même code. Il est important d'éviter les copier coller ( source d'erreur trop fréquentes ).
    Les tests sont les suivants:

    - Nous testons si nous avons la possibilité d'avoir une surface du coté matériel.
    - Nous testons si l'utilisateur veut le plein écran
    - Nous testons si nous avons un gestionnaire de fenêtre, qui dit gestionnaire de fenêtre, dit possibilité d'avoir une fenêtre, donc si nous n'en avons pas, nous mettons en plein écran.
    - Finalement, si nous voulons OpenGL, nous ajoutons le flag pour OpenGL. Mais nous définissons aussi le double buffering dans OpenGL

    Le fonction de réouverture de la fenêtre à une particularité, celle ci doit fermer complètement SDL pour pouvoir réouvrir une autre ( sans perte de mémoire ). Effectivement, dans la documentation, il est dit que la surface renvoyé par SDL_SetVideo() ne doit pas être désallouer manuellement.

    La fonction pour récupérer les résolutions est juste composer d'une boucle testant les resolutions une à une et retournant une liste contenant les résolutions valides. Une première optimisation est de sauter les nombres impaires car nous n'avons pas de résolutions impaires. Bien sur je pourrais faire mieux. Le test se fait que avec les flags de pleine écran, car en mode fenêtré toutes les résolutions sont acceptables.
    Cette fonction est importante pour les menus du jeu , laissant la liberté au joueur de changer la résolution.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    void Window :: getResolutionsAvailable(const bool isOpenGL, std::vector<ResolutionInfo>& riList)const
    {
    	Uint32 flags = this->getFlags(true,isOpenGL);
    	int bpp = 0;
     
    	std::cout << "Window :: getResolutionsAvailable (" << isOpenGL << ")" << std::endl;
     
    	for ( unsigned int w = 2 ; w <= 1280 ; w+=2 )
    		for ( unsigned int h = 2 ; h <= 768 ; h+=2 )
    		{
    			if ( (bpp = SDL_VideoModeOK(w, h, 32, flags)) != 0 )
    			{
    				ResolutionInfo ri(w,h,bpp);
     
    				std::cout << "Test (" << w << "x" << h << "x" << bpp << ") Passed" << std::endl;
     
    				riList.push_back(ri);
    			}
    		}
    }
    J'ai passé le std::vector par référence, car j'ai pensé que si je le renvoyer ( avec un return ) j'allais faire une copie supplémentaire de la liste.

    On peut remarquer l'utilisation des assertions ( assert() ), très pratiques pour notamment repéré rapidement des cas non attendus. De plus, les assertions ne sont pas présentes en Release.

    Comme vous pouvez le remarquer j'affiche tout un tas de messages, entre autre à chaque fois que je rentre dans une fonction. Pour cette raison, la prochaine étape est de faire un logguer que l'on pourra désactiver dans la Release.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  7. #7
    Membre averti
    Homme Profil pro
    Lycéen
    Inscrit en
    novembre 2008
    Messages
    86
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : novembre 2008
    Messages : 86
    Points : 363
    Points
    363
    Par défaut
    Citation Envoyé par LittleWhite Voir le message
    Par contre, pensez vous que c'est compatible GP2X et AmigaOS , LUA?
    J'ai recherché rapidement et il y a effectivement eu des portages de fait.
    Sinon, je vois que ça avance bien!

  8. #8
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    mai 2008
    Messages
    25 947
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : mai 2008
    Messages : 25 947
    Points : 207 568
    Points
    207 568
    Billets dans le blog
    85
    Par défaut
    Merci pour la recherche ... étant sur du 28k ( oui avec un 'k' et non un 'm' ) je ne peut pas faire toute les recherches que je vais :p

    Personnellement, je trouve que cela n'avance pas rapidement, mais ça avance

    -----

    Aujourd'hui j'ai rajouté le Logger ( enfin )

    C'est une nouvelle classe 'Logger' donc, qui utilise le design pattern nommé: 'Singleton'

    Le singleton c'est un design pattern qui dit qu'il ne peut y avoir qu'une seule instance de cette classe à la fois.
    Pour ce faire nous suivons les règles suivantes:

    Constructeur / Destructeur / Constructeur par Copie / Operator= sont privé ( empêche donc l'utilisateur de construire la classe lui même )
    Une instance static privée de la classe existe ( on a donc une instance de la classe ... dans la classe, et celle ci est accessible que sous certaine condition )
    Une fonction publique pour récupéré cette instance ( lorsque l'instance n'existe pas encore, nous la construisons puis nous la renvoyons )
    Une fonction publique pour détruire cette instance ( destruction de l'instance )

    Et voilà, le tour est joué. C'est un des plus facile design pattern qu'il existe

    Ma classe Logger ajoute une surcharge de l'operateur<< afin de pouvoir envoyer des messages commen en C++. La définition de cette fonction template est à part.
    Je défini aussi quelques macros pour m'éviter d'écrire tout plein de fois la ligne suivante:
    (*Logguer::getLogger(...))
    Je crois qu'il est possible de faire beaucoup mieux comme logger. Notamment, je connais un excellent tuto sur DVP qui explique comment avoir un superbe singleton ( héritable ) et un superbe logger ( héritable aussi ) ... en même temps ... c'est par le créateur de la SFML ( http://loulou.developpez.com/tutorie...eur3d/partie1/ )

    Dans mon Logger, nous pouvons logguer trois types de messages:
    - Debug
    - Warnings
    - Errors

    L'astuce est que l'on passe un argument dans la fonction getLogger() du Singleton, et cet argument sera garder car il détermine le type du message. L'operateur << regarde le type de message et agit en conséquent.

    Si la variable _DEBUG est présente le Logger va écrire les messages, sinon il ne fait rien.

    Par contre, je me suis permis d'ajouter de la couleur à la console pour les Warnings ( jaune ) et les Erreurs ( rouge ). Mais ça, c'est parce que j'avais le code dans un coin .
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  9. #9
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    mai 2008
    Messages
    25 947
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : mai 2008
    Messages : 25 947
    Points : 207 568
    Points
    207 568
    Billets dans le blog
    85
    Par défaut
    Bonjour,

    Tout d'abord, j'ai ajouté quelques nouvelles fonctions à la classe 'Window' afin qu'elle soit complète ( du moins je l'espère )

    - getWindowSurface() ( c'est assez surprenant que je ne l'avais pas intégrer, c'est une des plus importantes )
    - showCursor()
    - isCursorVisible()
    - setCaption()

    Là dedans rien de compliquer.

    Maintenant, attaquons le Renderer ( ou tout ce qui va me servir à afficher des jolis trucs sur mon écran ). Comme je l'ai dit dès mon premier message, je veux avoir la possibilité de pouvoir utilisé OpenGL ou SDL à volonté, en faisant le moins de code possible

    Finalement, j'ai opté pour une fabrique ( que l'on pourrait même doubler d'un Singleton, car avoir deux Renderer cela parait idiot ).
    La fabrique est, tout comme le Singleton, un design pattern ( appelé 'Factory' ). Celui ci n'est pas bien difficile, même si c'est la première fois que j'en implémente un :red: ( du coup, je ne suis pas entièrement sur de ce que j'ai fait, mais cela marche :p )

    Le principe de base ( fabrique ou pas ) c'est de faire une interface, de façon à avoir un seul code, même si on peut changer entre OpenGL et SDL. Pour cela j'ai fait une classe 'Renderer' qui déclare des fonctions tel que:
    drawTile()
    drawBackground()

    Ces fonctions sont virtuelles pure, cela veut dire, d'une part:
    - La classe qui hérite notre Renderer, peut réimplémenter les fonctions ... De plus, comme la fonction est pure, la classe DOIT réimplémenter la fonction
    - La class Renderer n'est pas instanciable ( cela veut dire que l'on ne peut pas faire: ( ceci est une conséquence des fonctions pures )

    Après, il faut hériter notre Renderer et nous allons l'hérité avec deux classes, une pour OpenGL ( qui implémente donc les fonctions de rendu avec les commandes OpenGL ) et une avec la SDL

    Finalement, lorsque nous voulons un Renderer, nous faisons:
    ou
    Mais là, tout n'est pas encore parfait. Certes cela pourrait très bien fonctionner comme cela, mais nous allons laisser encore moins de liberté à l'utilisateur de notre classe ( et c'est ce qui complête le design pattern de la 'Fabrique' ). L'utilisateur, va au final, n'avoir accès qu'a une fonction, qui lui retournera l'instance du Renderer qu'il veut, tout cela juste en passant un enum ( cela marche aussi avec une string )
    Donc j'ai rajouter une fonction permettant de crée le bon Renderer, selon ce que je veux.

    .h:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    typedef enum RenderingAPI
    {
    	RAPI_SDL,
    	RAPI_OpenGL
    }RenderingAPI;
     
    ... // Ici, en réalité, il y a la déclaration de la classe Renderer ( voir le code source )
     
    // The creator of the renderer
    Renderer* RendererFactory(const RenderingAPI renderingAPI);
    .c:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    Renderer* RendererFactory(const RenderingAPI renderingAPI)
    {
    	switch (renderingAPI)
    	{
    		case RAPI_SDL:
    			return new RSDL();
    			break;
    		case RAPI_OpenGL:
    			return new ROpenGL();
    			break;
    	}
     
    	return NULL;
    }
    Du coup, maintenant, l'utilisateur final ne voit pas de cast, et qu'une seule fois ( et seulement par le biais d'un enum ) qu'il a choisi entre OpenGL ou SDL ( ou autre chose, car il est facile d'implémenter une nouvelle bibliothèque )

    Dans le Renderer, j'ai rajouté une fonction pour connaitre qu'elle est la bibliothèque utilisé ... je pense que cela va mettre utile dans le futur.
    L'enum est passé au constructeur du Renderer, pour que l'on force tout les héritiers ( les classes filles ) à inscrire la bibliothèque utilisée.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  10. #10
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    mai 2008
    Messages
    25 947
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : mai 2008
    Messages : 25 947
    Points : 207 568
    Points
    207 568
    Billets dans le blog
    85
    Par défaut
    Bonjour à tous,

    Cette fois j'ai ajouté les premières classes très importantes du programme ( ce n'est pas comme si les autres ne l'étaient pas )

    Donc voici ce qu'il y a en plus:

    - Sprite
    - AnimatedSprite
    - SpriteManager

    La class 'Sprite' est toute simple, permet de charger une image en passant par le SpriteManager, est de récupéré la taille et la surface. Le Renderer peut dessiner un sprite grâce à quelques fonctions ( selon les cas )

    L'AnimatedSprite n'est pas plus compliqué. Tout d'abord elle hérite de la classe Sprite. Deuxièmement, je pars du principe que l'image que l'on va avoir en entrée, est une image composé de plusieurs sprites. ( Un moment, j'ai voulu aussi passer une liste de fichiers pour construire la classe, mais cela complexifié le code pour rien ( ou presque rien ) ). Lors du dessin d'un AnimatedSprite, nous devons passé le temps de l'application ( nous reverrons cela surement plus tard ), et selon ce temps, nous changeons le Sprite à dessiner ( enfin plus précisément, la partie du Sprite à dessiner ).

    Finalement, le SpriteManager est "simple". Il utilise juste une map venant de la stdlib.
    Pour rappel, une map permet d'associer deux éléments entre autre ( comme un dictionnaire avec un mot et une définition ( d'ailleurs, des fois, cette structure de donnée s'apelle un dictionnaire ( dictionnary ) )
    Donc, le principe ici, c'est d'éviter de charger plusieurs fois la même structure. La seule chose que l'on a et surtout qui permet d'identifier l'image, c'est son nom ( ou le chemin du fichier ).
    Notre map va garder en tant qu'identifiant le nom du fichier, et va garder un pointeur sur une SDL_Surface en tant que valeur associée.
    à chaque fois que l'on veut une texture, nous regardons dans notre map afin de savoir si le nom du fichier ( clé ) y est déjà. Si on ne l'a pas déjà, nous chargeons l'image et remplissons la map avec l'association clé / pointeur sur l'image chargée.
    Si nous l'avions déjà, nous avons juste à récupérer cette valeur ( grâce à la map et au nom de l'image ) et la retourner .

    Pour la destruction des textures, elle ne se font que lorsque l'on détruit le SpriteManager et pas dans la classe Sprite ( cela rend un peu plus simple la destruction )

    Voilà tout

    Pour vraiment conclure la chose, j'ai ajouté les fonctions dans les renderers pour dessiner mes Sprite et AnimatedSprite.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  11. #11
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    mai 2008
    Messages
    25 947
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : mai 2008
    Messages : 25 947
    Points : 207 568
    Points
    207 568
    Billets dans le blog
    85
    Par défaut
    Me revoici avec quelques nouveautés,

    Premièrement, j'ai pris légèrement du retard, car mon disque dur à crasher. Je n'ai perdu aucun morceau de code écrit (de toute façon j'avais le SVN). En fait, j'ai juste perdu une journée à tout réinstaller.

    Dans cette nouvelle version, j'ai fini le code de l'AnimatedSprite, qui n'avait jusqu'ici pas été tester, et en plus, il en manquait une partie :red:
    Maintenant, je sais qu'il marche ( vous remarquerez que j'ai tendance à tester chaque morceau de code )

    J'ai aussi intégré la notion de cartes ( sans unités, mais des batiments tout de même ). Contrairement à ce que je pensais, il n'y a pas de fabrique de batiment ( peut être par la suite ... ) par contre, il y a une fabrique de Tile ( tuile ). Une Tile est une case de la carte. Actuellement, elle peut avoir son énumérateur identifiant, son AnimatedSprite associé, une defense, si c'est une tile d'eau, et si c'est un batiment. Il faudra que je rajoute aussi un facteur de coup de déplacement.

    Il existe une fabrique pour chaque Tile, qui assigne tout ses paramètre et retourne un pointeur dessus. C'est une chose assez dangereuse, que de retourner un pointeur, car cela crée une allocation, sans avoir la destruction dans le même bloc de code...

    Je pense qu'il sera facile ( et j'envisage de le faire tot ou tard ) d'utiliser des fichiers externes pour la configuration de chaque Tile ( les moddeurs auront plus de facilité ).

    Le fichie de carte est pour le moment simple ( voir le fichier uploader sur le SVN, il y a des commentaires ).
    Je répète un peu ici ce qui est dit dans le fichier:
    - Une ligne commençant par '#' est un commentaire
    La première ligne de non commentaire est le theme à utiliser ( thème graphique pour les Tile )
    La deuxième ligne est la taille de la carte, comme suit:
    width height
    Les lignes suivantes représentent la carte, en utilisant comme ID, le numéro de l'énumérateur de la tuile dans le code source.

    On notera que la création de la map est:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    map = new Tile[height][width];
    Et que cette convention est importante à garder tout au long du programme. Une erreur résulterai à un bug, visible que sur des maps rectangulaire ( non carré ) ( un crash, car on sortira du tableau ).

    L'analyseur des fichiers de cartes peut repéré des erreurs, mais si un fichier est incorrect, le programme peut planter. Il faudra peut être que je tente de voir si je ne peux pas géré les cas extrèmes avec une simple gestion des exceptions.
    Sinon, il faut tout de même savoir, qu'il existera un éditeur de cartes.

    Plus tard, je pourrai ajouter des paramètre en plus sur les cartes. Par contre, et à cause de l'analyseur, l'ordre des paramètres est important.

    La prochaine étape de prévue est de la documentation et une relecture de code ( je crains qu'il ne soit plus sale que prévue )
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  12. #12
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    mai 2008
    Messages
    25 947
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : mai 2008
    Messages : 25 947
    Points : 207 568
    Points
    207 568
    Billets dans le blog
    85
    Par défaut
    Bonjour à tous,

    Pour tout ceux qui suivaient le projet, je m'excuse d'avoir été absent, sans même prévenir... :red:

    Ceux qui suivent le projet à partir de la page du projet sur google code, remarqueront que j'avais mis en ligne la documentation ( sur le SVN ) avant mon absence.
    La nouvelle mise à jour est un code review, pour corriger quelques erreurs de design et de const correctness ( mettre des const là où il le faut ).

    J'ai aussi ajouter des compteurs pour savoir combien d'Animated Sprite / Sprite / Tiles je créais, et surtout, savoir si tout autant de destructeur étaient appelés.

    Certains constructeurs par copie ont été clairement enlevé ( Mis en private, sans implémentation ), bloquant ainsi la copie de ressources pour lesquelles nous ne voulions aucune copie supplémentaires. Si je n'avais pas fait ceci, une implémentation par défaut est produite par le compilateur ... et bien souvent, elle ne prend pas en compte les allocations faites dans les constructeurs / désallocation dans les destructeurs. ( Soit, il faut les réimplémenter dès que l'on a un pointeur dans une classe ).
    J'ai fait ceci pour le SpriteManager, la Window ( ce qui est extrèmement important, sinon nous pourrions nous voir avec plusieurs libération pour les mêmes surfaces ) et pour AnimatedSprite et Sprite.

    J'ai aussi amélioré le Renderer qui, maintenant, ne demande plus la fenêtre à chaque fois que l'on veut dessiner. Pour cela, nous acceptons un pointeur sur la Window dans le constructeur même du Renderer, et nous utilisons celui ci pour toutes les fonctions du Renderer.

    Finalement, dans les mises à jour, il y a aussi l'ajout d'une fonction afin de redimensionner ( scaling ) les SDL_Surface des images chargées. Le but d'une telle manoeuvre est d'avoir la carte 15 x 10 qui remplit toujours l'écran. Contrairement à un des projets que j'ai vu, notre écran sera toujours remplit de façon optimal.

    Les fonctions de zoom, ainsi que de dézoom ( shrink ) sont directement inspirées de la bibliothèque SDL_gfx ( bouh! ). Actuellement, la fonction de dézoom a un soucis, car elle n'accepte que des fractions de l'image.
    Pour faire tout ceci, j'ai intégré une nouvelle classe: Scaler. En fait, cette classe est totallement statique. Je vous conseille vivement de voir la documentation ( certes en anglais, mais mis à jour ).
    Le principe est que l'on a deux facteurs de redimensionnement ( un pour l'axe des X, l'autre pour les Y ), directement calculé selon la taille de la fenêtre.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    static void setScaleFactor(const Window& win);
    Par défaut, il n'y a pas de redimensionnement. Dans un usage normal, il faut appelé setScaleFactor() juste après la création de la fenêtre, et surtout avant que l'on utilise le SpriteManager.

    Ensuite, j'ai ajouté l'appel à la fonction de redimensionnement, dans le SpriteManager, afin de générer et de sauvegarder les surfaces redimensionner ( donc le redimensionnement n'est effectué qu'une seule fois ).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    SDL_Surface* pTmpScaledSurface = Scaler::scale(pTmpSurface);
    ( C'est quand même ultra simple à utiliser )

    Dans le code de l'AnimatedSprite, il y a aussi un calcul de la nouvelle taille d'un sprite, si celui ci est redimensionné.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    // We scale the size of the sprite surface (since we always apply the scaler on the surface, from the SpriteManager)
    	if ( needScaling )
    	{
    		this->widthSprite = static_cast<unsigned int>(width * Scaler::getXScaleFactor());
    		this->heightSprite = static_cast<unsigned int>(height * Scaler::getYScaleFactor());
    	}
    Finalement, le SpriteManager a subit une grosse modification, pour qu'il puisse sauvegarder les surface non redimensionnées, ainsi que les redimensionnées. Maintenant la std::map affecte une paire de SDL_Surface* ( j'ai utilisé une structure perso pour ce faire , je crois qu'une std::pair marcherai aussi ) au lieu d'une seule SDL_Surface*
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    class SpriteManager
    {
    	struct SurfacePair
    	{
    		SDL_Surface* pSprite;
    		SDL_Surface* pScaledSprite;
     
    		SurfacePair(void):pSprite(NULL),pScaledSprite(NULL) {};
    		SurfacePair(SDL_Surface* const pSprite, SDL_Surface* const pScaledSprite):pSprite(pSprite),pScaledSprite(pScaledSprite) {};
    	};
     
    private:
    	std::map<std::string, SurfacePair> spritesBank;			/*!< Bank of sprites already loaded */
     
    	// ...
    };
    Voilà, je crois avoir tout dit sur ce nouveau code.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  13. #13
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : décembre 2005
    Messages : 5 121
    Points : 11 857
    Points
    11 857
    Par défaut
    Excellente présentation , j'attends de voir les premières screen shots ! (Ben oui c'est cela qui est important !)

    Tu penses avoir ta première screen quand ?

    Sinon, superbes explications encore,
    Jc

  14. #14
    Membre confirmé

    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    février 2005
    Messages
    460
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : Industrie

    Informations forums :
    Inscription : février 2005
    Messages : 460
    Points : 593
    Points
    593
    Par défaut
    Salut !
    Bravo pour la présentation de ton projet qui est abordée avec sérieux.

    La démarche que développement que tu utilises est clairement fondée sur une approche objet, peut-être voudras tu te servir de bouml ne serait-ce que pour nous aider à voir clair cette conception.
    Conception qui d'ailleurs ressemble à d'autres projets que j'ai consultés, tu est peut-être habitué à ce développement.
    Je développe surtout "système" et j'aurai plutôt fait des essais séparés pour des tests unitaires avant de faire cette conception globale. Les outils qu'on utilise nous indiquent parfois à la voir à prendre.

    Pour la GP32X, c'est une CPU ARM de chez TI, le cortex A8. Cette CPU intègre des fonctions compatible OpenGL ES 1.0 et 2.0 (une puce du même modèle que l'iPhone mais une gamme inférieure), et pas OpenGL. Il y a qd même quelques différences qui t'oblige à coder différemment. Il est préférable de développez avec OpenGL ES car les dernières spec de OpenGL tendent vers une compatibilité.
    Le développement OpenGL, c'est quand même particulier : la spec peut-être "facilement" comprise mais l'expérience montre qu'il faut maîtriser la mise en oeuvre faute de quoi l'accélération hardware ne compensera pas tes erreurs.
    Je te conseille malgré tout de te pencher dessus car une solution SDL "tout CPU" va "bouffer" les batteries de la GP32X. L'accéleration matérielle de permettra -je pense- d'économiser sur les fonctions de zoom, rotation, alpha .... qui couteraient cher au CPU et serait plus approximatives.

    Le "Chronos Group" fournissent un SDK PC pour le développement OpenGL ES, ainsi qu'une émulation Windows/Linux. Mais c du bas niveau et quand j'avais fais des essais il n'y avait pas de code pour gérer les fontes !
    Je sais qu'il y a une extension SDL pour le rendu OpenGL, à voir si tu peux t'en servir ou si une autre extension existe pour l'OpenGL/ES.

    As-tu regardé également du côté de cocos2d, ou Qt (avec la classe QtGraphics). Peux-être la conception de cocos2d pourra te donner des idées ?

    Tu ne parles pas trop de :
    _ ton AI
    _ le design artistique. Ou-vas tu charger tes caractères ? licence prévue ? non je demande cela car les graphistes tiennent beaucoup plus que nous à la propriété intellectuelle.
    _ As-tu défini un format pour tes cartes ... histoire de pouvoir facilement en éditer ou d'en construire ?
    Selso.
    Ingénieur/CdP développement systèmes embarqués &

  15. #15
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : décembre 2005
    Messages : 5 121
    Points : 11 857
    Points
    11 857
    Par défaut
    Citation Envoyé par bizulk Voir le message
    Salut !
    Tu ne parles pas trop de :
    _ ton AI
    _ le design artistique. Ou-vas tu charger tes caractères ? licence prévue ? non je demande cela car les graphistes tiennent beaucoup plus que nous à la propriété intellectuelle.
    _ As-tu défini un format pour tes cartes ... histoire de pouvoir facilement en éditer ou d'en construire ?
    Je pense que cela venir. Si littlewhite est comme moi, il n'a pas encore tout en place mais va y arriver étape par étape ;-)

    Jc

  16. #16
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    mai 2008
    Messages
    25 947
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : mai 2008
    Messages : 25 947
    Points : 207 568
    Points
    207 568
    Billets dans le blog
    85
    Par défaut
    Merci pour vos commentaires,

    Je vais répondre dans le désordre
    Pour le format de la carte, il faut voir la première carte qui a était uploader sur le SVN. Une deuxième carte arrivera bientot

    Pour les captures d'écrans, c'est pour bientot, notamment, avec la mise à jour de demain ( enfin prévue pour demain ). Je sais que c'est important, mais montrer une fenêtre remplie qu'avec un seul type de Tile, cela me semblait peu réjouissant .
    De plus les captures d'écrans avec le 28k, ce n'est pas une partie de plaisir :p

    Pour OpenGL, je connais aussi OpenGL ES, et en fait, j'ai travaillé une année avec OpenGL ES 1 / 2 donc je pense que je n'aurai pas de problème pour l'intégration.
    Deuxième point, je n'ai pas encore de GP32X à disposition, il faut que j'aille à mon université, et ma rentrée est le 4 octobre.
    Sinon, point de vue du renderer, cela devrait être putot assez simple, juste un héritage supplémentaire du Renderer et hop, c'est fini

    Pour l'UML, j'avais fait une petite présentation au début, mais pas de vrai schéma. Et puis je crois que j'ai un peu changé par la suite Mais pour dire vrai, je fais comme fearyourself sur son projet, juste de courte réflexion et hop!
    On peut avoir des schémas très simplistes avec Doxygen et je connais Bouml ( surtout que son auteur est actif sur nos forums C++ )

    Note: Il y a aussi un SDK + simulateur, produit par Imagination Technologies pour OpenGL ES

    La license est prévue pour le code, comme indiquer sur le premier message ( du GPLv2 ) Pour la license graphique, il faut que je vois avec un hypothétique artiste ( Si quelqu'un est tenté )

    l'AI c'est pour bien plus tard ( surtout après que j'ai eu les cours de AI de l'université )
    Les caractères, c'est prévu aussi, mais pas pour le moment, car bon ... je fais morceau pas morceau.

    Et puis, je ne crois pas l'avoir dit, mais il y aura très rapidement un éditeur de cartes ( encore heureux )
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  17. #17
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    mai 2008
    Messages
    25 947
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : mai 2008
    Messages : 25 947
    Points : 207 568
    Points
    207 568
    Billets dans le blog
    85
    Par défaut
    Aujourd'hui, nous allons voir deux nouvelles classes.

    Deux, car pour moi elles sont très liées. Celles ci sont: Cursor et Camera.
    Comme vous l'avez très certainement compris, la classe Cursor va géré un curseur pouvant se balader sur la carte. Celui ci permettra de commander les unités.
    La classe Camera, va géré une caméra très simpliste. En fait, nous avons besoin d'une camera, car j'ai choisi de voir dans la fenêtre, qu'une petite partie de la carte ( 15 x 10 ). Si la carte est plus grande, nous devons déplacer une caméra, qui indiquera donc, à la méthode draw() de Map de dessiner en partant de la case 1 à 16 ( pour un décalage de la caméra d'une case sur le coté droit ). Plus précisément, la camera indique juste un décalage ( 'offset' en anglais )
    Les deux classes sont liées, car lorsque le curseur va sur la droite, ou le bas, la camera, si nécessaire, doit se déplacer.
    Le curseur va aussi nous amener à voir les évènements claviers ( et souris par la suite ) afin de déplacer le curseur.
    Si vous regardez le main.cpp au fil des versions, vous verrez que plus j'avance, plus on voit la boucle de jeu se former pour atteindre son design final.

    Fin des explications \o/

    Mon curseur doit faire les choses suivantes:

    - Avoir une position
    - Retourner la Tile juste en dessous
    - Bouger
    - Se dessiner ( à l'aide d'une AnimatedSprite )

    Ce qui donne ( sans les commentaires ):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
     
    class Cursor
    {
    private:
    	const Map* const pMap;
     
    	AnimatedSprite* pCursorSprite;
     
    	UVec2 position;
     
    	Cursor(const Cursor& c);
    	Cursor& operator= (const Cursor& c);
     
    public:
    	Cursor(SpriteManager& sm, const std::string& fileName, const Map* const pMap, const UVec2& initialPosition);
    	~Cursor(void);
     
    	Tile* getTileUnderCursor(void)const;
     
    	UVec2 getPosition()const { return position; }
     
    	bool move(const ArrowsDirection ad);
    	bool move(const UVec2& newPosition);
     
    	bool draw(const Renderer& r, const unsigned int time)const;
    };
    Le code à l'intérieur des fonctions est plus que simpliste, et je ne pense pas avoir besoin de faire de commentaires suplémentaires.
    Par contre, vous pouvez tout de même remarquer que l'implémentation du move(const ArrowsDirection ad) après avoir fait le traitement de la direction, va simplement appeler la seconde implémentation de move(). Ceci est une astuce pour avoir un seul code, même si on a deux interface ( cela évite le copier coller, car le copier coller, c'est le mal )
    ( En fait, en écrivant cette phrase, j'ai pensé à une solution, qui garde tout ces avantages, et qui est d'ajouter une fonction privée, qui elle, fait le déplacement. Les fonctions visibles par l'utilisateur ne serai que des gardes fous. Je laisse le code comme ceci, car le premier move, utilise les garde fou du second )

    --

    L'implémentation du curseur amène à avoir une première mis en place de la gestion des controles ( soit le clavier ).
    J'ai donc crée une nouvelle classe, Keyboard, qui pourrait être statique, ou encore utilisant le Singleton, mais comme tout cela me semblait superflu, c'est une classe toute simple.
    Cette classe est capable d'indiquer ( pour le moment, c'est limité ) si l'utilisateur à appuyé sur la touche 'échap' pour quitter la boucle principale et une deuxième fonction pour avoir un compte rendu de la direction sur laquelle veut aller l'utilisateur ( appuie des touches flèches ).
    J'ai crée un nouveau joli enum:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    enum ArrowsDirection
    {
    	AD_UP,
    	AD_UPRIGHT,
    	AD_RIGHT,
    	AD_RIGHTDOWN,
    	AD_DOWN,
    	AD_DOWNLEFT,
    	AD_LEFT,
    	AD_LEFTUP,
    	AD_NONE
    };
    Qui laisse la possibilité à l'utilisateur d'appuyer sur deux flèches pour aller en diagonale.

    La classe Keyboard ressemble à cela:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    class Keyboard
    {
    private:
    	unsigned char* keys;		/*!< Array of keys state */
     
    public:
    	Keyboard(void);
    	~Keyboard(void);
     
    	unsigned char isEscapePressed(void)const;
    	ArrowsDirection getDirectionPressed(void)const;
     
    	void update(void);
    };
    La fonction update permet de remplir le tableau 'keys' qui contient l'état des touches. ( Le constructeur appelle la fonction update, pour être sur de toujours avoir un tableau prêt à être utilisé ).
    La fonction update utilise les fonctions de la SDL suivantes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    SDL_PumpEvents();
    keys = SDL_GetKeyState(NULL);
    Sur certains site ( je ne cite pas de nom ) on y explique que l'on peut récupérer les évènements ( SDL_Event ) à l'aide de SDL_WaitEvent() ou SDL_PollEvent(). Certes, cela fonctionne, mais c'est loin d'être parfait. Effectivement, les fonctions SDL_*Event() ne récupère qu'un évènement un par un, alors que si l'utilisateur appuie sur deux touches en même temps, deux évènements sont crées.
    Bien sur, on peut faire en sorte de palier à ce cas, mais cela est plus pénible que d'utiliser directement SDL_GetKeyState. Si vous voulez plus de précision, et aussi l'endroit où on trouve un superbe tuto SDL, vous n'avez juste à vous déplacer sur la section tutoriel de ce site, et trouver le fabuleux tuto de Loka

    Voilà tout à propos des touches ( je chercherai à faire beaucoup mieux, beaucoup plus tard ).
    --

    Maintenant que j'ai un joli curseur qui bouge ( que la documentation est écrite ), je vais agrandir la carte ( sinon ma caméra sera inutilie ), et implémenter la caméra \o/.
    Plusieurs fois, je me suis posé la question du comment faire. Effectivement, un des problèmes, c'est de savoir si la curseur devait avoir la position sur la carte, avec, ou sans l'effet de la camera. Ainsi qu'il faut savoir comment appliquer la camera afin de faire le dessin de la bonne région.
    Donc, voici le point:

    - Le curseur doit toujours avoir la position exacte sur la carte ( sinon on ne retourne pas la bonne Tile )
    - Le curseur est la carte, doivent connaitre la position de la camera pour être dessiner au bonne endroit sur l'écran.
    - La camera se déplace selon la position du curseur, mais ne peux pas se déplacer, dépendant de sa position sur la carte

    Ce qui nous donne les prototypes de fonctions suivants:

    Dans la classe Camera:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    class Camera
    {
    private:
    	UVec2 position;
     
    	void moveLeft();
    	void moveUp();
    	void moveRight(const Map& map);
    	void moveDown(const Map& map);
     
    public:
    	Camera(void);
    	~Camera(void);
     
    	void update(const Cursor& c, const Map& map);
     
    	UVec2 getPosition(void)const { return position; }
    };
    Dans la classe Map ( changement ):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    bool draw(const Renderer& r, const Camera& c, const unsigned int time);
    Dans la classe Cursor ( changement ):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    bool draw(const Renderer& r, const Camera& c, const unsigned int time)const;
    Et ça fonctionne \o/ ( voir les captures d'écrans )

    Note: Il y a un premier HACK, malgré que je sois totalement contre ces pratiques de barbares, j'ai du remplacé un SDL_BlitSurface par un memcpy ( vive le gorille ) car le SDL_BlitSurface ne voulais pas copier la composante alpha ... allez savoir pourquoi...

    Note: Les images que j'utilise actuellement, sont des images qui ont déjà subi un redimensionnement ( de 16x16 à 32x32 ) en utilisant le célèbre logiciel GIMP. Contrairement à mon programme, celui ci dispose d'un vrai algorithme de redimensionnement, sans failles. Après, mon programme redimensionne donc encore une fois les images, ce qui peut encore diminuer la qualité.

    Note: Il faut savoir que dans Advance Wars 2, certain sprites ont une taille non réglementaires ( plus que 16 x 16 ( les montagnes et les quartiers généraux ) ). De plus, il y a une gestion des ombres très simplistes, mais qui existe. J'ai rajouté un morceau de code, afin de géré les taille démesurées de ces sprites.
    La méthode est de vérifié la taille du sprite avec la taille que devrait avoir le sprite ( soit par defaut 32 * la facteur de redimenssionnement ). S'il y a un écart, nous l'enlevons à la position de dessin de la tuile, afin de pouvoir dessiner tout le sprite. Et hop, le tour est joué. Les ombres se sera pour plus tard .
    Du coup, et pour que ce soit plus beau sur mes captures d'écran ( et aussi pour pouvoir vérifié que la Camera fonctionne ) j'ai modifié ma carte afin d'avoir des arbres et des montagnes ( Wouhou \o/ ! ).

    On en remarquera un bug, qui amènera à la prochaine solution:
    Il faut faire d'abord, des prairies tout partout, et après on applique le sprite de montagne, qui aura tout le fond en transparent.

    Note sur les captures d'écran:
    - La première est la carte sans redimensionnement
    - La deuxième avec le redimensionnement à la volée
    - La troisième, c'est la camera déplacer sur la droite
    - La quatrième, la même carte, mais la camera déplacée sur le bas
    Images attachées Images attachées     
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  18. #18
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : décembre 2005
    Messages : 5 121
    Points : 11 857
    Points
    11 857
    Par défaut
    Citation Envoyé par LittleWhite Voir le message
    ( En fait, en écrivant cette phrase, j'ai pensé à une solution, qui garde tout ces avantages, et qui est d'ajouter une fonction privée, qui elle, fait le déplacement. Les fonctions visibles par l'utilisateur ne serai que des gardes fous. Je laisse le code comme ceci, car le premier move, utilise les garde fou du second )
    C'est ce que je fais généralement quand ce cas se présente ;-)


    L'implémentation du curseur amène à avoir une première mis en place de la gestion des controles ( soit le clavier ).
    J'ai donc crée une nouvelle classe, Keyboard, qui pourrait être statique, ou encore utilisant le Singleton, mais comme tout cela me semblait superflu, c'est une classe toute simple.
    C'est propre mais moi je ne fais rarement cela, sauf si cela est pour des raisons de vouloir passer à autre chose que la SDL, je ne le fais plus...

    Sur certains site ( je ne cite pas de nom ) on y explique que l'on peut récupérer les évènements ( SDL_Event ) à l'aide de SDL_WaitEvent() ou SDL_PollEvent(). Certes, cela fonctionne, mais c'est loin d'être parfait. Effectivement, les fonctions SDL_*Event() ne récupère qu'un évènement un par un, alors que si l'utilisateur appuie sur deux touches en même temps, deux évènements sont crées.
    So déjà tu fais une classe Keyboard, ajoute juste un tableau de touches et à chaque KEY_DOWN, mets un bit en place, à chaque KEY_UP, remets le bit à 0.

    Plusieurs fois, je me suis posé la question du comment faire. Effectivement, un des problèmes, c'est de savoir si la curseur devait avoir la position sur la carte, avec, ou sans l'effet de la camera. Ainsi qu'il faut savoir comment appliquer la camera afin de faire le dessin de la bonne région.
    J'ai toujours eu les meilleurs résultats avec :
    - Le curseur a la vraie position
    - La caméra demande le dessin du curseur en précisant la position à l'image

    Ainsi, la position logique du curseur est connu par tous, seule la caméra décide où se dessine le curseur...

    Si jamais tu changes de résolution, la facon dont est gérée la carte, cela fonctionne mieux je pense.

    - Le curseur doit toujours avoir la position exacte sur la carte ( sinon on ne retourne pas la bonne Tile )
    Oui.

    - Le curseur est la carte, doivent connaitre la position de la camera pour être dessiner au bonne endroit sur l'écran.
    Non, seul la caméra connait sa position.

    - La camera se déplace selon la position du curseur, mais ne peux pas se déplacer, dépendant de sa position sur la carte
    En fait, la caméra se déplace dépendant de la position du curseur. Elle ne se déplace pas vraiment, elle fait tout par rapport à la carte.

    Moi j'ai une tendance à virer la caméra et laisser la carte s'afficher... Mais c'est mon système ;-)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    	void moveLeft();
    	void moveUp();
    	void moveRight(const Map& map);
    	void moveDown(const Map& map);
    Pourquoi juste 2 fonctions ont la map en argument ?

    Note: Il y a un premier HACK, malgré que je sois totalement contre ces pratiques de barbares, j'ai du remplacé un SDL_BlitSurface par un memcpy ( vive le gorille ) car le SDL_BlitSurface ne voulais pas copier la composante alpha ... allez savoir pourquoi...
    Probablement une de tes surfaces est en RGB à la place de RGBA.

    On en remarquera un bug, qui amènera à la prochaine solution:
    Il faut faire d'abord, des prairies tout partout, et après on applique le sprite de montagne, qui aura tout le fond en transparent.
    Oui c'est le plus simple ;-)

    Jc

  19. #19
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    mai 2008
    Messages
    25 947
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : mai 2008
    Messages : 25 947
    Points : 207 568
    Points
    207 568
    Billets dans le blog
    85
    Par défaut
    Citation Envoyé par fearyourself Voir le message
    So déjà tu fais une classe Keyboard, ajoute juste un tableau de touches et à chaque KEY_DOWN, mets un bit en place, à chaque KEY_UP, remets le bit à 0.
    C'est ce que nous donne la fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    SDL_GetKeyState(NULL);
    un tableau avec l'état des touches. Donc je n'ai aucun problème avec ça

    Citation Envoyé par fearyourself Voir le message
    J'ai toujours eu les meilleurs résultats avec :
    - Le curseur a la vraie position
    - La caméra demande le dessin du curseur en précisant la position à l'image

    Ainsi, la position logique du curseur est connu par tous, seule la caméra décide où se dessine le curseur...
    Donc, dans votre système, c'est la camera qui dessine le curseur, ainsi que la Map ? ( j'ai du me perdre dans l'explication )

    Citation Envoyé par fearyourself Voir le message
    Si jamais tu changes de résolution, la facon dont est gérée la carte, cela fonctionne mieux je pense.
    Je ne pense pas avoir de problème avec les résolutions ...

    Citation Envoyé par fearyourself Voir le message
    Non, seul la caméra connait sa position.
    Cela revient à dire, qu'au lieu de passer toute la camera aux fonctions de dessins, je dois passer juste la position ... les deux reviennent au même, je ne sais pas ce qui est le meilleur


    Citation Envoyé par fearyourself Voir le message
    En fait, la caméra se déplace dépendant de la position du curseur. Elle ne se déplace pas vraiment, elle fait tout par rapport à la carte.
    Oui je pense que c'est ce que j'ai fais

    Citation Envoyé par fearyourself Voir le message
    Moi j'ai une tendance à virer la caméra et laisser la carte s'afficher... Mais c'est mon système ;-)
    Oui, bah moi ça marche aussi ... je pense laisser comme ça

    Citation Envoyé par fearyourself Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    	void moveLeft();
    	void moveUp();
    	void moveRight(const Map& map);
    	void moveDown(const Map& map);
    Pourquoi juste 2 fonctions ont la map en argument ?
    Oui, pourquoi ? Non je sais pourquoi, c'est simplement car moveLeft() et moveUp() font une vérification par rapport à 0... les autres vérifient par rapport à la taille de la carte ...

    Citation Envoyé par fearyourself Voir le message
    Probablement une de tes surfaces est en RGB à la place de RGBA.
    ... Je doute ... les deux avaient 32 bits par pixel ( voir le code du Scaler )

    Citation Envoyé par fearyourself Voir le message
    Oui c'est le plus simple ;-)
    Vous allez voir à la prochaine mise à jour
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  20. #20
    Membre averti
    Homme Profil pro
    Lycéen
    Inscrit en
    novembre 2008
    Messages
    86
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : novembre 2008
    Messages : 86
    Points : 363
    Points
    363
    Par défaut
    Salut, je vois que ça avance, félicitations !

    Allez, je donne aussi un peu de mes nouvelles :

    De mon côté, j'avance à pas de géa... nains

    Mais j'ai également quelques images, carte avec un bâtiment, en utilisant du script lua par exemple pour :
    - gestion contextuelle des tiles (par exemple pour une route, déterminer quelle animation jouer
    - appel de fonction lorsque la souris passe au-dessus d'une entité de jeu (graphique) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    --[[ Called when mouse is over a game entity.
    entity Reference to the game entity.
    ]]
    function onMouseOverGameEntity(entity)
        if (entity == nil) then
            return
        end
        local class = entity:getClass()
        if (class == TILE) then
            tile:xsprite():setFilter(sf.Color(175, 200, 250, 240))
            return
        elseif (class == BUILDING) then
            print "Over a building!"
        end
    end
    Donc je te conseille fortement de t'y mettre aussi! (quelques images ici).

Discussions similaires

  1. [Projet en cours] Strategy(nom provisoire) - Advance wars like
    Par TiranusKBX dans le forum Projets
    Réponses: 17
    Dernier message: 29/09/2016, 15h46
  2. [VB6] [ADO] Like sur base Access
    Par dlpxlid dans le forum VB 6 et antérieur
    Réponses: 9
    Dernier message: 24/01/2003, 11h03
  3. Créer un interpréteur de langage inspiré du Basic
    Par Picasso dans le forum Algorithmes et structures de données
    Réponses: 4
    Dernier message: 11/05/2002, 17h10

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