Cela dépend de l'étendue de votre jeu. Un gestionnaire d'actifs est absolument essentiel pour les grands titres, moins pour les petits jeux.
Pour les titres plus volumineux, vous devez gérer des problèmes tels que les suivants:
- Ressources partagées - cette texture de brique est-elle utilisée par plusieurs modèles?
- Durée de vie de l'actif - cet actif que vous avez chargé il y a 15 minutes n'est-il plus nécessaire? Référence comptant vos actifs pour vous assurer que vous savez quand quelque chose est terminé, etc.
- Dans DirectX 9 si certains types d'actifs sont chargés et que votre périphérique graphique est 'perdu' (cela se produit si vous appuyez sur Ctrl + Alt + Suppr entre autres) - votre jeu devra les recréer
- Chargement des actifs avant d'en avoir besoin - vous ne pourriez pas créer de grands jeux en monde ouvert sans cela
- Chargement en masse d'actifs - Nous regroupons souvent de nombreux actifs dans un seul fichier pour améliorer les temps de chargement - la recherche autour du disque prend beaucoup de temps
Pour les petits titres, ces choses sont moins problématiques, les cadres comme XNA ont des gestionnaires d'actifs en eux - il est très inutile de le réinventer.
Si vous avez besoin d'un gestionnaire d'actifs, il n'y a pas vraiment de solution unique, mais j'ai trouvé qu'une carte de hachage avec la clé comme hachage * du nom de fichier (abaissé et séparateurs tous «fixes») fonctionne bien pour les projets sur lesquels j'ai travaillé.
Il n'est généralement pas conseillé de coder en dur les noms de fichiers dans votre application, il est généralement préférable qu'un autre format de données (tel que xml) représente les noms de fichiers en «ID».
- Comme note latérale amusante, vous obtenez normalement une collision de hachage par projet.
(Essayer d'éviter la discussion "n'utilisez pas de gestionnaire d'actifs" ici, car je considère que c'est hors sujet.)
Une carte clé / valeur est une approche très utilisable.
Nous avons une implémentation ResourceManager où les usines pour différents types de ressources peuvent s'inscrire.
La méthode "getResource" utilise des modèles pour trouver la fabrique correcte pour le type de ressources souhaité et renvoie un ResourceHandle spécifique (en utilisant à nouveau le modèle pour renvoyer un SpecificResourceHandle).
Les ressources sont recomptées par le ResourceManager (à l'intérieur du ResourceHandle) et libérées lorsqu'elles ne sont plus nécessaires.
Le premier addon que nous avons écrit était la méthode "reload (XYZ)", qui nous permet de changer les ressources de l'extérieur du moteur en cours d'exécution sans changer de code ni recharger le jeu. (Ceci est essentiel lorsque les artistes travaillent sur des consoles;))
La plupart du temps, nous n'avons que sur l'instance du ResourceManager, mais parfois nous créons une nouvelle instance juste pour un niveau ou une carte. De cette façon, nous pouvons simplement appeler «shutdown» sur le levelResourceManager et nous assurer que rien ne fuit.
(bref) exemple
la source
Les classes de gestionnaire dédié ne sont presque jamais le bon outil d'ingénierie. Si vous n'avez besoin de l'actif qu'une seule fois (comme un arrière-plan ou une carte), vous ne devez le demander qu'une seule fois et le laisser mourir normalement lorsque vous en avez terminé. Si vous devez mettre en cache un type particulier d'objet, vous devez utiliser une fabrique qui vérifie d'abord une antémémoire et charge autrement quelque chose, la place dans la mémoire cache, puis la renvoie - et cette fabrique peut simplement être une fonction statique accédant à une variable statique , pas un type à part.
Steve Yegge (parmi beaucoup, beaucoup d'autres) a écrit une bonne histoire sur la façon dont les classes de manager inutiles, par le biais du modèle singleton, finissent par être. http://sites.google.com/site/steveyegge2/singleton-considered-stupid
la source
J'ai toujours pensé qu'un bon gestionnaire d'actifs devrait avoir plusieurs modes de fonctionnement. Ces modes seraient très probablement des modules source distincts adhérant à une interface commune. Les deux modes de fonctionnement de base seraient:
Vous auriez besoin d'un outil qui peut récupérer toutes les analyses de la base de données partagée et créer l'ensemble de données de production.
Pendant mes années en tant que développeur, je n'ai jamais rien vu de tel, même si je n'ai travaillé que pour une poignée d'entreprises, mon point de vue n'est donc pas vraiment représentatif.
Mise à jour
OK, quelques votes négatifs. Je développerai cette conception.
Tout d'abord, vous n'avez pas vraiment besoin de classes d'usine car si vous avez:
vous connaissez le type, alors faites simplement:
mais ensuite, ce que j'essayais de dire ci-dessus, c'est que vous n'utiliseriez pas de toute façon des noms de fichiers explicites, la texture à charger serait spécifiée par le modèle sur lequel la texture est utilisée, donc vous n'avez pas réellement besoin d'un nom lisible par l'homme, il peut s'agir d'une valeur entière de 32 bits, ce qui est beaucoup plus facile à gérer pour le processeur. Ainsi, dans le constructeur de TextureHandle, vous auriez:
AssetStream utilise le paramètre resource_id pour trouver l'emplacement des données. La façon dont cela a été fait dépendrait de l'environnement dans lequel vous exécutez:
En développement: le flux recherche l'ID dans une base de données (en utilisant SQL par exemple) pour obtenir un nom de fichier puis ouvre le fichier, le fichier peut être mis en cache localement, ou extrait d'un serveur si le fichier local n'existe pas ou est périmé.
Dans la version: le flux recherche l'ID dans une table clé / valeur pour obtenir un décalage / taille dans un grand fichier compressé (comme le fichier WAD de Doom).
la source
Ce que j'aime faire pour les actifs, c'est mettre en place un gestionnaire forfaitaire . Inspirés par le moteur Doom, les blocs sont des éléments de données qui contiennent des actifs, stockés dans un fichier forfaitaire qui déclare les noms des blocs, les longueurs, le type (bitmap, son, shader, etc.) et le type de contenu (fichier, un autre bloc, à l'intérieur le fichier forfaitaire lui-même). Au démarrage, ces grumeaux sont entrés dans un arbre binaire, mais pas encore chargés. Chaque carte (qui est également un bloc) a une liste de dépendances, qui sont simplement les noms des blocs dont la carte a besoin pour fonctionner. Ces morceaux, à moins qu'ils n'aient déjà été chargés, sont chargés au moment du chargement de la carte. De plus, les morceaux des cartes adjacentes de la carte sont chargés, mais pas en même temps, mais lorsque le moteur tourne au ralenti pour une raison quelconque. Cela peut rendre les cartes transparentes et il n'y a pas d'écran de chargement.
Ma méthode est parfaite pour les cartes du monde ouvert, mais un jeu basé sur le niveau ne bénéficiera pas de la fluidité de cette méthode. J'espère que cela t'aides!
la source