12
\$\begingroup\$

I want to identify my loaded assets, but I don't know which one should I choose. There are 2 options:

  • Name (string)

    • This is the easiest and also fast with unordered_map ( O(1) ), but way slower then using integers.
    • Easily understandable in the code.
  • Integers

    • Fastest.
    • Aren't understandable in code.

I know that strings are not so safe or fast, but is it that bad, or does it only count as bad in a AAA title? I could make enums, to use integers, but if I load the scene, assets, etc from a file at runtime, I can't use enums. Is there a way to make these integers readable if they are generated at runtime?

I know that this issue has a few threads all around the internet, but I couldn't find out how important in which cases is this.

\$\endgroup\$
  • 10
    \$\begingroup\$ Why not an implementation of both? The string version connects to a Dictionary<string,int> which in turn calls a Dictionary<int,Asset>. You could circumvent the string based layer in code, but use the string based layer for user interaction. \$\endgroup\$ – Krythic Dec 11 '16 at 17:19
  • 2
    \$\begingroup\$ I'd second @Krythic's point. If your code likes integers for speed, let your code use integers. If your users like strings for legibility, let your users use strings. The two can coexist quite happily (and you can selectively compile the string version into development builds only, if you want to skip the overhead entirely in release) \$\endgroup\$ – DMGregory Dec 11 '16 at 17:30
  • \$\begingroup\$ Same problem in a slightly different context: Different methods of item implementation - what are the differences? \$\endgroup\$ – Philipp Dec 12 '16 at 9:01
20
\$\begingroup\$

You can support both.

While it is often more efficient at runtime to reference assets by an integer or some similar fast-to-compare key, it's often more efficient at design time to reference them by name, because humans are a lot better at working with names like enemy_bullet_casing_sound than 72910613.

Use an integer key to look up the resources directly, and use this integer in code wherever possible (where you can put the actual value of the integer in a variable and thus work with it easier). Provide a mapping from name to that integer key (rather than to the resource directly), and use that mapping whenever you encounter named references to assets to resolve the actual integer key and find the asset.

Using the name-based lookup will make your data files much easier to work with, and mapping the name to a faster key will preserve all the important benefits of a faster, integer-type key anywhere its needed.

\$\endgroup\$
  • \$\begingroup\$ My case: I want to change an Object's material, so I send a request with the new material's name. (string) Then in the graphics system there is a search in a <string, pointer> unorderered map, and the object's material's pointer will be replaced by the new pointer. So in my case, I don't have to convert it to an integer? (because I convert it to pointer and in the frequent algorhytms I use pointers, I only use strings for the occasional things.) \$\endgroup\$ – Tudvari Dec 11 '16 at 19:34
  • \$\begingroup\$ Or should I use integer ID-s instead of pointers everywhere it's possible? (So I don't have to include the header file of e.g. the material.) For example the renderer component now stores the pointer of the used material, which can be used directly by the graphics engine, but I have to include Material.h. But when I store only integers at the renderer component, I don't have to include Material.h, but I have to make an integer based search in the array of pointers. I think the latter one is better. Is it? Should I refactor this? \$\endgroup\$ – Tudvari Dec 11 '16 at 21:45
1
\$\begingroup\$

In my project I use hashed strings, which are transformed, at compile time in unique (I wish!) numbers. So, when I need a resource, for example a texture I simply call

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

And since I'm creating a simple entity system framework and I need to load components data from files I created a simple language like json to store data, but is compilable (transforming words and chars from digits to number and from strings to hashed values). So, for example, if I want to link the texture with ID hash("my_texture") to "ball.PNG" in my data file I'll have

|my_texture| = "ball.PNG"

Where || is an operator which tells the compiler to hash the word inside.

So basically I use strings which are mapped to ints at compile time (so they haven't any overhead), both in the actual code and in the files which are the streams for loading components. For computing the hash a compile time simply google it, it a simple function of 5-10 lines of code.

Of course you can load the string from you're files and hashes it at run time, in this case you don't have to write the dictionary on your own because the algorithm will do it for you (creating integers from strings) and I think hasing is at least as fast as searching in a map, because of memory locality (you are just looping through a string which is few bytes long).

Hope this can help.

\$\endgroup\$
0
\$\begingroup\$

Identifying object by strings is not optimal, ints are much more efficient. For convenience you can maintain a string table (or dictionary) of strings to ints to help at design time and during debugging.

I would, however, advocate that within your core game code you only refer to objects by their integer ID (or an enum for readability). Doing this makes it simpler to break out the string table as a separate asset. If your core game code doesn't rely on this string table then you can drop it from the released game potentially saving a significant amount of memory - an important consideration if you are working on a mobile game and want to keep download sizes as small as possible.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.