游戏开发设计模式之命令模式(unity3d 示例实现)
博主才学尚浅,难免会有错误,尤其是设计模式这种极富禅意且需要大量经验的东西,如果哪里书写错误或有遗漏,还请各位前辈指正。
打
算写设计模式的目的就是,首先自己可以理清思路,还有就是国内的设计模式资料很丰富,但是并没有专门用在游戏开发上的讲解,看过之后有些不知道怎么用在游
戏方面上,怎么用,博主在学习过程中会结合一些国外的游戏设计模式资料加上自己的理解与实践,写出文章,在自己理清思路的同时也希望能对像我这样的小白们
提供一点微薄帮助。
在我没学这个模式之前写的控制部分的代码,就是把按键控制写成if
else简单的,一次性的写在update()函数中,对这样散乱的块来做轮询,这样的代码不整体,是一次性的,难以维护,如果想要在其中新添加功能会非
常难找,改动也容易出现错误。之前的代码例子如下(错误示例,仅给出部分):
void Update()
{
if (Input.GetKeyDown(KeyCode.J))
{
…攻击操作…
}
if (Input.GetKeyDown(KeyCode.Space))
{
…跳跃操作…
}
if (Input.GetKey(KeyCode.D))
{
…向左移动操作…
}
}
相信不少人和我一样是这么写的,接下来要介绍命令模式,这种模式不仅能用在unity的脚本编程上,所有面向对象语言都适用。
命令模式是游戏中很有用的设计模式,四人帮有一句话是这样说的:
Encapsulate
a request as an object, thereby letting users parameterize clients with
different requests, queue or log requests, and support undoable
operations.
大概意思是,将请求封装为一个对象,让用户参数化的提出不同的请求,并提供撤销操作。
我们可以理解为是把命令具体化来调用。
比如把控制命令变成实实在在的实体来调用,就不用像上面错误的例子那样轮询一堆散乱的东西。
如下图,我们先把具体控制封装成函数,J键定义为act操作,把space键定义为jump操作。
命令模式好处之一:
方便替换按键,大家都知道大部分游戏设置中会有替换按键的设置,把按键设置为自己的常用键,玩着顺手,使用命令模式我们把每个操作控制封装成块,把用户按键操作与实现控制通过命令解耦,更改按键十分容易。如下图:
我们通过赋值b1,b2可以动态改变按键操作。但是这样方便的一切的前提都是使用命令模式把命令具体化来调用。
再把所有button整合成一个数组button
然后代码就变成了这样
void Update()
{
if (Input.GetKeyDown(button[0]))
{
act();
}
if (Input.GetKeyDown(button[1]))
{
jump();
}
if (Input.GetKey(button[2]))
{
move();
}
}
稍微规整了一些。而且这样我们就可以让玩家自定义按键了。
接下来我们就可以使用命令模式了,就是替换jump(),act(),move()这些操作为具体的command命令。
我们可以用一个借口command来抽象概括所有的这些命令,再分别实现它们。把这些操作看成客户下的命令,所以每一个command命令都应该有一个执行命令的函数execute()。代码如下:
using UnityEngine;
using System.Collections; public interface ICommand{
void execute();
}
这个接口就是我们的抽象,然后我们在一一实现我们的命令类,拿jump举例:
using UnityEngine;
using System.Collections; public class JumpCommand : ICommand
{
public void execute()
{
….实现jump….
}
}
但是这里出现了问题,jump命令是要用在我们的“hero”上的也就是玩家控制的人物,说白了就是一个
gameobject,所以只要把hero的gameobject传入我们的命令类即可。这样做带来了命令模式的另一个好处,举个博主最爱玩的游戏-传说
系列,里面一般有4-6个英雄可以替换控制(对,博主就是要安利你们玩。。),随意更换英雄,就是随意更换操作的人物,只要我们传参传入不同的hero
的gameobject即可。
using UnityEngine;
using System.Collections; public interface ICommand{
void execute(GameObject Hero);
}
然后这里我们可以选择是在一个新的脚本中实现操作,还是在这个command中实现,这两种都可以,前者重用性好,后者重用性差一些,但更具体。实例在一个新脚本HeroCtrl中实现具体操作:
using UnityEngine;
using System.Collections; public class JumpCommand : ICommand
{
public void execute(GameObject Hero)
{
Hero.GetComponent<HeroCtrl>().jump();
}
}
如果想在这个command中实现就可以这样:
using UnityEngine;
using System.Collections; public class JumpCommand : ICommand
{
float pow = 0.1f;
CharacterController controller;
public void execute(GameObject Hero)
{
controller = Hero.GetComponent<CharacterController>();
if (controller.isGrounded)
{
controller.Move(Vector3.up * pow);
Hero.GetComponent<Animation>().CrossFade(…);
}
}
}
此时的结构就是这样了,我们成功的实现了解耦:
我们在写AI的时候也可以使用命令模式,此时的AI逻辑只负责“发号施令”就可以了,更加灵活的编写AI。
然
后再次揭开sims的一个秘密,在玩sims可以对一个小人下许多命令,但是小人需要花时间才能干完一件事,通常我们看到我们想让他做的事的图标就会堆在
上面,小人会一个一个的处理,这就是任务列表,我们可以把代做的任务存到一个list中,给每个任务一个index,完成一个就做下一个,产生新任务就堆
在后面,这也是命令模式的一大功能。
然后就是撤销undo和重做redo部分,这个一般用在策略游戏中,我们错误操作了可以及时撤销。
undo实现方法就是把该任务反过来的操作作为undo函数,举一个最简单的例子:
public class addCommand : ICommand
{
public int execute(int num)
{
return ++num;
}
public int undo (int num)
{
return --num;
}
}
加法的undo就是减法,前移的undo就是后移。
如果想要redo的话就要把之前的操作储存起来,最好的办法把undo,当前操作,redo都存在一个堆中:
当产生一个新操作时,后面的redo全都不要了
游戏回放功能原理与之相同,回放时执行已经记录好的命令,有些游戏记录每一帧整个游戏的状态来回放,这样会消耗很多内存。
实现结果:
博主写了一个“玩具”用来专门练习设计模式,gameplay 模仿传说系列前几代。
命令模式完美运行:
命令模式完了。总之就是希望前辈们多多指正或者建议,能够带来帮助就更好。
博主近期渲染:最近用unity5弄的一些渲染
---- by wolf96
游戏开发设计模式之命令模式(unity3d 示例实现)的更多相关文章
- 游戏开发设计模式之原型模式 & unity3d JSON的使用(unity3d 示例实现)
命令模式:游戏开发设计模式之命令模式(unity3d 示例实现) 对象池模式:游戏开发设计模式之对象池模式(unity3d 示例实现) 实现原型模式 原型模式带来的好处就是,想要构建生成任意独特对象的 ...
- 游戏开发设计模式之状态模式 & 有限状态机 & c#委托事件(unity3d 示例实现)
命令模式:游戏开发设计模式之命令模式(unity3d 示例实现) 对象池模式:游戏开发设计模式之对象池模式(unity3d 示例实现) 原型模式:游戏开发设计模式之原型模式 & unity3d ...
- 游戏开发设计模式之对象池模式(unity3d 示例实现)
前篇:游戏开发设计模式之命令模式(unity3d 示例实现) 博主才学尚浅,难免会有错误,尤其是设计模式这种极富禅意且需要大量经验的东西,如果哪里书写错误或有遗漏,还请各位前辈指正. 原理:从一个固定 ...
- python设计模式之命令模式
python设计模式之命令模式 现在多数应用都有撤销操作.虽然难以想象,但在很多年里,任何软件中确实都不存在撤销操作.撤销操作是在1974年引入的,但Fortran和Lisp分别早在1957年和195 ...
- 乐在其中设计模式(C#) - 命令模式(Command Pattern)
原文:乐在其中设计模式(C#) - 命令模式(Command Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 命令模式(Command Pattern) 作者:webabcd ...
- 面向对象设计模式_命令模式(Command)解读
在.Net框架中很多对象的方法中都会有Invoke方法,这种方法的设计实际是用了设计模式的命令模式, 模式图如下 其核心思路是将Client 向Receiver发送的命令行为进行抽象(ICommand ...
- 设计模式 ( 十三 ) 命令模式Command(对象行为型)
设计模式 ( 十三 ) 命令模式Command(对象行为型) 1.概述 在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需 ...
- 折腾Java设计模式之命令模式
博客原文地址 折腾Java设计模式之命令模式 命令模式 wiki上的描述 Encapsulate a request as an object, thereby allowing for the pa ...
- 用Java 8 Lambda表达式实现设计模式:命令模式
在这篇博客里,我将说明如何在使用 Java 8 Lambda表达式 的函数式编程方式 时实现 命令 设计模式 .命令模式的目标是将请求封装成一个对象,从对客户端的不同类型请求,例如队列或日志请求参数化 ...
随机推荐
- C#中有关字符串去重的解决方案
今天在群里看到一个同学的面试题 题目中有一个这样的要求 //本地有个文档文件a.txt里面包含的内容分为一段字符串"abacbacde"请编写一个程序,获取文件得到对应的内容,并对 ...
- Android 读取txt文件并以utf-8格式转换成字符串
博客: 安卓之家 微博: 追风917 CSDN: 蒋朋的家 简书: 追风917 博客园: 追风917 # 使用EncodingUtils 今天用到了城市选择三级联动的库,用的这个:https://gi ...
- Android基础问题汇总
一.android:gravity 和android:layout_gravity的区别: android;gravity是自己的内容相对于自己的控件的位置,而android:layout_gravi ...
- 正则表达式-delphi
一.工具选择 在 Delphi 中使用正则表达式, 目前 PerlRegEx 应该是首选, 准备彻底而细致地研究它. 官方网站: http://www.regular-expressions.inf ...
- 数据库(学习整理)----3--Oracle创建表和设置约束
BBS论坛表设计 包含的表:BBSusers(用户表),BBSsection(版块表),BBStopic(主贴表),BBSreply(跟帖表) 表结构 1)BBSusers 字段名 字段说明 数据类型 ...
- 注解 @RequestMapping
通过RequestMapping注解可以定义不同的处理器映射规则. 1.URL路径映射 @RequestMapping(value="/item")或@RequestMapping ...
- VC++ 17、18课
进程间通信的四种方式: 剪贴板 匿名管道 命名管道 邮槽 容器和服务器程序 容器应用程序是可以嵌入或链接对象的应用程序.word就是容器应用程序. 服务器应用程序是创建对象并且当对象呗双击时,可以被启 ...
- Savelog项目总结回忆
Savelog项目的细节已经不太记得,感觉有些遥远,需要翻回旧的笔记本电脑或者是旧的笔记本. 概述: 本项目采用的Linux C,监听一个或多个特殊的端口,当其中一个端口有发起连接时就产生一个新的线程 ...
- 做了五套登录页,晒一下 自己比较满意的~ oh yeh~
- 《Velocity java开发指南》中文版(上)转载
文章引自:http://sakyone.iteye.com/blog/524289 1.开始入门 Velocity是一基于java语言的模板引擎,使用这个简单.功能强大的开发工具,可以很容易的将数据对 ...