0

我正在编写一个 RTS 游戏,我想将用户操作封装成“命令”。命令将允许:

  • 通过网络将用户操作发送给其他玩家,因此每个人都知道其他人在做什么
  • 记录用户对文件的操作以启用重播功能
  • 在执行之前验证每个动作以防止(一种形式的)作弊
  • 分类动作,例如只导致 UI 变化的动作(移动相机)、改变游戏状态的动作(移动单位)、只有地图编辑器才能发出的动作(改变地形)等。

他们还必须增加最小的开销。因此,我想避免使用反射。到目前为止,我想出的最好的结果很糟糕,因为我不可避免地会得到一个巨大的 switch 语句。

enum CommandType {
    MoveCamera,
    ChangeTerrain
}

// Base class for all commands (public fields used for brevity)
abstract class Command {
    protected Command(CommandType type) {
        Type = type;
    }
    public CommandType Type;
}

class CommandMoveCamera : Command {
    public CommandMoveCamera() : base(CommandType.MoveCamera) {}
    public int DeltaX;
    public int DeltaY;
}

class CommandChangeTerrain : Command {
    public CommandChangeTerrain() : base(CommandType.ChangeTerrain) {}
    public int NewTerrainType;
    public int X;
    public int Y;
}

class Game {
    Queue<Command> m_commands;
    void Update() {
        // Example of adding a command
        m_commands.Enqueue(new CommandMoveCamera { DeltaX = -10, DeltaY = 0 });

        // Processing commands
        while (m_commands.Count > 0) {
            var c = m_commands.Dequeue();
            switch(c.Type) {
            case CommandType.MoveCamera:
                var command = (CommandMoveCamera)c;
                MoveCamera(c.DeltaX, c.DeltaY);
                break;
            case CommandType.ChangeTerrain:
                var command = (CommandChangeTerrain)c;
                ChangeTerrain(c.X, c.Y, c.NewTerrainType);
                break;
            }
        }
    }
}

语言是 C#。我的问题是:以满足要求的方式实现该系统并避免依赖于巨大的 switch 语句来分支每种不同类型的命令的方法是什么?

谢谢你。

4

2 回答 2

0

不久前我为游戏引擎做了一个非常相似的事情。我实际上经历了几个不同的版本,我想出的是这样的。

  • 所有命令都实现 Command 接口(这意味着可序列化)
  • 所有命令都必须在 CommandRegistry 中注册,因此 CommandRegistry 对每个命令都有一个唯一的 Id。

然后通过线路发送命令,您要求 CommandRegistry 为您序列化它。它将序列化命令并附加其 ID。接收端的 CommandRegistry 将读取 Id,创建适当类型的 Command,然后要求它从其余数据中反序列化自身。

我已经在 C++ 和 Go 中完成了这个基本设置,所以我认为它在 C# 中应该可以正常工作。

于 2012-04-08T00:12:01.057 回答
0

我有几个想法。首先,您可以公开On<Event>每种命令的方法。然后添加一个抽象方法Command,就像Execute参数一样Game。然后每个命令实现都可以调用适当的方法Game(包括与命令相关的任何其他逻辑)。您将不再需要枚举。

另一个想法有点相似,但使用了委托。为每个命令类型定义一个委托,并为每个命令实现公开一个使用此委托的事件。然后在您的Command摘要中,您可以拥有方法Execute,该方法在实施时会引发适当的事件。当您创建每个事件时,您只需将事件委托Game给将处理该命令的成员。

于 2012-04-08T00:28:59.153 回答