Bienvenue, Invité. Merci de vous connecter ou de vous inscrire.
Avez-vous perdu votre e-mail d'activation ?

Auteur Sujet: Framework  (Lu 49313 fois)

0 Membres et 6 Invités sur ce sujet

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Re : Framework
« Réponse #75 le: Décembre 07, 2013, 10:32:41 am »
Bon je vais commencer à implémenter le système de resource holder du bouquin ainsi que les states, et, je compte séparer les states en 2 parties :

-Les "GameStates" qui seront les options de rendu du jeux (Le mode vidéo,  les options de rendu (affichage des lumières, ombres, shaders ?) et tout les states qui ne se dessinent pas.
-Les "GuiStates" qui concerneront plutôt l'affichage des menus et des gui IG, la gestion de l'input et des commandes, etc...

Mais il me faut trouvé un compilateur qui supporte le c++11 et le dwarf 2 sinon ça ne compile pas chez moi, le compilateur TDM qui ne gère que le sjlj, ça ne marche pas. :/

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Re : Framework
« Réponse #76 le: Décembre 07, 2013, 12:36:33 pm »
Bon, j'en ai presque fini avec le resource holder par contre je préfère vraiment gérer les ids via une variable statique pour être sur que les ids se suivent et qu'ils soient vraiment unique. (Encore un truc que j'ai appris à l'école xd)

Je pense que je ne vais pas utiliser le c++11 pour l'instant car les nouveaux compilateurs ne semble pas compatible avec toutes les librairies... (Bref de mon côté le système sjlj me pose problème au niveau de la compatibilité)

Bref les mutex et les thread de sfml devraient faire l'affaire pour l'instant, au pire je me renseignerai sur pthread pour savoir comment utiliser d'autres primitive de synchronisation avec cette librairie.

Cmdu76

  • Full Member
  • ***
  • Messages: 194
    • Voir le profil
Re : Framework
« Réponse #77 le: Décembre 07, 2013, 01:45:30 pm »
Je crois que tu n'as pas vraiment compris le but des States, la classe State doit être abstraite, c'est au développeur qui va créer son jeu de la reutiliser comme il le veut. Il peut creer un State qui melange le Monde et des GUI, il peit mettre un State qui est une sprite et des GUi... enfin bref il choisi tout ce qu'il veut au niveau de l'affichage, lui imposer des states speciaux est inutile si tu réduis les possibilités qui sont permises à la base...
Et pour le resource, le système que je t'avais envoyé par Skype avec des enums est plus simple et plus compréhensible pour l'utilisateur car il associe lui même les ID et il peut en faire autant qu'il veut

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Re : Framework
« Réponse #78 le: Décembre 07, 2013, 02:17:33 pm »
Ok, je vois pour les states, donc en gros tu veux par exemple que je fasse un state qui affiche les lumières, un autre qui n'affiche pas les lumières, etc..., et dessiner celui que je veux.
Ca pourrait en effet être intéressant.

Mais je n'aime pas trop l'idée de pouvoir laisser l'utilisateur mettre ce qu'il veut comme id.

Qu'est ce qui se passerais si l'utilisateur met 2 fois le même id pour 2 ressources différentes ?

Bref, pour moi, chaque id doit être unique à chaque objet et atomique. (c'est à dire composé d'une seule variable (par exemple un char, un int, un long, un short, etc...))

Le but d'un id est justement de désigner un objet de manière unique.

C'est un peu comme un pointeur si tu veux à l'exception que l'id ne référence pas une adresse mémoire unique, mais c'est juste un nombre (comme l'indice d'un tableau par exemple) qui permet de référencer un objet unique dans un ensemble d'objets.

MySQL utilise se système d'ailleurs, pourquoi ne pas le réutiliser ici ?

De plus je trouve ça vraiment plus pratique pour faire des références à des objets grâces à des int dans un fichier ou une base de donnée que de le faire avec n'importe quel type d'id qui pourrait référencer plusieurs objets et compliquer ainsi les choses.
Bref moi on m'a toujours conseillé de travailler avec un id unique pour chaque objet créer avec une classe, ou bien avec un système de gestion de base de données, ou bien avec n'importe quel autre système.


#ifndef RESOURCEMANAGER_HPP_INCLUDED
#define RESOURCEMANAGER_HPP_INCLUDED

#include <map>
#include <string>
#include <memory>
#include <stdexcept>
#include <cassert>

namespace sfgl
{


template<typename R> class ResourceManager
{
        public:
                void            load(const std::string& filename);
                R                       getByPath(const std::string& path) const;
                R                       getById(const int id) const;
                void        deleteResource (const std::string &path);
        private:
                struct Resource {
                Resource (std::string path, R* resource) {
                    this->path = path;
                    this->resource = resource;
                }
                ~Resource() {
                    delete resource;
                    nbResources--;
                }
                R resource;
                std::string path;
                int id;
            };
                void insertResource(const std::string &path, R* resource);
                void updateIds(const int &id);
                static int nbResources;
        std::map<int, Resource*>        mResourceMap;
};

///////////////////////////////////////////////////////////////////////////////
// IMPLEMENTATION                                                            //
///////////////////////////////////////////////////////////////////////////////
template <typename R> int ResourceManager<R>::nbResources = 0;
template <typename R>
void ResourceManager<R>::load(const std::string& filename)
{
        // Create and load resource
        R* resource(new R());
        if (!resource->loadFromFile(filename))
                throw Erreur(6, "ResourceManager::load - Failed to load ",0);
        // If loading successful, insert resource to map
        insertResource(resource);
}

template <typename R>
R ResourceManager<R>::getById(int id) const
{
        Resource &found = *mResourceMap.find(id);
        if(found == mResourceMap.end())
        return nullptr;
        return found->second.resource;
}

template <typename R>
R ResourceManager<R>::getByPath(const std::string &path) const
{
    typename std::map<int, Resource*>::iterator it;
    for (it = mResourceMap.begin(); it != mResourceMap.end(); it++) {
        if (it->second.path == path)
            return it->second.resource;
    }
        return nullptr;
}

template <typename R>
void ResourceManager<R>::insertResource(const std::string &path, R* resource)
{
        // Insert and check success
        Resource* r = new Resource (path, resource);
    mResourceMap.insert(std::make_pair(nbResources, r));
}
template <typename R> void ResourceManager<R>::updateIds (const int &id) {
    typename std::map<int, Resource*>::iterator it;
    for (it = mResourceMap.begin(); it != mResourceMap.end(); it++) {
        if (it->first > id) {
            it->first--;
        }
    }
}
template <typename R> void ResourceManager<R>::deleteResource(const std::string &path) {
    typename std::map<int, Resource*>::iterator it;
    for (it = mResourceMap.begin(); it != mResourceMap.end();) {
        if (it->second.path == path) {
            updateIds(it->first);
            delete it->second;
            mResourceMap.erase(it);
        } else
            it++;
    }
}
}

////////////////

namespace sf
{
    class Texture;
    class Font;
    class Shader;
    class SoundBuffer;
}

namespace sfgl
{

typedef ResourceManager<const sf::Texture*>      TextureManager;
typedef ResourceManager<const sf::Font*>         FontManager;
typedef ResourceManager<const sf::Shader*>       ShaderManager;
typedef ResourceManager<const sf::SoundBuffer*>  SoundBufferManager;

}


#endif // RESOURCEMANAGER_HPP_INCLUDED
 

Par contre faudrait que je revois un peu la redéfinition de template si je veux que R soit absolument un pointeur constant. (Vu que il faudrait éviter de modifier les ressources via le CPU)

J'ai essayer de redéfinir R en const R* pour toutes les fonctions cependant, j'ai une erreur à la compilation comme quoi il me dit qu'il ne peut pas convertir const Texture const* en const Texture* lorsque j'utilise un get.
« Modifié: Décembre 07, 2013, 02:28:14 pm par Lolilolight »

Cmdu76

  • Full Member
  • ***
  • Messages: 194
    • Voir le profil
Re : Framework
« Réponse #79 le: Décembre 07, 2013, 02:31:30 pm »
Nan c'est pas dutout ce que je voulais dire, justement même tout le contraire !
Finalement on crée un State qui ne dessine RIEN, c'est l'utilisateur qui va choisir ce que son State va dessiner en créant par exemple une classe GameState (qui PAR EXEMPLE peut dessiner le monde + des GUI + des sprites banales (ce qui est presque inutile mais c'est pour montrer que c'est lui qui choisi))

Ensuite dans un enum, chaque entrée est associé à une valeur unique donc on a pas le problème de l'avoir deux fois...

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Re : Framework
« Réponse #80 le: Décembre 07, 2013, 02:49:17 pm »
Oui, mais une enum ça sert plutôt pour le développeur ça, pour définir un ensemble restreins de valeurs possibles que peut prendre une variable.

Je ne vois pas comment on pourrait utiliser ça pour créer des ids.

Surtout que, les ids ne sont pas prédéfini à l'avance contrairement aux valeurs des l'enums.

Le développeur peut créer autant d'objets qu'il veut. (Et avec ton idée il faudrait donc, rajouté des valeurs dans l'enum à chaque fois que le développeur va recréer un nouvel objet)

Bref, je trouve pas ça si bien personnellement ou alors je n'ai pas très bien compris ce que tu veux faire.

En tout cas moi, je crée un objet, il a l'id 0, j'en recrée un deuxième, il a l'id 1, et ainsi de suite..., et lorsque j'en supprime un, bah tout ceux qui ont un id plus élevé que lui voient leur id diminué de 1. (Ainsi j'ai toujours des id qui se suivent pour tout les objets que j'ai créer et je me retrouve pas 2 fois avec le même id)

Je doute fort qu'on sache faire ça avec des enums ou alors faudrait vraiment que tu me montre un exemple de code source qui le fait parce que là je ne te suis vraiment pas. :o

Cmdu76

  • Full Member
  • ***
  • Messages: 194
    • Voir le profil
Re : Framework
« Réponse #81 le: Décembre 07, 2013, 03:07:54 pm »
Le problème est que du coup peut etre que les id sont bien ordonnes (mais au final avec les enmus c'est pas si important)
mais après il fait récuperer l'id et le ressortir a chaque fois...

Par contre je pense que ducoup le getByPath peut être une solution

Aussi tant qu'à faire,

R get(const std::string& path) const;
R get(const int id) const;

C'est plus simple comme ça et ça ne perd pas son sens dans la doc

Et du coup je parlais de retourner l'id, donc tant quà faire :

/// \return The id of the loaded resource
int load(const std::string& filename);

Sinon comment moi (enfin je tire ça du livre SFML une fois de plus) je procède :

- L'utilisateur crée un fichier "ResourceIdentifiers.hpp" dedans il crée le namespace Textures avec l'enum en question contenant une entrée avec une valeur pour chaque texture qu'il voudrait utiliser.
- Ensuite dans la classe Application, tu donnes en paramètres de load(Textures::ID id, std::string const& filename);
- Du coup quand tu veux utiliser la texture ailleurs, tu as juste à faire : get(Textures::ID id);

Oui, mais une enum ça sert plutôt pour le développeur ça, pour définir un ensemble restreins de valeurs possibles que peut prendre une variable.

Du coup, dans mon exemple tu limites tes valeurs aux ID que tu veux.

Ainsi j'ai toujours des id qui se suivent pour tout les objets que j'ai créer et je me retrouve pas 2 fois avec le même id

Je ne vois pas en quoi le fait d'avoir des id qui ne se suivent pas est gênant...
Et moi non plus je ne peux pas me retrouver avec deux fois la même ID, mon Id (mon Id corresponds à une case un tableau basique ( monVector[ID] ) ) sera juste redéfinie avec le 2ème fichier que je donne.

Encore une fois pour les exemples, n'hésite pas à aller voir le livre SFML ou à checker mon projet GameTest sur GitHub : https://github.com/Cmdu76/GameTest
« Modifié: Décembre 07, 2013, 04:02:52 pm par Cmdu76 »

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Re : Framework
« Réponse #82 le: Décembre 07, 2013, 05:20:43 pm »
Bof, je ne suis pas fan du système qu'il y a dans le livre, je trouve que ça complique bien les choses surtout que mon système permet de faire exactement la même chose mais en plus simple! (Sans devoir recréer un fichier ResourceIdentifiers.hpp et tout ce bazar auquel je n'y comprend absolument rien)

Mais comme tu dis je pourrai très bien rajouter des méthodes :

R get(const int id) const;
/// \return The id of the loaded resource
int load(const std::string& filename);
 

Je compte d'ailleurs le faire par la suite, ainsi on pourra récupérer la ressource, soit suivant sont path, ou bien avec son id, ou bien même retourner l'id d'une resource à partir de son path ou bien à partir de la ressource elle même, ou bien charger plusieurs ressources d'un coup.
Bref, ça, ce sera comme lui le développeur le veux, tout ce que je veux c'est proposer des classes qui offrent le maximum de possibilités de manière la plus simple qui soit.
« Modifié: Décembre 07, 2013, 05:26:50 pm par Lolilolight »

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Re : Framework
« Réponse #83 le: Décembre 08, 2013, 12:37:53 pm »
Voilà j'ai fini d'améliorer la classe qui gère les ressources.

Demain je commencerai à faire le système de states et de gui, et ensuite, je commencerai à faire les tutoriels pour tester tout ça et le forum sur des sites temporaire afin de sortir une première version stable. (En attendant d'avoir mon propre site web)

Car je n'ai pas le temps de m'occuper du site web de SFGL pour l'instant.



Lo-X

  • Hero Member
  • *****
  • Messages: 618
    • Voir le profil
    • My personal website, with CV, portfolio and projects
Re : Framework
« Réponse #84 le: Décembre 08, 2013, 01:38:09 pm »
Le soucis de l'enum c'est que c'est contraignant, cepandant il permet plus de modularité que les autres, je m'explique :

Gérer les ressources uniquement en fonction du filepath, c'est le plus simple pour l'utilisateur, mais ça peut devenir très embêtant. En effet, si soudainement notre texture de vaisseau utilisée par 10 classes dans le jeu vient à changer de nom, il faut changer ça en 10 endroits du code. Avec un Texture::ID il ne faut le faire qu'à un seul endroit

Avoir des IDs imposés pour l'utilisateur ça rime à rien, en effet il faut qu'il retienne quelque part que l'ID retourné c'est telle texture, donc il doit faire le boulot des ResourceHolder au final.

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Re : Framework
« Réponse #85 le: Décembre 08, 2013, 02:42:24 pm »
Oui le but du ressource holder c'est justement ça : si on change le path de la texture, on n'a qu'à le changer à un endroit dans le code et pas a 10 endroits différents si plusieurs entités utilisent la même texture. (Ce qui peut bien sûr arriver)

Et l'utilisateur n'est pas obligé de retenir l'id de la texture, l'id de la texture me sert juste à lier une texture à une entité dans le fichier de sauvegarde du monde. (Donc si il sait ou la texture se trouve c'est suffisant, il n'uara qu'à faire un getResource(path) pour la récupérer, il n'a pas besoin de retenir l'id)

Si le path de la texture change, il n'a qu'à le changer lors de l'appel à la fonction load du resource holder..., donc, il n'y a pas vraiment besoin que l'utilisateur puisse créer ses propres id pour faire ça.

Maintenant si tu veux faire un alias vers l'id de la texture pour la récupérer d'une autre manière que de part son id ou son path, cela revient à recréer son propre resource holder en effet...
Mais personnellement je n'en vois pas trop l'intérêt, le chemin relatif vers la texture est suffisant.

A la limite je pourrai toujours rajouté plus tard la possibilité au développeur de créer un alias vers le path de la texture, mais, pour le moment, ce n'est pas ma priorité.

PS : Et si il veut récupérer l'id de la texture il n'a qu'à appeler la fonction getId(path) du resource holder et garder l'id de la texture en mémoire un peu comme le fait opengl avec ses fonctions pour créer des textures, des shaders, ou n'importe quoi.
PS 2 : et de toute façon dans mon framework, je n'utilise le path qu'à un seul endroit, c'est au chargement de la texture ensuite je garde l'id de la texture en mémoire, (ou le path peut importe) et puis, je passe un pointeurs sur la texture à mon entité.

string pathToTexture = "PathToTexture";
holder.load(pathToTexture);
int id = holder.getId(pathToTexture);
Entity entite = new Entity(holder.getResource(id), position, size, origin, type);
 

Ou bien :
string pathToTexture = "PathToTexture";
holder.load(pathToTexture);
Entity entite = new Entity(holder.getResource(pathToTexture), position, size, origin, type);
 

Donc voilà si je change le path il n'y a qu'à changer la 1ère ligne de code.

Maintenant bien sûr il ne faut pas faire ça :
holder.load("PathToTexture");
Entity entite = new Entity(holder.getResource("PathToTexture"), position, size, origin, type);
 
Sinon là il faudra changer le code source à 2 endroits.
Mais je préfère laisser le soin au développeur de gérer lui même ses variables pour le stockage des id ou path vers les textures dans le programme ou bien dans un fichier.

Donc pour répondre à ta question, si il veut utiliser autre chose comme identifiant (une enum par exemple) il faudra en effet qu'il recrée son propre ressource holder.

Mais je pense pas que ça soit nécessaire de le faire, en tout cas moi dans le projet Sorrok je n'ai pas eu besoin de le faire.
Sinon, comment tu ferais si le développeur a envie de sauver les paths de textures ou les id de texture dans un fichiers ???
(Chose que je fais avec le projet Sorrok)

« Modifié: Décembre 08, 2013, 03:37:35 pm par Lolilolight »

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Re : Framework
« Réponse #86 le: Décembre 08, 2013, 06:15:42 pm »
Bien que ce n'est pas très compliqué à faire et je crois que je vais d'ailleurs le faire, mais pas vraiment besoin d'utiliser une enum pour faire ça, un string suffit, il faut juste que je m'arrange pour que l'alias soit unique pour chaque texture :

holder.load("pathToTexture", "AliasToTexture");
Texture *t = holder.getResource("AliasToTexture");
 

Je pense que j'ai enfin compris ce que tu veux as voulu me dire.

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Re : Framework
« Réponse #87 le: Décembre 08, 2013, 10:09:54 pm »
Bon voilà c'est fait j'ai rajouté un alias pour chaque texture, j'essaye de mettre ça sur git hub bah, dès que ce git commit et ce git push marcheront...

Soit je vais finir la 1ère version du framework je pense (en me basant sur le système de state, gui et command de Cmdu76.

Et ensuite, je mettrai tout d'un coup sur github. (Une fois que j'aurai testé tout ça)

Et enfin je ferai les tutoriels et la doc.

Ca devrait me prendre +/- 1 mois...


Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Re : Framework
« Réponse #88 le: Décembre 09, 2013, 05:00:47 pm »
Salut, je pensais faire un conteneur dans la classe Application ou j'ajouterai tout les ressources holder.


TextureManager tm;
FontManager fm;
SoundManager sm;
Application::addResourceManager(TextureManager, "TextureManager");
Application::addResourceManager(FontManager, "FontManager");
Application::addResourceManager(SoundManager, "SoundManager");
 

Cependant étant donné que ma classe ResourceManager est template, je peux pas le faire, car, je peux pas faire ceci :
template <typename R> std::map<std::string, ResourceManager <R> > resourceManagers;
 

Bref je ne vois pas d'autre moyen que de le faire en utilisant un code source du genre boost::any.

template <typename R> std::map<std::string, any> resourceManagers;
 

Surtout que chaque resource holder devrait être unique à l'application.

J'ai pensé à faire une classe super classe mais cela na marche pas non plus car si je fais des fonctions template virtuelle le compilateur n'est pas content.

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Re : Framework
« Réponse #89 le: Décembre 10, 2013, 06:08:37 pm »
Bon j'ai enfin réussi à compiler et à tester le système de resource holder et ça semble fonctionner! :D

//#include <SFGL/utilities.h>
#include <vector>
#include <iostream>
#include "SFGL/Core/game.h"
#include "SFGL/Core/ResourceManager.h"*/
#include <SFML/Graphics.hpp>
#include "SFGL/Graphics/2D/tile.h"
using namespace sfgl;
using namespace sf;
int main () {
    TextureManager tm;
    tm.load("tilesets/herbe.png", "HERBE");
    Tile *t = new Tile(tm.getResourceByAlias("HERBE"), Vec2f(0, 0), Vec2f(100, 50),IntRect(0, 0, 100, 50), 0);
    // create the window
    sf::RenderWindow window(sf::VideoMode(800, 600), "My window");

    // run the program as long as the window is open
    while (window.isOpen())
    {
        // check all the window's events that were triggered since the last iteration of the loop
        sf::Event event;
        while (window.pollEvent(event))
        {
            // "close requested" event: we close the window
            if (event.type == sf::Event::Closed)
                window.close();
        }

        // clear the window with black color
        window.clear(sf::Color::Black);

        // draw everything here...
        window.draw(*t);

        // end the current frame
        window.display();
    }
    delete t;
    tm.deleteResourceByAlias("HERBE");
}
 

Bref ceci n'est qu'un test, plus tard il faudra redéfinir les méthodes init, update et render de la classe application ceci afin de réduire le nombres de lignes de code dans le main.

La méthode init : c'est dans cette méthode qu'il faudra faire tout chargement de ressources, le chargement de la map, etc.... (que ça soit à partir d'un serveur ou bien de la machine locale)

La méthode update (c'est là dedans qu'il faudra remettre à jour la frame courante pour le rendu, traiter les évènement, etc...)

La méthode render (c'est là dedans qu'il faudra afficher les states courants)

A terme le main ressemblera donc à ceci :

int main () {
     Application app;
     return app.exec();
}
 
C'est dans la méthode exec que je compte appeler les méthodes init, update et render. (Je sais je m'inspire un peu de QT mais je trouve ça vraiment pas mal.