在 C# 中什么更有效 - 硬编码 41 修饰符,或通过数学解决它?

What is more efficient in C# - hardcoding 41 modifiers, or solving that through maths?

我是一个真正的编码新手,想要将 Dungeons & Dragons OGL 机制移植到我的 Unity3D 项目中。
现在,我想在 C# 中为基本字符属性添加修饰符。 这些基于数字 10/11,即 20 面骰子的 "middle" 结果。
基本角色属性例如力量、智力、魅力等
您的统计数据高于 10 的越高,您获得的统计修正值就越高。 10 越低,您的修正值越低(负数)。

So, for 10 and 11 you have +0 (no modifer). Now, for:
12, 13 -> you get +1
14, 15 = +2
16, 17 = +3
18, 19 = +4
20, 21 = +5
22, 22 = +6 and so on (Character Attributes can go up to 40 and as low as 0 I guees)

For attributes below average, so below 10:
8, 9 = -1
6, 7 = -2
4, 5 = -3
2, 3 = -4
0, 1 = -5

现在,我可以在 ifs 上或像一个人一样在开关上对其进行硬编码。这是他的代码的一部分:

private string DetermineModNum(string value)
{
    int score; //convert to int.
    TryParse(value, NumberStyles.Integer, null, out score);
    if (score > 10)
    {
        if (score % 2 == 0) //can be divided by 2
        {
            switch (score)
            {
                case 12:
                    return "1";
                case 14:
                    return "2";
                case 16:
                    return "3";
                case 18:
                    return "4";
                case 20:
                    return "5";
                case 22:
                    return "6";
                case 24:
                    return "7";
                case 26:
                    return "8";
                case 28:
                    return "9";
                case 30:
                    return "10";

            }
        }
        else
        {
            switch (score)
            {
                case 11:
                    return "0";
                case 13:
                    return "1";
                case 15:
                    return "2";
                case 17:
                    return "3";
                case 19:
                    return "4";
            }
        }
    }
    else
    {
        if (score % 2 == 0) //can be divided by 2
        {
            switch (score)
            {
                case 10:
                    return "0";
                case 8:
                    return "-1";
            }
        }
        else
        {
            switch (score)
            {
                case 9:
                    return "-1";
                case 7:
                    return "-2";
            }
        }
    }
    return null;
}

这是不完整的,只是他的角色生成器的一部分。 但另一种方法可能是将属性除以 4。因此,我们可以将统计数据除以 4,而不是全部写下来。

例如:
强度:7(修饰符为 7 / 4 = 1,75,因此我们应将其四舍五入为 2 并将其更改为 -2)
智力:18(修改器将是 18 / 4 = 4,5,所以这只是 int 4)

在 Unity3D 游戏中哪种方法会更快?

此外,如果第二种解决方案更好,你能帮我展示一下如何在 C# 中最好地构建它吗?我只是在学习,真的可以在这里使用一些很好的例子。我需要低于 10 的修饰符为 -,高于 10 为 +,属性范围至少在 0 - 40 左右(将很快检查 SRD 中的最大属性)。

我需要很多基于不同事物的修饰符。有些会像上面一样简单和规则,有些有其他修饰符模式,比如每 2 级,但其他一些东西,比如 class 能力,会有自定义,但有时仍然是重复的模式。

所有机制都必须尽可能快,因为在战斗中所有内容都是实时计算的,我希望尽可能获得最佳性能。

Case 语句很长,而数学计算可能很难理解(尽管在您的情况下它们看起来很简单)。

一种非常灵活的方法是构建一个查找表 table,用答案填充它,然后通过简单的向上循环得到结果到数组中:

private static int[] ModNumByScore = new [] {
    0, 0, 0, 0, 0, 0, 0,-2,-1,-1,
    0, 0, 1, 1, 2, 2, 3, 3, 4, 4,
    5, 0, 6, 0, 7, 0, 8, 0, 9, 0,
   10
};
private static string DetermineModNum(string value) {
    int score; //convert to int.
    if (!TryParse(value, NumberStyles.Integer, null, out score)) {
        // Throw an exception: the string is invalid
    }
    if (score > 30 || score < 7) {
        // Throw an exception: the score is invalid
    }
    return ModNumByScore[score].ToString();
}

现在您可以按照您希望的方式填充您的 table,您的代码的读者将能够通过查看 table 中的数字来判断每个分数返回的内容。

你可以通过简单的计算摆脱巨大的switch语句:

float value = Mathf.Floor(score/2) - 5;
return value.ToString();

虽然在这个阶段担心这样的优化是愚蠢的。在您有具体的东西或发现任何明显的性能问题后分析您的游戏。

编辑:如评论中所述。 Mathf.Floor 是不必要的。整数值将被自动截断(向下舍入)。

整数运算在现代 CPU 上非常快。另一方面,条件跳转可以清空执行管道并减慢执行速度。所以做数学运算可能比冗长的 switch 语句更快。与充满案例陈述的 2 屏相比,数学也将更简洁,更不容易出错。

但我想您几乎不会注意到不同方法之间的任何区别。别忘了:premature optimization is the root of all evil.

所以

int modNum = (score / 2) - 5;

显然是首选。请注意,这里执行了整数除法,它会自动截断结果。例如。 13 / 2 ==> 6.

short's (16-bit), int's (32-bit) and longs (64-bit) 都存储整数,即整数有没有小数部分。

性能差异可能可以忽略不计,数学很简单:

score = (score - score % 2) / 2 - 5; 

您要做的第一件事是将成对的连续数字处理为相同的数字。这可以通过从原始数字中减去模数 2 轻松实现。
然后将结果除以 2 再次得到连续的数字。 之后你所要做的就是从中减去 5 得到你开始的方程式:

...
8, 9 => -1
10, 11 => 0
12, 13 => 1
...