美文网首页
《游戏编程模式》Ch1-Ch2

《游戏编程模式》Ch1-Ch2

作者: 昼阴夜阳 | 来源:发表于2019-08-12 19:20 被阅读0次

    1 架构、性能和游戏

    1.1 什么是软件架构

    软件架构:代码的组织方式。

    好的架构:适度抽象,在轻松应对快速变化的同时不过于复杂冗余。

    核心思想:解耦,最小化解决单个问题需要的代码学习和知识储备。

    1.2 有什么代价

    添加更多代码并对抽象层进行开发、调试和维护。

    添加补丁的同时需要谨慎的组织代码维护架构。

    增加了解决问题时理解代码的难度。

    1.3 性能和速度

    灵活的模式通常依赖于运行成本较大的机制。例如虚函数派发、指针、消息、接口。

    折中方法:先保持灵活性,直到设计稳定下来再去除抽象提高性能。

    1.4 设计的灵活性

    为了验证想法的代码大部分需要抛弃。因此原型是一个完全正确的编程实践,只要保证以后重写。

    1.5 寻求平衡

    开发本身也需要权衡利弊。

    • 良好的架构
    • 优秀的性能
    • 快速的编码

    1.6 简单性

    一个思路是努力试着编写最干净、直接的函数来解决问题。

    用一小块逻辑解决一大片用例永远是最优雅的。其本质是寻找到了用例背后的模式关系。

    If I had more time, I would have written you a short letter. —— Blaise Pascal

    1.7 TIPS

    • 抑制住抽象和解耦的冲动,除非必要,否则别浪费时间
    • 大胆尝试,探索设计空间,但不要留下一个烂摊子继续往前
    • 底层优化能晚则晚
    • 最重要的是:开心就好!

    2.命令模式

    2.0 概述

    将一个request封装成一个对象,从而允许使用不同的请求、队列或日志将客户端参数化,同时支持请求操作的撤销与恢复。 —— GoF

    A command is a reified method call. 命令就是一个具象化(实例化)的方法调用。 —— Robert Nystrom

    2.1 配置输入

    按钮与游戏行为(方法)的映射,为了支持自定义配置,就需要将直接调用转换为可以swap out的变量分配。

    首先对将不同游戏行为的调用(回调)具象为命令。虽然函数指针就可以做到这一点,但并不完整,所以这里定义命令基类class Command。

    class Command{
    public:
        virtual ~Command() {};
        virtual void execute() = 0;
    }
    

    为不同游戏行为(方法)分别创建不同命令子类,并对执行操作虚函数进行重载绑定。

    class JumpCommand : public Command {
    public:
        virtual void execute() { jump(); }
    };
    // ...
    

    最后就可以通过间接调用层的命令指针处理输入。

    class InputHandler{
    public:
        void handleInput();
        // Methods to bind commands to buttons
    private:
        Command* buttonX_;
        // ...
    }
    void InputHandler::handleInput(){
        if (isPressed(BUTTON_X)) buttonX_->execute();
        // else if...
    }
    

    // 这种方式是将执行功能集成在了命令内部,应该是比较低级的命令,之前写过的完全抽象成数据的命令,需要装载数据到执行模块才能用的比较高级。不过提供了添加一个装载到执行器并执行的基类方法的想法。

    // 早知道不敲这么多憨憨代码了,诚招打字员

    2.2 关于角色的说明

    命令模式更普遍的应用场景是作为游戏AI引擎和角色之间的接口。通过命令模式,AI模块和角色行为实现了解耦。AI模块只需要简单的提供命令流以供角色(引擎)执行。同样,对于多人网络游戏,命令序列化、传送、再回放的过程是关键部分。

    2.3 撤销和重做

    如果一个命令对象可以do,也应该可以轻松的undo,尤其是在回合策略类游戏中。为此,输入处理程序需要对每次输入的动作创建一次性命令实例。

    class Command{
    public:
        virtual ~Command() {};
        virtual void execute() = 0;
        virtual void undo() = 0;
    };
    

    为了撤销状态,可以在 execute() 执行的时候先记录当前状态。通过在命令里增加记录状态的变量实现。

    为了支持多次撤销,我们需要维护一个命令列表和一个对当前命令的引用。在执行、撤销、重做或选择新命令后根据情况对命令列表和当前命令引用进行更新。

    2.4 类风格化还是函数风格化

    函数式编程在解决许多问题时拥有高效性,例如用 js 实现命令模式。

    function makeMoveUnitCommand(unit, nextStatus) {
        var beforeStatus;
        // return command object
        return {
            execute: function() {
                beforeStatus = unit.status();
                unit.moveTo(nextStatus);
            },
            undo: function() {
                unit.moveTo(beforeStatus);
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:《游戏编程模式》Ch1-Ch2

          本文链接:https://www.haomeiwen.com/subject/qrrpjctx.html