我目前正在努力为游戏添加声音效果,尽管我当前的代码运行良好,但我正在寻找一种简化它的方法。基本上,游戏中的每个对象都有一个字符串值,表示它的材料(即。“木头”、“金属”等),当两个物体相撞时,在组合的基础上播放声音效果。代码实质上如下所示:
if( (matA == "metal" && matB == "wood") || (matA == "wood" && matB == "metal") )
{
//play sound for metal-wood collision
}但我想知道是否有办法将if -语句简化为这样的东西:
if( one of the materials is wood && one of the materials is metal )
{
//play sound for metal-wood collision
}发布于 2016-04-17 09:29:33
你应该用一个enum来代替字符串,你可以用一个Dictionary来保存相应的声音组合。您可以跳过多个if语句,并使用Dictionary自动为每个材料选择相应的对象。例如:
[Flags]
enum Material
{
Wood=1,
Iron=2,
Glass=4
//...
}
Dictionary<Material,SoundObject> sounds = new Dictionary<Material,SoundObject>();
sounds.add(Material.Wood,woodSound);
sounds.add(Material.Iron,ironSound);
sounds.add(Material.Wood | Material.Iron,woodAndIronSound);
// And play corresponding sound directly without any if statement.
sounds[object.Material].Play();
sounds[matA | matB].Play(); 业绩优势:
您还将通过使用这种方法来提高性能。因为对Enum值或散列代码的绝对整数比较比字符串比较更容易,速度更快。关于字典和多个if-else语句,if/else if语句序列是线性执行的;因此,它的性能很大程度上取决于if语句的数量和对象的相等比较器;而Dictionary是基于哈希表的。它使用一个优化的索引集合来存储值,有效地保持了恒定的访问时间。这意味着无论字典中有多少键,您都将在固定的时间内访问值,而且在大多数情况下,它比多个if语句更快。
业绩比较:
在本例中,我们将比较两种方法的性能:
//If you want to try, just copy the code and see the result.
static Dictionary<char, short> myHashTable = Enumerable.Range((short)'A', (short)'z').ToDictionary((ch) => (char)ch, (sh) => (short)sh);
static void Main(string[] args)
{
System.Diagnostics.Stopwatch SW = new System.Diagnostics.Stopwatch();
short temp = 0;
SW.Start();
for(int i=0;i<10000000;i++)
temp = getValue('z');
SW.Stop();
Console.WriteLine(SW.ElapsedMilliseconds );
SW.Reset();
SW.Start();
for(int i =0;i<10000000;i++)
temp = myHashTable['a'];
SW.Stop();
Console.WriteLine(SW.ElapsedMilliseconds);
}
static short getValue(char input)
{
if (input == 'a')
return (short)'a';
else if (input == 'b')
return (short)'b';
else if (input == 'c')
return (short)'c';
else if (input == 'd')
return (short)'d';
else if (input == 'e')
return (short)'e';
else if (input == 'f')
return (short)'f';
else if (input == 'g')
return (short)'g';
else if (input == 'h')
return (short)'h';
else if (input == 'i')
return (short)'i';
else if (input == 'j')
return (short)'j';
else if (input == 'k')
return (short)'k';
else if (input == 'l')
return (short)'l';
else if (input == 'm')
return (short)'m';
else if (input == 'n')
return (short)'n';
else if (input == 'o')
return (short)'o';
else if (input == 'p')
return (short)'p';
else if (input == 'q')
return (short)'q';
else if (input == 'r')
return (short)'r';
else if (input == 's')
return (short)'s';
else if (input == 't')
return (short)'t';
else if (input == 'u')
return (short)'u';
else if (input == 'v')
return (short)'v';
else if (input == 'w')
return (short)'w';
else if (input == 'x')
return (short)'x';
else if (input == 'y')
return (short)'y';
else if (input == 'z')
return (short)'z';
return 0;
} 结果:
包含26个条目的if语句,包含122个条目的字典。
593 254
579 256
572 252
570 246
587 248
574 291
576 246
685 265
599 282
723 338
这表明字典比if/else if语句快2倍多。
发布于 2016-04-17 09:56:37
当您发现自己是重复代码时,通常的方法是提取一个方法:
if (IsWoodAndMetal(matA, matB) || IsWoodAndMetal(matB, matA))
{
// play sound for metal-wood collision
}其中IsWoodAndMetal被定义为:
public static bool IsWoodAndMetal(string matA, string matB)
{
return matA == "wood" && matB == "metal";
}这将与原始代码一样快,不像所有分配内存的linq/list和string级联解决方案那样快,这是用于频繁的游戏循环的坏消息,因为它会导致更频繁和/或更长的垃圾收集。
如果||仍然困扰您,我们可以更进一步,提取:
public static bool EitherParameterOrder<T>(Func<T, T, bool> func, T a, T b)
{
return func(a, b) || func(b, a);
}现在的案文如下:
if (EitherParameterOrder(IsWoodAndMetal, matA, matB))
{
// play sound for metal-wood collision
}与其他解决方案相比,我仍然希望它的性能(除了字典解决方案,当您有几个条目时)。
发布于 2016-04-17 10:47:03
它可能不是最现代的解决方案,但使用素数作为参考你的材料可以提高你的性能。我知道并理解“在必要之前进行优化”是许多程序员不建议的,但是在这种情况下,我认为它并没有增加代码的复杂性,而是提高了这个(相当微不足道的)任务的性能。
public static class Materials
{
public static uint Wood = 2,
public static uint Metal = 3,
public static uint Dirt = 5,
// etc...
}
if(matA*matB == Materials.Wood*Materials.Metal)
{
//play sound for metal-wood collision
}
//or with enums but annoying casts are necessary...
enum Materials:uint
{
Wood = 2,
Metal = 3,
Dirt = 5,
// etc...
}
if((uint)matA*(uint)matB == (uint)Materials.Wood*(uint)Materials.Metal)
{
//play sound for metal-wood collision
}这种方法不依赖于物质的顺序(交换乘法),不需要对字符串进行任何长的比较,也不需要比整数更复杂的结构。
假设您希望保持所有的引用数4字节整数和最大的4字节整数的平方根约为65535,那么您将有大约6550个可能的素数低于65535,这样没有任何积会导致整数溢出。到目前为止,这对于任何普通的游戏来说都是足够的了。
https://stackoverflow.com/questions/36672631
复制相似问题