替换嵌套的切换语句

1 c# unity-game-engine

我正在尝试为修改静态游戏控制器内部变量的按钮创建一个多用途脚本.单击时,每个应修改它们由序列化枚举绑定的正确变量.我的想法是,我可以在任何按钮上敲击它们,只需通过更改按钮脚本实例上的几个标志来更改它们对数据的作用.

麻烦来自于可能的排列数量,我有两个"军队",每个都有四个"单位",每个"单位"有五个"属性".我最终得到了一堆看起来非常密集的代码,我确信它可以以某种方式解决,但我找不到任何解决方案.

(为了清楚起见activeArmy,unitToChange,unitNum,和attributeToChangeenums)

if (activeArmy == ArmyNum.army1)
{
    switch (attributeToChange)
    {
        case AttributeType.Accuracy:
            switch (unitToChange)
            {
                case UnitNum.unit1:
                    //if it's not too large
                    GameController.controller.army1.unit1.accuracy++;
                    //recalculate unit cost
                    GameController.controller.army1.unit1.RecalculateCost()
                    //then give the new number to the UI to display it
                    break;
Run Code Online (Sandbox Code Playgroud)

现在我希望能够做到这样的事情:

GameController.controller.[activeArmy].[unitToChange].[attributeToChange]++;
Run Code Online (Sandbox Code Playgroud)

那种路径甚至可能吗?有没有办法在枚举中替换像这样的变量的路径?

这是我通过改变我的架构来解决的问题吗?

Eri*_*ert 6

你内外有逻辑; 这就是创造你的问题的原因.以其他顺序执行,并将所有内容分解为小方法:

Army GetArmy(ArmyNum a)
{
  switch(a)
  {
    case ArmyNum.army1: return controller.army1;
    ...
  }
}

Unit GetUnit(Army a, UnitNum u)
{
  switch(u)
  {
    case UnitNum.unit1: return a.unit1;
    ...
  }
}

void ChangeAttribute(GameAttribute a, Army a, Unit u)
{
  switch (attributeToChange) {
    case GameAttribute.Accuracy:
      u.accuracy += 1;
      break;
      ...
Run Code Online (Sandbox Code Playgroud)

现在呼叫网站简单地说:

Army a = GetArmy(activeArmy);
Unit u = GetUnit(a, unitToChange);
ChangeAttribute(attributeToChange, a, u); 
Run Code Online (Sandbox Code Playgroud)

这里的教训是制作小方法,每个方法都做得非常好.然后用这些较小的方法组成更复杂的方法.

完成后,您就可以开始更改实施细节了.例如,我们可能会注意到这GetUnit是一种正确的方法Army,因此我们将其签名更改为

Unit GetUnit(UnitNum u) // Now a method of Army
{
  switch(u)
  {
    case UnitNum.unit1: return this.unit1; // this, not 'a'.
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

现在呼叫网站是

Army a = GetArmy(activeArmy);
Unit u = a.GetUnit(unitToChange);
ChangeAttribute(attributeToChange, a, u); 
Run Code Online (Sandbox Code Playgroud)

这显然更好.

现在假设你做了一个Dictionary<ArmyNum, Army>Armies.然后你重写:

Army GetArmy(ArmyNum a) => Armies[a];
Run Code Online (Sandbox Code Playgroud)

和GetUnits类似.一旦你在那里,你可以找到你使用的网站GetArmy,并GetUnit与更换Armies[a]Armies[a].Units[u]等.

你想要进入一个参数化的世界是一个好主意.通过做一些小改动逐渐到达那里,每一个都是明显正确的.

一种先进的解决方案将是使与其相关的行动代表:

actions = new Dictionary<GameAttribute, Action<Army, Unit>>() 
{
  { Attribute.Accuracy, (a, u) => { u.accuracy += 1; } }, 
  ...
};
Run Code Online (Sandbox Code Playgroud)

然后你可以写:

a = Armies[army];
u = a.Units[unit]
actions[attribute](a, u);
Run Code Online (Sandbox Code Playgroud)

但是在跑步之前走吧!随着程序逻辑变得越来越复杂,你会发现你再次制造了大量复杂的代码,然后你会尝试使用优秀的OO原则将它组织成类,这可能会使情况变得更糟.我写了一系列关于如何使用OO试图解决这些问题的文章; 如果您对此主题感兴趣,请参阅https://ericlippert.com/2015/04/27/wizards-and-warriors-part-one/

  • 这就是我在写作过程中的答案:)我也想知道枚举和开关是否真的是最好的解决方案,特别是对于陆军和单位级别.简单的集合和索引不是更容易吗? (2认同)