Idea: Using Dictionary<enum, animation> vs <string, animation> C#

Started by
4 comments, last by rpiller 12 years, 2 months ago
Hi guys

Working on a game engine in 2d C# and currently working on the animation and entity classes. An entity has a set of animations can play and I'm tossing up between using enums or using strings as the key, ie

Entity player = new Entity();
e.play("playerWalk")

vs

Entity player = new Entity();
e.play(playeranimations.walk);

the latter would ensure at compile time that the call to play always contains a valid animation, while the former is far simpler to implement.

Using the later, each different entity type would need its own enum, but that's not too bad as I can easily parse my sprite's xml metadata and add a bit of code generation as a pre compile step. I'm leaning towards the enum approach as it would eliminate one potential source of fauilts at run-time, but I feel like i'm abusing the concept of an enum, so other peoples opinions would be welcome.

Here's my code if it helps visualise things

Entity class:

public class Entity
{
private Dictionary<int, Animation> AnimationSet;
public Enum Animations;
public Entity(Enum animations)
{
AnimationSet = new Dictionary<int,Animation>();
Animations = animations;
}
public void AddAnimation(Enum id, Animation a )
{
if (id.GetType() == Animations.GetType())
{
int idint = Convert.ToInt32(id);
AnimationSet.Add(idint, a);
}
else
{
throw new ArgumentException(String.Format("Incorrect Enum used, this entity uses '{0}' but passed in ' {1}'", Animations.GetType(), id.GetType()));
}
}


Here's my unit tests - Shows the class in practice.
[Test]
public void EntityConstruct()
{
Entity myPC = new Entity(new PlayerAnimations());
myPC.AddAnimation(PlayerAnimations.die, new Animation("afd", null, 1, 1, 1, 1, 1, 1, 1));
}
[Test]
public void EntityConstructFail()
{
Entity myPC = new Entity(new PlayerAnimations());
Assert.Throws(typeof(ArgumentException), delegate() { myPC.AddAnimation(TankAnimations.die, new Animation("afd", null, 1, 1, 1, 1, 1, 1, 1)); });
}

enum PlayerAnimations { walk, run, die } // auto generated
enum TankAnimations { roll, shoot, die } // auto generated
Advertisement
An enum with code generation would add a step to your content pipeline, the code would have to be rebuilt each time a new animation type is added. You can merge the enum's speed with the string's user friendliness by making a hashed string class. Store the string as a character array and hash it into a 32 or 64 bit int during creation, which is then used for all comparisons.
Because it works as a string, you can add content without any additional recompilation or asset conditioning. You can get rid of all runtime hashing fairly trivially, giving you the best of performance and flexibility.
Have you tried to make some profiling on using one and then the other? My personal experience with c# is that string operations are so fast, even string comparing, that you can get away with it using plain strings, with no hashing needed. However, i recommend you to do a test first and check how much you can gain with using enums, but as turch said, you are adding up complexity too early. This is an optimization that should be done only when clear proof exists that the one with the strings is too slow.
edit: realised that C# doesn't have typedef or define (not the way I use it below anyway). The advice still applies, you just have to use a C# appropriate way of doing it like a wrapper class.


This is an optimization that should be done only when clear proof exists that the one with the strings is too slow.


I'd add that you should go ahead and set up a way to change which method you use. Do a typedef or define something like ASSETSTRING to string. When trying out hashed strings all you have to do is change the define to your hashstring class, and everything will automagically work. If you just stick regular strings in your code, it will be virtually impossible to find all the right strings to replace, and you will probably introduce a lot of bugs. Later, when you've settled on an implementation, you can find+replace ASSETSTRING to whatever if you want.
I'm leaning towards the version that uses the string. Unless you're going to be calling that Play() function a lot, the overall speed difference between using a string versus an int32 (or Enum) is going to be negligible. Plus, if you're concerned about errors creeping in, have the Play() function throw an exception or write to a log it it can't find the passed in string in the list of animations.
[size="2"]Currently working on an open world survival RPG - For info check out my Development blog:[size="2"] ByteWrangler
From his post he doesn't seem to be concerned about speed and I wouldn't think he need to either. You basically call once each time you change animations. No need to worry about speed. What he is worried about is being able to add an animation name that doesn't exist and avoiding those development issue errors.

Pesronally I'd go string and leave it to the developer to work out that the animation names are correct. Nice and simple. I think you are trying to solve a problem that isn't that big of a problem to begin with.

This topic is closed to new replies.

Advertisement