Identifier les actifs dans un moteur de jeu?

12

Je veux identifier mes actifs chargés, mais je ne sais pas lequel dois-je choisir. Il y a 2 options:

  • Nom (chaîne)

    • C'est le plus simple et aussi le plus rapide avec unordered_map (O (1)), mais beaucoup plus lent qu'en utilisant des entiers.
    • Facilement compréhensible dans le code.
  • Entiers

    • Le plus rapide.
    • Ne sont pas compréhensibles dans le code.

Je sais que les cordes ne sont pas aussi sûres ou rapides, mais est-ce si mauvais, ou cela ne compte-t-il que comme mauvais dans un titre AAA? Je pourrais faire des énumérations, pour utiliser des entiers, mais si je charge la scène, les actifs, etc. à partir d'un fichier au moment de l'exécution, je ne peux pas utiliser les énumérations. Existe-t-il un moyen de rendre ces entiers lisibles s'ils sont générés au moment de l'exécution?

Je sais que ce problème a quelques discussions sur Internet, mais je n'ai pas pu savoir à quel point cela est important.

Tudvari
la source
10
Pourquoi pas une implémentation des deux? La version chaîne se connecte à un dictionnaire <chaîne, int> qui à son tour appelle un dictionnaire <int, actif>. Vous pouvez contourner la couche basée sur des chaînes dans le code, mais utilisez la couche basée sur des chaînes pour l'interaction avec l'utilisateur.
Krythic
2
J'appuierais le point de @ Krythic. Si votre code aime les entiers pour la vitesse, laissez-le utiliser des entiers. Si vos utilisateurs aiment les chaînes pour la lisibilité, laissez vos utilisateurs utiliser des chaînes. Les deux peuvent coexister très heureusement (et vous pouvez compiler de manière sélective la version de chaîne dans les builds de développement uniquement, si vous voulez ignorer la surcharge entièrement dans la version)
DMGregory
Même problème dans un contexte légèrement différent: Différentes méthodes d'implémentation des éléments - quelles sont les différences?
Philipp

Réponses:

19

Vous pouvez prendre en charge les deux.

Alors qu'il est souvent plus efficace lors de l' exécution d'actifs de référence par un entier ou d' une même clé comparer à rapide, il est souvent plus efficace au moment de la conception pour les référencer par nom, parce que les humains sont beaucoup mieux à travailler avec des noms tels enemy_bullet_casing_soundque 72910613.

Utilisez une clé entière pour rechercher les ressources directement, et utilisez cet entier dans le code autant que possible (où vous pouvez mettre la valeur réelle de l'entier dans une variable et ainsi travailler plus facilement avec). Fournissez un mappage du nom à cette clé entière (plutôt que directement à la ressource) et utilisez ce mappage chaque fois que vous rencontrez des références nommées aux actifs pour résoudre la clé entière réelle et rechercher l'actif.

L'utilisation de la recherche basée sur le nom rendra vos fichiers de données beaucoup plus faciles à utiliser, et le mappage du nom à une clé plus rapide préservera tous les avantages importants d'une clé de type entier plus rapide partout où cela est nécessaire.


la source
Mon cas: je veux changer le matériau d'un objet, alors j'envoie une demande avec le nom du nouveau matériau. (chaîne) Ensuite, dans le système graphique, il y a une recherche dans une carte <chaîne, pointeur> non ordonnée, et le pointeur du matériau de l'objet sera remplacé par le nouveau pointeur. Donc dans mon cas, je n'ai pas besoin de le convertir en entier? (parce que je le convertis en pointeur et dans les algorhytmes fréquents j'utilise des pointeurs, j'utilise uniquement des chaînes pour les choses occasionnelles.)
Tudvari
Ou dois-je utiliser des ID entiers au lieu de pointeurs partout où cela est possible? (Je n'ai donc pas besoin d'inclure le fichier d'en-tête, par exemple du matériau.) Par exemple, le composant de rendu stocke désormais le pointeur du matériau utilisé, qui peut être utilisé directement par le moteur graphique, mais je dois inclure Material.h . Mais lorsque je stocke uniquement des entiers dans le composant de rendu, je n'ai pas à inclure Material.h, mais je dois effectuer une recherche basée sur des nombres entiers dans le tableau de pointeurs. Je pense que ce dernier est meilleur. C'est ça? Dois-je refactoriser cela?
Tudvari
1

Dans mon projet, j'utilise des chaînes hachées, qui sont transformées, au moment de la compilation, en nombres uniques (je le souhaite!). Donc, quand j'ai besoin d'une ressource, par exemple une texture que j'appelle simplement

MngTexture->get(hash("my_texture"))

Et comme je crée un cadre de système d'entité simple et que je dois charger des données de composants à partir de fichiers, j'ai créé un langage simple comme json pour stocker les données, mais il est compilable (transformant les mots et les caractères des chiffres en nombre et des chaînes en valeurs hachées) . Ainsi, par exemple, si je veux lier la texture avec le hachage ID ("my_texture") à "ball.PNG" dans mon fichier de données, je devrai

|my_texture| = "ball.PNG"

Où || est un opérateur qui dit au compilateur de hacher le mot à l'intérieur.

Donc, fondamentalement, j'utilise des chaînes qui sont mappées en entiers au moment de la compilation (donc elles n'ont pas de surcharge), à ​​la fois dans le code réel et dans les fichiers qui sont les flux pour charger les composants. Pour calculer le hachage un temps de compilation simplement google, c'est une simple fonction de 5-10 lignes de code.

Bien sûr, vous pouvez charger la chaîne à partir de vos fichiers et la hacher au moment de l'exécution, dans ce cas, vous n'avez pas à écrire le dictionnaire par vous-même car l'algorithme le fera pour vous (création d'entiers à partir de chaînes) et je pense que le hasing est au moins aussi rapide que la recherche dans une carte, en raison de la localisation de la mémoire (vous parcourez simplement une chaîne de quelques octets).

J'espère que cela peut vous aider.

Liuka
la source
0

L'identification d'un objet par des chaînes n'est pas optimale, les entiers sont beaucoup plus efficaces. Pour plus de commodité, vous pouvez gérer une table de chaînes (ou un dictionnaire) de chaînes en entiers pour vous aider au moment de la conception et pendant le débogage.

Je recommanderais cependant que dans votre code de jeu de base, vous ne fassiez référence aux objets que par leur identifiant entier (ou une énumération pour la lisibilité). Cela simplifie la séparation de la table de chaînes en tant qu'actif distinct. Si votre code de jeu de base ne repose pas sur cette table de chaînes, vous pouvez le supprimer du jeu publié, ce qui peut potentiellement économiser une quantité importante de mémoire - une considération importante si vous travaillez sur un jeu mobile et souhaitez conserver des tailles de téléchargement aussi petites que possible.

steeveeet
la source