精华内容
参与话题
问答
  • 游戏设计模式

    2016-12-13 20:57:39
    本书中你将会学习到如何写一个健壮的游戏主体,如何使用组件...同时你将深入的离家怎么使用脚本引擎来编辑一系列的功能,如何使用四叉树和其它的空间规划算法来优化你的引擎,以及如果将传统的设计模式应用到游戏设计
  • 游戏设计模式new

    2016-09-27 20:53:23
    游戏设计模式
  • 游戏设计模式-重访设计模式 读《游戏设计模式》第一部分的总结-代码没运行只是提示模式的构建方法 命令模式 特点:Character根据情况获取相应Command,Command命令Character执行方法。 场景:Character的方法和情况...

    游戏设计模式-重访设计模式

    读《游戏设计模式》第一部分的总结-代码没运行只是提示模式的构建方法

    命令模式

    特点:Character根据情况获取相应Command,Command命令Character执行方法。
    场景:Character的方法情况判断需要解耦。多种情况会在多种Character的方法中进行判断
    注意:真正的运行方法都是在Character下的,Command可以简化为委托

    public interface Command{
        public void execute(Character go);//这里使用游戏对象基类(能检测输入的基类)更好
    }
    public class JumpCommand implements Command{
        public void execute(Character go){
            go.jump();
        }
    }
    public class RunCommand implements Command{
        public void execute(Character go){
            go.run();
        }
    }
    public class InputCommands{
        RunCommand run=new RunCommand();
        JumpCommand jump=new JumpCommand();
        public Command getInput(){
            if(Input.GetKeyDown("W"))return run;
            else if(Input.GetKeyDown("Space") return jump;
            else return null;
        }
    }
    public class Character{
        void Update(){
            Command command=InputCommands.getInput();
            if(command!=null)command.excute(this);
        }
        void run(){}
        void jump(){}
    }
    

    观察者模式

    特点:被观察者注册观察者,需要通知时向所有观察者通知信息
    场景:两种不同功能的模块(之间只有事件通知关系)需要也应该解耦成观察者和被观察者,不混杂在一起
    注意:

    • 两个模块都有各自的作用,和命令模式相比,命令可以简化成委托,为Character服务;但观察者只是和被观察者有事件上的耦合
    • 如果被观察者不销毁而观察者已经不再使用,需要手动去销毁观察者(因为被观察者始终持有引用)
    public class Observer{
         private beNotified(){
         }
    }
    public class BeObserved{
        private ArrayList<Observer> obs=new ArrayList<Observer>();
        private notify(){
            for(int i=0;i<obs.length;i++){
                obs.get(i).beNotified();
            }
        }
    }
    

    原型模式

    特点:通过现有的对象克隆出相同的对象,克隆结束后两者之间是相互独立的
    场景:当类的实例化比较复杂且比较相似时使用
    注意:和享元模式相比,各个个体之间是没有联系的,数据也是相互独立的

    public abstract class Shape implements Cloneable{
        @Override
        public Object clone() {
          Object clone = null;
          try {
             clone = super.clone();
          } catch (CloneNotSupportedException e) {
             e.printStackTrace();
          }
          return clone;
       }
    }
    public class Circle extends Shape{}
    public class Rectangle extends Shape{}
    

    享元模式

    特点:大量对象持有一个共同的引用,所以这个引用只被实例化一次
    场景:需要创建大量重复的对象,同时这些对象的部分数据是不变的或是分成几类的
    注意:共同的引用其状态不应该经常被改变

    //字段不变
    public class TreeModel{//每个树的材质、纹理、叶子等都相同
        Mesh mesh;
        Texture bark;
        Texture leaves;
    }
    public class Tree
    {
      TreeModel model_;
      //以下的字段每个对象都不同
      Vector position_;
      double height_;
      double thickness_;
      Color barkTint_;
      Color leafTint_;
    };
    
    //字段枚举
    public class Terrain{
      int getMovementCost() const { return movementCost_; }
      bool isWater() const { return isWater_; }
      const Texture getTexture() const { return texture_; }
      
      int movementCost_;
      bool isWater_;
      Texture texture_;
    }
    public class World{
        Terrain grassTerrain=new Terrain(XXXXX);
        Terrain blockTerrain=new Terrain(XXXXX);
        ....
        Terrain[] terrains=new Terrain[10[10];//之后让terrains指向不同的XXXTerrain
        
    }
    

    状态模式

    特点:通过管理对象的状态来定义对象的行为,通常需要画状态机
    场景:对象的行为基于一些内在状态,状态可以被严格地分割为相对较少的不相干项目。而对象需要响应各种输入(或其他条件判断)
    注意:当状态管理过于复杂(制作更强大的AI时)使用行为树和规划系统

    //简单的情况下可以使用枚举来管理对象的状态
    enum State
    {
      STATE_STANDING,
      STATE_JUMPING,
      STATE_DUCKING,
      STATE_DIVING
    }
    //复杂的情况使用状态机
    interface BasicState{
        public BasicState handleInput(Heroine heroine, Input input);
        public void update(Heroine heroine);
        //入口方法,当进入该状态时需要调用,相对的也可以定义出口方法。
        public void enter(Heroine heroine);
    }
    //如果你的State都不需要有其他的变量(比如用来计时等)则简化为委托(但一般都有其他变量)
    class StandState implements BasicState{
        public BasicState handleInput(Heroine heroine, Input input) {
            if (input == PRESS_A){
                return new JumpState();
            }
        }
        public void update(Heroine heroine){
        //dosomething
        }
        public void enter(Heroine heroine){
            heroine.setGraphics(IMAGE_STAND);
        }
    }
    class JumpState implements BasicState{
        public BasicState handleInput(Heroine heroine, Input input) {
            if (input == PRESS_DOWN){
                return new OtherState();
            }
        }
        public void update(Heroine heroine){
        //dosomething
        }
        public void enter(Heroine heroine){
            heroine.setGraphics(IMAGE_JUMP);
        }
    }
    class OtherState implements BasicState{//...}
    class Heroine{
    //如果状态使用者是一个单例(不是单例模式)可以使用静态参数来使用状态
        BasicState state=new StandState();
        void handleInput(Input input){
            BasicState newState = state.handleInput(this, input);
            if (newState != NULL){
                Destroy(state);//清理工作
                state = newState;
                state.enter(this)
            }
        }
        void update(){
            state.update(this);
        }
    }
    

    并发状态

    当状态之间具有叠加关系时,可以在Heroine再定义一个state来指向叠加状态。但要注意叠加的越多,状态之间if判断越复杂。比如持枪状态和未持枪状态下的各种跳跃、行走

    分层状态

    当状态之间具有相似关系时,可以在使用继承来模拟状态的分层。子状态可以调用父状态的handleInput和update,不同子状态又有各自的处理,减少代码

    下推自动机

    当Heroine需要记住上一状态等操作时,可以维护一个容器(比如栈)来存储状态

    单例模式

    特点:类有且只有一个实例化对象,是可以被全局访问的,通常是惰性初始化
    场景:创建多个对象会出错的类、文件读写类、需要全局访问的类
    注意:尽可能的少使用单例模式
    缺点:

    • 全局变量将会使代码变得不可维护
    • 过渡滥用单例模式,单例模式解决两个问题(单例和全局),但实际上只需要解决一个问题
    • 对并行不友好
    • 惰性初始化在游戏开发中是不可控的因素
      解决:
    • 可以使用静态类解决惰性初始化
    • 观察是否真的需要单例模式,XXXManager往往可以在XXX类执行,而不需要通过一个特定、单独的管理器管理
    • 如果是为了实现单例,可以在多次创建时抛出异常等方法控制。让该类只有一个非全局的示例。被正确销毁后允许创建下一个实例
    • 如果是为了获取访问,可以考虑在方法里传参、在基类里定义保护对象、加入到已有的全局变量里、从服务器定位中获得
    展开全文
  • [Unity]游戏设计模式:命令模式 之前做过两款游戏的开发,遇到了许许多多的问题,从中体会到有个好的结构对游戏开发至关重要。在研究如何解决问题的时候,幸运的找到《游戏编程模式》这一救命神器!在此分享一下,...

    [Unity]游戏设计模式:命令模式

    之前做过两款游戏的开发,遇到了许许多多的问题,从中体会到有个好的结构对游戏开发至关重要。在研究如何解决问题的时候,幸运的找到《游戏编程模式》这一救命神器!在此分享一下,也为了复习一下书中所学。
    以下内容是我结合书中所学总结而来,我不太喜欢专业且抽象的描述,如有错误,还请指正!

    1.动机

    命令模式实现控制的直接解耦,把来自输入,AI的指令或者其他一些控制封装成数据对象,作为中间层,分离输入到行为的直接操作。在我的第一个项目中,Input直接写在了英雄控制器下,而后就调用到行为函数,简直愚蠢至极!把它们分开!通俗一点,命令模式大概是这样:就像你去点美团外卖,你只用发布一个买外卖的订单命令,里面有你的订单信息,然后提交订单,系统会帮你指派,你不用管谁去帮你炒菜!而你的订单就是一个命令。

    2.举例

    我用一个病菌的行为来说吧,首先定义了一个病菌对象。

    public class Germ
    {
       private int curCount;
       private int divideMuti;
       private int infectTargetID;
    
       public Germ(byte divideMuti, int infectTargetID)
       {
            curCount = 1;
            this.divideMuti = divideMuti;
            this.infectTargetID = infectTargetID;
       } 
        
       public void Divide()
       {
           Debug.Log("Germ Dividing! Count: " + (curCount *= divideMuti));
       }
        
       public void Infect()
       {
           Debug.Log("Germ Infecting! Target: " + infectTargetID++);
       }
    }

    病菌有两个行为,分裂和感染,如果按照输入直接控制行为,那它的代码是这样的。

    void Update() {
        if (Input.GetKeyDown(KeyCode.D))
           Divide();
        else if (Input.GetKeyDown(KeyCode.I))
           Infect();
    }

    显然,我看这段代码更像是测试时随便码上的。这样写虽然没错,但是想象一下,它不能被扩展了,比如想改变按键触发时的行为,你可能会说代码直接换下执行函数不就行了,可是游戏发布后你的玩家可没那么聪明!让我们分离输入到行为的直接控制,抽象出一个命令来进行调用。
    直接上代码!

    public abstract class Command
    {
        public abstract void Excute(Germ germ);
    }
    
    public class DivideCommand : Command
    {
        public override void Excute(Germ germ)
        {
            germ.Divide();
        }
    }
    
    public class InfectCommand : Command
    {
        public override void Excute(Germ germ)
        {
            germ.Infect();
        }
    }
    
    public class NoneCommand : Command
    {
       public override void Excute(Germ germ){}
    }

    定义了一个命令的抽象类Command,Excute(Germ germ)是执行方法,传入了一个病菌对象的引用,为什么这么做?你可以用这个命令控制你想控制的病菌,而不是只能控制一个。设想下当你有个技能是精神控制,把被你控制的角色用这些命令来驱动,那你可以为所欲为!我继承了两个用于实现抽象命令的具体类,最后还有一个什么也不做的命令,其目的在于命令传递中,你不想把null值到处流窜。
    命令定义好之后,还需要一个处理这些命令到底如何分配,代码如下:

    public abstract class Handler
    {
        protected Command[] commands;
        protected Command noneCommand;
        
        public Handler(Command[] commands)
        {
            noneCommand = new NoneCommand();
            this.commands = commands;
        }
        
        public abstract Command Handling();
    }
    
    public class InputHandler : Handler
    {
        public InputHandler(Command[] commands) : base(commands){}
        
        public override Command Handling()
        {
            if (Input.GetKeyDown(KeyCode.D))
                return commands[0];
            else if (Input.GetKeyDown(KeyCode.I))
                return commands[1];
            else
                return noneCommand;
        }
    }

    处理命令的Handler类构造需要一个Command的数组,InputHandler中实现了处理命令的方式,命令的调用根据数组的不同,可以生成不同的按键映射,当然这不是最好的方式,但比之前的要好!
    现在,我们来写一段测试代码,如下:

    public class CommandPattern : MonoBehaviour
    {
        private Germ curGerm;
        private InputHandler inputHandler;
        
        private void Start()
        {
            curGerm = new Germ(2, 1);
            Command[] comds = new Command[2] { new DivideCommand(), new InfectCommand() };
            inputHandler = new InputHandler(comds);
        }
        
        private void Update()
        {
            Command comd = inputHandler.Handling();
            comd.Excute(curGerm);
        }
    }

    测试正常运行!按下D键,病菌分裂,按下I键,病菌感染目标。我可以随时更换要操作的病菌对象!

    3.扩展

    有了命令模式,我想我还可以做很多事。之前的代码抽象了处理命令的处理器Handler,再重写一个新的处理逻辑AIHandler,可以自动控制病菌的行为。

    public class AIHandler : Handler
    {    
        public AIHandler(Command[] commands) : base(commands){}
        
        public override Command Handling()
        {
            if (Time.frameCount % 60 == 0)
            {
                return commands[Random.Range(0, commands.Length)];
            }
            else {
                return noneCommand;
            }
        }
    }

    每60帧随机产生一种命令,控制病菌的行为,当然这很Low,你可以写出更酷炫的实现方式!
    更改测试代码

    public class CommandPattern : MonoBehaviour
    {
        public bool InputHandlerSwitch;//输入处理器开关。
        
        private Germ curGerm;
        private InputHandler inputHandler;
        private AIHandler iHandler;
        
        private void Start()
        {
            curGerm = new Germ(2, 1);
            Command[] comds = new Command[2] { new DivideCommand(), new InfectCommand() };
            inputHandler = new InputHandler(comds);
            iHandler = new AIHandler(comds);
        }
        
        private void Update()
        {
            Command comd = InputHandlerSwitch ? inputHandler.Handling() : iHandler.Handling();
            comd.Excute(curGerm);
        }
    }

    启用InputHandlerSwitch时,Germ受输入控制,关闭时自动控制。

    命令模式不止于此,你还可以把命令存起来,实现撤销,重做,等功能。回放功能也如此,按照时间顺序把命令从队列中依次取出,用命令控制你要回放的对象行为,倒放也可以弄…
    谢谢大家赏脸,如有错误还请指正,本人第一次写博客,请多指教!

    展开全文
  • 游戏设计模式学习笔记(19)装饰模式、适配器模式、代理模式 参考: 《设计模式与游戏完美开发》 《游戏编程模式》(https://github.com/tkchu/Game-Programming-Patterns-CN) 《图说设计模式( Graphic Design ...

    游戏设计模式学习笔记(19)装饰模式、适配器模式、代理模式

    参考:

    《设计模式与游戏完美开发》

    《游戏编程模式》(https://github.com/tkchu/Game-Programming-Patterns-CN)

    《图说设计模式( Graphic Design Patterns)》(https://github.com/me115/design_patterns)

    【游戏设计模式】浅墨_毛星云: https://blog.csdn.net/poem_qianmo/article/details/53240330

    runoob.com 设计模式:https://design-patterns.readthedocs.io/zh_CN/latest/structural_patterns/decorator.html


    • “一个具有新功能的类,加入到现有群组结构中,且不破坏原有架构和接口” 的结构模式。
      在这里插入图片描述

    装饰模式

    定义

    • 动态额外的责任给一个对象,提供一个灵活的选择,给子类扩展功能。

    • 可以代替继承。

    • 相当于加多一层封装。

    在这里插入图片描述

    优缺点

    • 优点
      • 装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
    • 缺点
      • 装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

    应用

    • 网络数据加密解密。
    • 界面的特效,,可以在原有界面组件上增加一个接口特效装饰者。

    适配器模式

    定义

    • 将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。
    • 最常见例子:插头适配器。

    在这里插入图片描述

    • Client:客户类,是Target目标接口的对象。

    • Target:目标抽象类,定义提供给客户端使用的接口。

    • Adaptee:适配者类,与客户端预期不同的类

    • Adapter:适配器类。

      • 继承Target,让客户端可以操作。
      • 包含Adaptee转换类,可以作为引用或者组合。
      • 实现Target的request方法,调用Adaptee的方法。

    应用

    • 分离项目和第三方库。

    代理模式

    定义

    • 提供一个代理者位置给对象,让代理者可以控制存取这个对象。
    • 举例:秘书(代理)过滤电话给总经理。

    在这里插入图片描述

    • Subject: 抽象主题角色,定义让客户端操作的接口
    • RealSubject: 真正执行功能的类
    • Proxy: 代理RealSubject,实现Subject的接口,做前置判断,必要时调转调RealSubject的操作

    与装饰模式的区别

    • 代理模式可以选择新功能是否要继续执行,而装饰者是除了原有功能之外,也一定要执行的功能。

    与适配器的区别

    • 适配器注重于“不同实现的转换”。

    应用

    • 远程代理。
    • 虚拟代理:让资源延后加载,即资源真正要用的时候才加载。
    • 保护代理:控制是否真正取用原始对象的资源。
    • 智能引用(智能指针):C++减少内存遗失和空指针问题。
    展开全文
  • 游戏设计模式】之四 游戏编程模式 全书内容提炼总结
                   




     本系列文章由@浅墨_毛星云 出品,转载请注明出处。  
     文章链接: http://blog.csdn.net/poem_qianmo/article/details/53240330
     作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 

     本文的Github版本:QianMo/Reading-Notes/《游戏编程模式》读书笔记



    这是一篇超过万字读书笔记,总结了《Game Programming Patterns》(中译版《游戏编程模式》)一书中所有章节与内容的知识梗概。

    我们知道,游戏行业其实一直很缺一本系统介绍游戏编程进阶技巧的书籍,而《游戏编程模式》的出现,正好弥补了这一点。

    之前已经有提到过,不同于传统的出版方式,这本书是网络出版,然后Web版完全免费,其更是在amazon上具有罕见的5星评价,可见读者对其的好评程度之高。加之书中内容生动有趣,将各种经验之谈娓娓道来,实在是业界良心。

    书本主页:http://gameprogrammingpatterns.com/

    Web版全文阅读:http://gameprogrammingpatterns.com/contents.html

    全书中文翻译:http://gpp.tkchu.me/




    在这篇文章之前,我已经写了三篇相关的读书笔记,但感觉一次一种模式的介绍,节奏太慢,就用这篇总结式的文章来把19种设计模式一次介绍完。

     



     

    文章的短版本:全书内容思维导图



    以下是《游戏编程模式》一书的内容梗概,全书内容19种模式的思维导图:







    本文阅读说明

     


    本文按照《游戏编程模式》书中顺序,对全书的19种模式分以下三个方面进行了介绍:

    • 要点
    • 使用场合
    • 引申与参考

    依次介绍完19种模式之后,最终给出了一些更多的参考与学习资源。

    需要注意,设计模式本身在理解上就比较抽象。而因为本文是设计模式内容的总结式介绍,所以理解坡度自然会比较陡。若总结的部分不太理解的地方,建议大家去阅读原文(在每种模式的“引申与参考”一部分都已经给出了链接),将这篇文章对原文的总结与原文结合起来理解,这样掌握起来会比较顺畅。





     

    一、常用GOF设计模式




    这一部分介绍了游戏开发中较为常用的六种GOF设计模式:

    • 命令模式
    • 享元模式
    • 观察者模式
    • 原型模式
    • 单例模式
    • 状态模式




    1.  命令模式 Command Pattern


    命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象,同时支持可撤消的操作。


    要点

    • 将一组行为抽象为对象,这个对象和其他对象一样可以被存储和传递,从而实现行为请求者与行为实现者之间的松耦合,这就是命令模式。
    • 命令模式是回调机制的面向对象版本。
    • 命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开。
    • 命令模式的优点有:对类间解耦、可扩展性强、易于命令的组合维护、易于与其他模式结合,而缺点是会导致类的膨胀。
    • 命令模式有不少的细分种类,实际使用时应根据当前所需来找到合适的设计方式。

     

    使用场合

    • 命令模式很适合实现诸如撤消,重做,回放,时间倒流之类的功能。
    • 基于命令模式实现录像与回放等功能,也就是执行并解析一系列经过预录制的序列化后的各玩家操作的有序命令集合。

     

    引申与参考

     

     



    2. 享元模式 Flyweight Pattern


    享元模式,以共享的方式高效地支持大量的细粒度的对象。通过复用内存中已存在的对象,降低系统创建对象实例的性能消耗。

     

    要点

    • 享元模式中有两种状态。内蕴状态(Internal State)和外蕴状态(External State)。
      • 内蕴状态,是不会随环境改变而改变的,是存储在享元对象内部的状态信息,因此内蕴状态是可以共享的。对任何一个享元对象而言,内蕴状态的值是完全相同的。
      • 外蕴状态,是会随着环境的改变而改变的。因此是不可共享的状态,对于不同的享元对象而言,它的值可能是不同的。
    • 享元模式通过共享内蕴状态,区分外蕴状态,有效隔离系统中的变化部分和不变部分。

    使用场合


    在以下情况都成立时,适合使用享元模式:

    • 当系统中某个对象类型的实例较多的时候。
    • 由于使用了大量的对象,造成了很大的存储开销。
    • 对象的大多数状态都可变为外蕴状态。
    •  在系统设计中,对象实例进行分类后,发现真正有区别的分类很少的时候。

     


    引申与参考

     

     

    3. 观察者模式 Observer Pattern



    观察者模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。


    要点


    • 观察者模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
    • 我们知道,将一个系统分割成一个一些类相互协作的类有一个不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。观察者就是解决这类的耦合关系的。
    • 目前广泛使用的MVC模式,究其根本,是基于观察者模式的。
    • 观察者模式应用广泛,Java甚至将其放到了核心库之中(java.util.Observer),而C#直接将其嵌入了语法(event关键字)中。

     

    使用场合

    • 当一个抽象模式有两个方面,其中一个方面依赖于另一个方面,需要将这两个方面分别封装到独立的对象中,彼此独立地改变和复用的时候。
    • 当一个系统中一个对象的改变需要同时改变其他对象内容,但是又不知道待改变的对象到底有多少个的时候。
    • 当一个对象的改变必须通知其他对象作出相应的变化,但是不能确定通知的对象是谁的时候。

     

    引申与参考

     

     



    4.  原型模式 Prototype Pattern

     


    用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

     

    要点

    • 原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
    • 原型模式是一种比较简单的模式,也非常容易理解,实现一个接口,重写一个方法即完成了原型模式。在实际应用中,原型模式很少单独出现。经常与其他模式混用,他的原型类Prototype也常用抽象类来替代。
    • 使用原型模式拷贝对象时,需注意浅拷贝与深拷贝的区别。
    • 原型模式可以结合JSON等数据交换格式,为数据模型构建原型。

     

    使用场合

    • 产生对象过程比较复杂,初始化需要许多资源时。
    • 希望框架原型和产生对象分开时。
    • 同一个对象可能会供其他调用者同时调用访问时。

     

    参考与引申

     

     


    5.  单例模式 Singleton Pattern



    保证一个类只有一个实例,并且提供了访问该实例的全局访问点。

     


    要点

    • 单例模式因其方便的特性,在开发过程中的运用很多。
    • 单例模式有两个要点,保证一个类只有一个实例,并提供访问该实例的全局访问点。
    • 尽量少用单例模式。单例模式作为一个全局的变量,有很多全局的变量的弊病。它会使代码更难理解,更加耦合,并且对并行不太友好。

     

    使用场合

    • 当在系统中某个特定的类对象实例只需要有唯一一个的时候。
    • 单例模式要尽量少用,无节制的使用会带来各种弊病。
    • 为了保证实例是单一的,可以简单的使用静态类。 还可以使用静态标识位,在运行时检测是不是只有一个实例被创建了。


    参考与引申

     


    6.  状态模式 State Pattern


    允许对象在当内部状态改变时改变其行为,就好像此对象改变了自己的类一样。


    要点

    • 状态模式用来解决当控制一个对象状态转换的条件表达式过于复杂的情况,它把状态的判断逻辑转移到表示不同的一系列类当中,可以把复杂的逻辑判断简单化。
    • 状态模式的实现分为三个要点:
      • 为状态定义一个接口。
      • 为每个状态定义一个类。
      • 恰当地进行状态委托。
    • 通常来说,状态模式中状态对象的存放有两种实现存放的思路:
      • 静态状态。初始化时把所有可能的状态都new好,状态切换时通过赋值改变当前的状态。
      • 实例化状态。每次切换状态时动态new出新的状态。

     

    使用场合


    • 在游戏开发过程中,涉及到复杂的状态切换时,可以运用状态模式以及状态机来高效地完成任务。
    • 有限状态机的实现方式,有两种可以选择:
      • 用枚举配合switch case语句。
      • 用多态与虚函数(即状态模式)。
    • 有限状态机在以下情况成立时可以使用:
      • 有一个行为基于一些内在状态的实体。
      • 状态可以被严格的分割为相对较少的不相干项目。
      • 实体可以响应一系列输入或事件。

     

    参考与引申

     

     

     


     

     

    二、序列型模式 Sequencing Patterns




    本章的三种模式都是游戏开发中的常客:

    • 游戏循环是游戏运行的主心骨。
    • 游戏对象通过更新方法来进行每帧的更新。
    • 我们可以用双缓冲模式存储快照,来隐藏计算机的顺序执行,从而使得游戏世界能够同步更新。



    7.  双缓冲模式 Double Buffer

     

    双缓冲模式,使用序列操作来模拟瞬间或者同时发生的事情。


    要点

    • 一个双缓冲类封装了一个缓冲:一段可改变的状态。这个缓冲被增量的修改,但我们想要外部的代码将其视为单一的元素修改。 为了实现这点,双缓冲类需保存两个缓冲的实例:下一缓存和当前缓存。
    • 当信息从缓冲区中读取,我们总是去读取当前的缓冲区。当信息需要写到缓存,我们总是在下一缓冲区上操作。 当改变完成后,一个交换操作会立刻将当前缓冲区和下一缓冲区交换, 这样新缓冲区就是公共可见的了。旧的缓冲区则成为了下一个重用的缓冲区。
    • 双缓冲模式常用来做帧缓冲区交换。

    使用场合


    双缓冲模式是那种你需要它时自然会想起来的模式。以下情况都满足时,使用这个模式很合适:

    • 我们需要维护一些被增量修改的状态
    • 在修改过程中,状态可能会被外部请求。
    • 我们想要防止请求状态的外部代码知道内部是如何工作的。
    • 我们想要读取状态,而且不想在修改的时候等待。

     

    引申与参考

     


    8.  游戏循环模式 Game Loop


    游戏循环模式,实现游戏运行过程中对用户输入处理和时间处理的解耦。

     

    要点

    • 游戏循环模式:游戏循环在游戏过程中持续运转。每循环一次,它非阻塞地处理用户的输入,更新游戏状态,并渲染游戏。它跟踪流逝的时间并控制游戏的速率。
    • 游戏循环将游戏的处理过程和玩家输入解耦,和处理器速度解耦,实现用户输入和处理器速度在游戏行进时间上的分离。
    • 游戏循环也许需要与平台的事件循环相协调。如果在操作系统的高层或有图形UI和内建事件循环的平台上构建游戏, 那就有了两个应用循环在同时运作,需要对他们进行相应的协调。

     

    使用场合


    任何游戏或游戏引擎都拥有自己的游戏循环,因为游戏循环是游戏运行的主心骨。

     


    引申与参考

     



    9.  更新方法 Update Method



    更新方法,通过每次处理一帧的行为来模拟一系列独立对象。


    要点

    • 更新方法模式:在游戏中保持游戏对象的集合。每个对象实现一个更新方法,以处理对象在一帧内的行为。每一帧中,游戏循环对集合中的每一个对象进行更新。
    • 当离开每帧时,我们也许需要存储下状态,以备不时之需。


     

    使用场合


    更新方法和游戏循环模式一般一起使用。更新方法适应以下情况:

    • 游戏中有很多对象或系统需要同时运行。
    • 每个对象的行为都与其他的大部分独立。
    • 游戏中的对象需要随时间模拟。

    引申与参考

    • 更新方法模式,以及游戏循环模式和组件模式,是构建游戏引擎核心的铁三角。
    • Unity引擎在多个类中使用了这个模式,包括MonoBehaviour。
    • 微软的XNA框架在 Game 和GameComponent 类中使用了这个模式。
    • 当你关注在每帧中更新实体或组件的缓存性能时,数据局部性模式可以帮上忙。
    • 本节内容相关的英文原文:http://gameprogrammingpatterns.com/update-method.html
    • 本节内容相关的中文翻译:http://gpp.tkchu.me/update-method.html

     




     

    三、行为型模式 Behavioral Patterns



    本章的模式可以帮助我们快速定义和完善多种多样的行为:

     

    • 类型对象定义行为的类别而无需完成真正的类。
    • 子类沙盒定义各种行为的安全原语。
    • 字节码,将行为从代码中拖出,放入数据。

     

    10. 字节码模式 Bytecode



    字节码模式,将行为编码为虚拟机器上的指令,来赋予其数据的灵活性。从而让数据易于修改,易于加载,并与其他可执行部分相隔离。

     

    要点

    • 字节码模式:指令集定义了可执行的底层操作。一系列的指令被编码为字节序列。 虚拟机使用中间值堆栈 依次执行这些指令。 通过组合指令,可以定义复杂的高层行为。
    • 可以理解为项目中的转表工具,将excel中的数据转为二进制数据,并读取到工程中,如在项目中使用googleprotobuf或json。
    • 字节码类似GOF的解释器模式,这两种方式都能让我们将数据与行为相组合。其实很多时候都是两者一起使用。用来构造字节码的工具会有内部的对象树,而为了编译到字节码,我们需要递归回溯整棵树,就像用解释器模式去解释它一样。唯一的不同在于,并不是立即执行一段行为,而是生成整个字节码再执行

     

    使用场合


    这是GPP一书中最复杂的模式,不能轻易的加入到游戏中。 当我们需要定义很多行为,而游戏实现语言因为以下原因不能很好地完成任务时,就可以使用字节码模式:

    • 这些行为过于底层,繁琐易错。
    • 这些行为遍历起来很缓慢,导致编译时间长。
    • 这些行为太受依赖。如果想保证行为不会破坏游戏,你需要将其与代码的其他部分隔开。

    如果是上述的这些情况,就比较适合使用字节码模式。

    但需要注意,字节码比本地代码慢,所以最好不要用于引擎对性能敏感的部分。

     

    引申与参考

     



    11. 子类沙箱模式 Subclass Sandbox



    用一系列由基类提供的操作定义子类中的行为。


    要点


    子类沙箱模式:基类定义抽象的沙箱方法和几个提供操作的实现方法,将他们设为protected,表明它们只为子类所使用。每个推导出的沙箱子类用提供的操作实现了沙箱方法。

     

    使用场合


    子类沙箱模式是潜伏在编程日常中简单常用的模式,哪怕是在游戏之外的地方。 如果有一个非虚的protected方法,你可能早已在用类似的技术了。

    沙箱方法在以下情况适用:

    • 你有一个能推导很多子类的基类。
    • 基类可以提供子类需要的所有操作。
    • 在子类中有行为重复,你想要更容易的在它们间分享代码。
    • 你想要最小化子类和程序的其他部分的耦合。

     

    引申与参考

     

    12. 类型对象模式 Type Object

     

    创造一个类A来允许灵活的创造新的类,而类A的每个实例都代表了不同类型的对象。

     

    要点

    • 类型对象模式:定义类型对象类与有类型的对象类。每个类型对象实例代表一种不同的逻辑类型。每种有类型的对象保存描述它类型的对类型对象的引用。
    • 类型对象的基本思想就是给基类一个品种类(breed类),而不是用一些子类继承自这个基类。所以我们在做种类区分的时候就可以只有两个类,怪物类monster和品种类breed,而不是monster,dragon,troll等一堆类。所以在此种情况下,游戏中的每个怪物都是怪物类的一个实例,而实例中的breed类包含了所有同种类型怪物共享的信息。

     

     

    使用场合


    这个模式在任何你需要定义不同“种”事物,使用不当会让你的系统过于僵硬。而下面两者之一成立时,就非常适合使用:

    • 不知道后续还需什么新类型。(举个例子,如果你的游戏需要支持增量更新,让用户下载后续新包含进来的怪物品种)
    • 想要不改变代码或不重新编译就能修改或添加新类型。

     

    引申与参考

    • 这个模式引出的进阶问题是如何在不同对象之间共享数据。以不同的方式解决同一个问题的是GOF设计模式中的原型模式(prototype pattern)。
    • 类型对象是GOF设计模式中享元模式的亲兄弟。两者都让你在实例间分享代码。使用享元,意图是节约内存,而分享的数据也许不代表任何概念上对象的“类型”。而使用类型对象模式,焦点在组织性和灵活性。
    • 这个模式和GOF设计模式中状态模式有很多相似之处,两者都是委托了对象的部分定义给另外一个对象。
    • 本节内容相关的英文原文:http://gameprogrammingpatterns.com/type-object.html
    • 本节内容相关的中文翻译:http://gpp.tkchu.me/type-object.html





     

    四、解耦型模式  Decoupling Patterns



    这一部分的三种模式,专注于解耦:

    • 组件模式将一个实体拆成多个,解耦不同的领域。
    • 事件队列解耦了两个互相通信的事物,稳定而且实时。
    • 服务定位器让代码使用服务而无需绑定到提供服务的代码上。


     

    13. 组件模式 Component


    允许单一的实体跨越多个领域,无需这些领域彼此耦合。

     

    要点

    • 组件模式:在单一实体跨越了多个领域时,为了保持领域之间相互解耦,可以将每部分代码放入各自的组件类中,将实体简化为组件的容器。
    • Unity引擎在设计中频繁使用了这种设计方法,从而让其易于使用。

     

    使用场合


    组件通常在定义游戏实体的核心部分中使用,当然,它们在其他地方也适用。这个模式在如下情况下可以很好的适用:

    • 有一个涉及了多个领域的类,而你想保持这些领域互相隔离。
    • 一个类正在变大而且越来越难以使用。
    • 想要能定义一系列分享不同能力的类,但是使用接口不足以得到足够的重用部分。


    引申与参考

    • Unity核心架构中GameObject类完全根据此模式来进行设计。
    • 这种模式与GOF设计模式中的策略模式类似。两种模式都是将对象的行为取出,委派到一个单独的从属对象中。两者的不同点在于:
    • 策略模式中分离出的策略对象通常是无状态的——它封装的是算法,而不是数据。策略模式定义了对象的行为,而不是该对象是什么。
    • 而组件模式就更加复杂。组件经常保存了对象的状态,这有助于确定其真正的身份。但是,其界限往往很模糊。有些情况下组件也许根本没有任何状态。在这种情况下,你可以在不同的容器对象中使用相同的组件实例。这样看来,它的行为确实更像一种策略。
    • 本节内容相关的英文原文:http://gameprogrammingpatterns.com/component.html
    • 本节内容相关的中文翻译:http://gpp.tkchu.me/component.html

     

     

     

    14. 事件队列模式 Event Queue


    事件队列模式,对消息或事件的发送与处理进行时间上的解耦。

     

    要点

    • 事件队列:在先入先出的队列中存储一系列通知或请求。发送通知时,将请求放入队列并返回。处理请求的系统在稍晚些的时候从队列中获取请求并进行处理。 这样就解耦了发送者和接收者,既静态又及时。
    • 事件队列很复杂,会对游戏架构引起广泛影响。中心事件队列是一个全局变量。这个模式的通常方法是一个大的交换站,游戏中的每个部分都能将消息送过这里。
    • 事件队列是基础架构中很强大的存在,但有些时候强大并不代表好。事件队列模式将状态包裹在协议中,但是它还是全局的,仍然存在全局变量引发的一系列危险。

     

    使用场合

    • 如果你只是想解耦接收者和发送者,像观察者模式和命令模式都可以用较小的复杂度来进行处理。在需要解耦某些实时的内容时才建议使用事件队列。
    • 不妨用推和拉来的情形来考虑。有一块代码A需要另一块代码B去做些事情。对A自然的处理方式是将请求推给B。同时,对B自然的处理方式是在B方便时将请求拉入。当一端有推模型另一端有拉模型时,你就需要在它们间放一个缓冲的区域。 这就是队列比简单的解耦模式多出来的那一部分。队列给了代码对拉取的控制权——接收者可以延迟处理,合并或者忽视请求。发送者能做的就是向队列发送请求然后就完事了,并不能决定什么时候发送的请求会受到处理。
    • 而当发送者需要一些回复反馈时,队列模式就不是一个好的选择。

    引申与参考


    • 很大程度上,事件队列模式就是广为人知的GOF设计模式中观察者模式的异步实现。
    • 就像其他很多模式一样,事件队列有很多别名。其中一个是“消息队列”。 消息队列通常指代一个更高层次的实现。可以这样理解,事件队列在应用中进行交流,而消息队列通常在应用间进行交流。另一个别名是“发布/提交”,有时被缩写为“pubsub”,这个别名通常指代更大的分布式系统中的应用。
    • 在有限状态机与状态模式中,往往需要一个输入流。如果想要异步响应,可以考虑用队列模式来存储它们。
    • Go语言内建的“Channel”机制,其本质上就是事件队列。
    • 本节内容相关的英文原文:http://gameprogrammingpatterns.com/event-queue.html
    • 本节内容相关的中文翻译:http://gpp.tkchu.me/event-queue.html

     



    15. 服务定位模式 Service Locator



    提供服务的全局接入点,而不必让用户和实现它的具体类耦合。

     

    要点

    • 服务定位模式:服务类定义了一堆操作的抽象接口。具体的服务提供者实现这个接口。 分离的服务定位器提供了通过查询合适的提供者, 获取服务的方法,同时隐藏了提供者的具体细节和需要定位它的进程。
    • 一般通过使用单例或者静态类来实现服务定位模式,提供服务的全局接入点。
    • 服务定位模式可以看做是更加灵活,更加可配置的单例模式。如果用得好,它能以很小的运行时开销,换取很大的灵活性。相反,如果用得不好,它会带来单例模式的所有缺点以及更多的运行时开销。
    • 使用服务定位器的核心难点是它将依赖,也就是两块代码之间的一点耦合,推迟到运行时再连接。这有了更大的灵活度,但是代价是更难在阅读代码时理解其依赖的是什么。

     

     

    使用场合


    • 服务定位模式在很多方面是单例模式的亲兄弟,在应用前应该考虑看看哪个更适合你的需求。
    • 让大量内容在程序的各处都能被访问时,就是在制造混乱。对何时使用服务定位模式的最简单的建议就是:尽量少用。
    • 与其使用全局机制让某些代码直接接触到它,不妨先考虑将对象传过来。因为这样可以明显地保持解耦,而且可以满足我们大部分的需求。当然,有时候不方便手动传入对象,也可以使用单例的方式。

     


    引申与参考


     



    五、优化型模式 Optimization Patterns



    这一部分,描述了几个优化和加速游戏的中间层模式:

    • 数据局部性介绍了计算机的存储层次以及如何使用其以获得优势。
    • 脏标识帮我们避开不必要的计算。
    • 对象池帮我们避开不必要的分配。
    • 空间分区加速了虚拟世界和其中内容的空间布局。

     



    16. 数据局部性模式 Data Locality

     

    合理组织数据,充分使用CPU的缓存来加速内存读取。

     

    要点


    • 现代的CPU有缓存来加速内存读取,其可以更快地读取最近访问过的内存毗邻的内存。基于这一点,我们通过保证处理的数据排列在连续内存上,以提高内存局部性,从而提高性能。
    • 为了保证数据局部性,就要避免的缓存不命中。也许你需要牺牲一些宝贵的抽象。你越围绕数据局部性设计程序,就越放弃继承、接口和它们带来的好处。没有银弹,只有权衡。

     

    使用场合

     

    • 使用数据局部性的第一准则是在遇到性能问题时使用。不要将其应用在代码库不经常使用的角落上。 优化代码后其结果往往更加复杂,更加缺乏灵活性。
    • 就本模式而言,还得确认你的性能问题确实由缓存不命中而引发的。如果代码是因为其他原因而缓慢,这个模式自然就不会有帮助。
    • 简单的性能评估方法是手动添加指令,用计时器检查代码中两点间消耗的时间。而为了找到糟糕的缓存使用情况,知道缓存不命中有多少发生,又是在哪里发生的,则需要使用更加复杂的工具—— profilers。
    • 组件模式是为缓存优化的最常见例子。而任何需要接触很多数据的关键代码,考虑数据局部性都是很重要的。


    引申与参考


     

     

     

    17. 脏标识模式 Dirty Flag

     


    将工作延期至需要其结果时才去执行,以避免不必要的工作。

     

    要点

    • 脏标记,就是用来表示被标记的内容是否有被修改过的一个标志位。
    • 脏标识模式:考虑情况,当前有一组原始数据随着时间变化而改变。由这些原始数据计算出目标数据需要耗费一定的计算量。这个时候,可以用一个脏标识,来追踪目前的原始数据是否与之前的原始数据保持一致,而此脏标识会在被标记的原始数据改变时改变。那么,若这个标记没被改变,就可以使用之前缓存的目标数据,不用再重复计算。反之,若此标记已经改变,则需用新的原始数据计算目标数据。

     

    使用场合

     

    • 就像其他优化模式一样,此模式会增加代码复杂度。只在有足够大的性能问题时,再考虑使用这一模式。
    • 脏标记在这两种情况下适用:
      • 当前任务有昂贵的计算开销
      • 当前任务有昂贵的同步开销。

     若满足这两者之一,也就是两者从原始数据转换到目标数据会消耗很多时间,都可以考虑使用脏标记模式来节省开销。

    • 若原始数据的变化速度远高于目标数据的使用速度,此时数据会因为随后的修改而失效,此时就不适合使用脏标记模式。

     

    引申与参考


     



    18. 对象池模式 Object Pool

     

    放弃单独地分配和释放对象,从固定的池中重用对象,以提高性能和内存使用率。


    要点

    • 对象池模式:定义一个包含了一组可重用对象的对象池。其中每个可重用对象都支持查询“使用中”状态,说明它是不是“正在使用”。 对象池被初始化时,就创建了整个对象集合(通常使用一次连续的分配),然后初始化所有对象到“不在使用中”状态。
    • 当我们需要新对象时,就从对象池中获取。从对象池取到一个可用对象,初始化为“使用中”然后返回给我们。当不再需要某对象时,将其设置回“不在使用中”状态。 通过这种方式,便可以轻易地创建和销毁对象,而不必每次都分配内存或其他资源。

     

    使用场合

    • 这个模式广泛使用在可见事物上,比如游戏物体和特效。但是它也可在不那么视觉化的数据结构上使用,比如正在播放的声音。
    • 满足以下情况可以使用对象池:
      • 需要频繁创建和销毁对象。
      • 对象大小相仿。
      • 在堆上分配对象缓慢或者会导致内存碎片。
      • 每个对象都封装了像数据库或者网络连接这样很昂贵又可以重用的资源。

     

    引申与参考

    • 对象池模式与GOF设计模式中享元模式类似。 两者都控制了一系列可重用的对象。不同在于重用的含义。
      • 享元对象分享实例间同时拥有的相同部分。享元模式在不同上下文中使用相同对象避免了重复内存使用。
      • 对象池中的对象也被重用了,但是是在不同的时间点上被重用的。重用在对象池中意味着对象在原先的对象用完之后再分配内存。对象池的对象不会在它的生命周期中与其他对象共享数据。
    • 将内存中同样类型的对象进行整合,能确保在遍历对象时CPU缓存是满载的。这便是数据局部性模式中介绍的内容。
    • 本节内容相关的英文原文:http://gameprogrammingpatterns.com/object-pool.html
    • 本节内容相关的中文翻译:http://gpp.tkchu.me/object-pool.html

     


    19. 空间分区模式 Spatial Partition

     

    将对象存储在基于位置组织的数据结构中,来有效的定位对象。

     

    要点

    • 对于一系列对象,每个对象都有空间上的位置。将它们存储在根据位置组织对象的空间数据结构中,让我们有效查询在某处或者附近的对象。 当对象的位置改变时,更新空间数据结构,这样它可以继续找到对象。
    • 最简单的空间分区:固定网格。想象某即时战略类游戏,一改在单独的数组中存储我们的游戏对象的常规思维,我们将它们存到网格的格子中。每个格子存储一组单位,它们的位置在格子的边界内部。当我们处理战斗时,一般只需考虑在同一格子或相邻格子中的单位,而不是将每个游戏中的单位与其他所有单位比较,这样就大大节约了计算量。

    使用场合

    • 空间分区模式在需要大量存储活跃、移动的游戏物体,和静态的美术模型的游戏中比较常用。因为复杂的游戏中不同的内容有不同的空间划分。
    • 这个模式的基本适用场景是你有一系列有位置的对象,当做了大量通过位置寻找对象的查询而导致性能下降的时候。
    • 空间分区的存在是为了将O(n)或者O(n²) 的操作降到更加可控的数量级。 你拥有的对象越多,此模式就越好用。相反的,如果n足够小,也许就不需要使用此模式。

    引申与参考


    • 了解了空间分区模式,下一步应该是学习一下常见的结构。常见的有:

    • 每种空间划分数据结构基本上都是将一维数据结构扩展成更高维度的数据结构。而了解它的直系子孙,有助于分辨其对当前问题的解答是不是有帮助:

     



     

    六、更多参考与学习资源

     


    [1] 本书的英文Web原版目录:

    http://gameprogrammingpatterns.com/contents.html 

    [2] 本书的中文翻译web版目录:http://gpp.tkchu.me/

    [3] https://www.youtube.com/playlist?list=PLF206E906175C7E07

    [4] https://github.com/Naphier/unity-design-patterns

    [5] http://www.dofactory.com/net/design-patterns

    [6] https://sourcemaking.com/design_patterns

    [7] 《设计模式:可复用面向对象软件的基础》

    [8] https://github.com/QianMo/Unity-Design-Pattern


               

    再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

    展开全文
  • 游戏设计模式学习笔记(13)桥接模式 参考: 《设计模式与游戏完美开发》 《游戏编程模式》(https://github.com/tkchu/Game-Programming-Patterns-CN) 《图说设计模式( Graphic Design Patterns)》...
  • 游戏设计模式学习笔记(11)外观模式 参考: 《设计模式与游戏完美开发》 《游戏编程模式》(https://github.com/tkchu/Game-Programming-Patterns-CN) 《图说设计模式( Graphic Design Patterns)》...
  • 游戏设计模式学习笔记(14)策略模式 参考: 《设计模式与游戏完美开发》 《游戏编程模式》(https://github.com/tkchu/Game-Programming-Patterns-CN) 《图说设计模式( Graphic Design Patterns)》...
  • 游戏设计模式学习笔记(15)模板模式 参考: 《设计模式与游戏完美开发》 《游戏编程模式》(https://github.com/tkchu/Game-Programming-Patterns-CN) 《图说设计模式( Graphic Design Patterns)》...
  • 游戏设计模式学习笔记(6)状态模式 参考: 《设计模式与游戏完美开发》 《游戏编程模式》(https://github.com/tkchu/Game-Programming-Patterns-CN) 《图说设计模式( Graphic Design Patterns)》...
  • 游戏设计模式学习笔记(5)单例模式 参考: 《设计模式与游戏完美开发》 《游戏编程模式》(https://github.com/tkchu/Game-Programming-Patterns-CN) 《图说设计模式( Graphic Design Patterns)》...
  • 游戏设计模式学习笔记(2)命令模式 参考: 《设计模式与游戏完美开发》 《游戏编程模式》(https://github.com/tkchu/Game-Programming-Patterns-CN) 《图说设计模式( Graphic Design Patterns)》...
  • 游戏设计模式学习笔记(20)工厂模式、抽象工厂模式 参考: 《设计模式与游戏完美开发》 《游戏编程模式》(https://github.com/tkchu/Game-Programming-Patterns-CN) 《图说设计模式( Graphic Design Patterns)...
  • 游戏设计模式Design Patterns Revisited 命令模式是我最喜欢的模式之一。 大多数我写的游戏或者别的什么之类的大型程序,都会在某处用到它。 当在正确的地方使用时,它可以将复杂的代码清理干净。 对于这样一个...
  • /* 游戏设计模式--命令模式 * 命令模式:将一个请求封装为一个对象(即我们创建的Command对象),从而使你可用不同的请求对客户进行参数化; * 对请求排队或记录请求日志,以及支持可撤销的操作。 * Command:定义...
  • /* 游戏设计模式--备忘录模式 * 备忘录模式(Memento Pattern)又叫做快照模式(Snapshot Pattern)或Token模式,是GoF的23种设计模式之一,属于行为模式。 * 定义:在不破坏封闭的前提下,捕获一个对象的内部状态...
  • 游戏设计模式学习笔记(21)建造者模式 参考: 《设计模式与游戏完美开发》 《游戏编程模式》(https://github.com/tkchu/Game-Programming-Patterns-CN) 《图说设计模式( Graphic Design Patterns)》...
  • 游戏设计模式学习笔记(18)访问者模式 参考: 《设计模式与游戏完美开发》 《游戏编程模式》(https://github.com/tkchu/Game-Programming-Patterns-CN) 《图说设计模式( Graphic Design Patterns)》...
  • 游戏设计模式学习笔记(16)责任链模式 参考: 《设计模式与游戏完美开发》 《游戏编程模式》(https://github.com/tkchu/Game-Programming-Patterns-CN) 《图说设计模式( Graphic Design Patterns)》...
  • 游戏设计模式学习笔记(12)中介者模式 参考: 《设计模式与游戏完美开发》 《游戏编程模式》(https://github.com/tkchu/Game-Programming-Patterns-CN) 《图说设计模式( Graphic Design Patterns)》...
  • 游戏设计模式学习笔记(17)备忘录模式 参考: 《设计模式与游戏完美开发》 《游戏编程模式》(https://github.com/tkchu/Game-Programming-Patterns-CN) 《图说设计模式( Graphic Design Patterns)》...
  • 游戏设计模式学习笔记(4)观察者模式 参考: 《设计模式与游戏完美开发》 《游戏编程模式》(https://github.com/tkchu/Game-Programming-Patterns-CN) 《图说设计模式( Graphic Design Patterns)》...
  • 游戏设计模式学习笔记(3)享元模式 参考: 《设计模式与游戏完美开发》 《游戏编程模式》(https://github.com/tkchu/Game-Programming-Patterns-CN) 《图说设计模式( Graphic Design Patterns)》...

空空如也

1 2 3 4 5 ... 20
收藏数 6,211
精华内容 2,484
关键字:

游戏设计模式