我正在尝试为用于修改静态游戏控制器内部变量的按钮创建多用途脚本。单击时,每个都应修改序列化枚举绑定到的正确变量。我的想法是,我可以将它们拍打在任何按钮上,只需通过更改按钮脚本实例上的一些标志,即可将它们更改为什么数据。

麻烦来自可能的排列数量,我有两个“手臂”,每个都有四个“单元”,每个单元都有五个“属性”。我最终看到的是一堆看上去很密集的代码,我敢肯定可以以某种方式解决它,但我找不到任何解决方案。

(为清楚起见,activeArmyunitToChangeunitNumattributeToChange均为enums

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;


现在,我希望能够执行以下操作:

GameController.controller.[activeArmy].[unitToChange].[attributeToChange]++;


这样的路径有可能吗?有没有办法用枚举代替类似这样的变量的路径?

我可以通过更改体系结构来解决此问题吗?

最佳答案

您拥有由内而外的逻辑;这就是造成您的问题的原因。以另一种顺序执行,然后将所有内容分解为一些小方法:

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;
      ...


现在,呼叫站点就是:

Army a = GetArmy(activeArmy);
Unit u = GetUnit(a, unitToChange);
ChangeAttribute(attributeToChange, a, u);


这里的课程是制作小型方法,每种方法都做得非常好。然后从那些较小的方法中组合出更复杂的方法。

完成此操作后,即可开始更改实施细节。例如,我们可能会注意到GetUnitArmy的正确方法,因此我们将其签名更改为

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


现在,呼叫站点是

Army a = GetArmy(activeArmy);
Unit u = a.GetUnit(unitToChange);
ChangeAttribute(attributeToChange, a, u);


显然更好。

现在假设您创建了一个名为Dictionary<ArmyNum, Army>Armies。然后,您重写:

Army GetArmy(ArmyNum a) => Armies[a];


对于GetUnits同样如此。到达那里后,您可以找到使用GetArmyGetUnit的站点,并将其替换为Armies[a]Armies[a].Units[u]等。

您迈向一个将所有参数都参数化的世界的想法是一个好主意。进行一些小改动,逐步达到目标,每一项都是正确的。

一个高级的解决方案是使与代表相关联的动作:

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


然后您可以写:

a = Armies[army];
u = a.Units[unit]
actions[attribute](a, u);


但是在跑步前先走!随着程序逻辑变得越来越复杂,您会发现您再次使复杂的代码变得一团糟,然后您将尝试使用良好的OO原理将其组织到类中,这可能会使情况变得更糟。我写了一系列有关如何使用OO解决此类问题的文章。如果您对此主题感兴趣,请参见https://ericlippert.com/2015/04/27/wizards-and-warriors-part-one/

09-28 06:21