RTS游戏的命令系统

时间:2012-04-08 00:01:15

标签: c# architecture

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

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

此外,他们必须增加最小的开销。因此,我想避免使用反射。 到目前为止,我提出的最好的是糟糕的,因为我不可避免地得到了一个巨大的转换声明。

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语句来分支每种不同类型的命令?

谢谢。

2 个答案:

答案 0 :(得分:0)

我刚才为游戏引擎做了类似的事情。我实际上经历了一些不同的版本,而我提出的版本是这样的。

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

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

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

答案 1 :(得分:0)

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

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

相关问题