命令模式的描述:

命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。


意图: 将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。


需求描述给定两种不同的工具:锤子、刷子;锤子可以用来砸开泥土表层,刷子可以用来清理泥土表面的灰尘。要求:当选中的工具为锤子时,鼠标点击屏幕的任意位置,锤子移动到鼠标点击的位置。当选中的工具为刷子时,鼠标点击屏幕的任意位置,刷子移动到鼠标点击的位置,并且如果不放开鼠标,可以继续拖动刷子(即刷子跟随鼠标移动)。下面分别使用常规方法和命令模式来实现。


首先给出一种最直接的、没有应用任何设计模式的实现方法,如下:

(代码仅作演示)

 void Update () {if (CurrentToolType == "刷子") {if (Input.GetMouseButtonDown (0)) {//计算鼠标相对刷子的偏移量}if (Input.GetMouseButton (0)) {//根据偏移量改变刷子的偏移量,并让刷子跟随鼠标移动}} else if (CurrentToolType == "锤子") {if (Input.GetMouseButtonDown (0)) {//将锤子的位置改变为鼠标的位置}}///******* */}

这种实现方法并没有什么错误,但是不利于扩展,比如说我现在需要加入镰刀、剪刀、菜刀等工具;且、这些工具的使用方法和刷子、锤子有相同和不同之处,那我就需要疯狂的在if语句里加判断,导致if语句臃肿;而且如果我需要为其中一些工具添加单独的限制条件,比如限制可拖动边界和可点击范围,那将是巨大的灾难。幸好,命令模式可以很好的帮我们解决这个问题。


首先对问题进行分析,我们有两个工具,用户可通过操作UI在工具之间进行切换;不同的工具有不同的使用方法;锤子需要通过点击鼠标来进行操作,刷子需要拖动鼠标来进行操作。两者都需要通过鼠标操作,那么我们可以为这个操作提供一个入口,抽象出一个基类来,代码如下:

public abstract class BaseCommand {/// <summary>/// 执行/// </summary>public abstract void Execute(Transform t);/// <summary>/// 边界限制/// </summary>public abstract  bool BoundClamp();
}

接下来实现具体的操作工具的命令类。

操作锤子工具的命令类,如下:


public class ClickCommand : BaseCommand {public override void Execute (Transform t) {if (Input.GetMouseButtonDown (0)) {Vector3 pos = Camera.main.ScreenToWorldPoint (Input.mousePosition);pos = new Vector3 (pos.x, pos.y, Camera.main.nearClipPlane);//Debug.Log(pos);t.transform.position = pos;}}/// <summary>/// 锤子工具没有边界限制,可以全屏点击/// </summary>/// <returns></returns>public override bool BoundClamp () {return true;}
}

操作刷子工具的命令类,如下:


public class SliderCommand : BaseCommand {private Vector3 offset = Vector3.zero;private bool isDown = false;public override void Execute (Transform t) {if (Input.GetMouseButtonDown (0)) {isDown = true;var pos = Camera.main.ScreenToWorldPoint (Input.mousePosition);offset = t.transform.position - pos;offset = new Vector3 (offset.x, offset.y, 0);          if (!ClickClamp (new Vector3 (pos.x, pos.y, pos.z), t)){if (!BoundClamp())return;t.transform.position=new Vector3(pos.x,pos.y,t.position.z);   offset=Vector3.zero;}}if (isDown) {if (Input.GetMouseButton (0)) {if (!BoundClamp())return;var pos = Camera.main.ScreenToWorldPoint (Input.mousePosition);pos = new Vector3 (pos.x, pos.y, t.transform.position.z);t.transform.position = pos + offset;}}if (Input.GetMouseButtonUp(0)){isDown=false;}}private bool ClickClamp (Vector3 pos, Transform t) {pos = new Vector3 (pos.x, pos.y, Camera.main.nearClipPlane);if (t.GetComponent<BoxCollider> ().bounds.Contains (pos)) {return true;}return false;}/// <summary>/// 为刷子添加一些拖动范围的限制,例如,/// 限制可拖动范围为距离屏幕边缘上200px、下100px/// </summary>/// <returns></returns>public override bool BoundClamp(){var pos=Input.mousePosition;//Debug.Log(pos);Rect rect=new Rect(200,100,Screen.width-200,Screen.height-100);if (pos.x<rect.x||pos.x>rect.width){return false;}if (pos.y<rect.y||pos.y>rect.height){return false;}return true;}
}

有的时候我们需要为每个工具做一些单独的配置,比如更换不同的图片,选择使用不同的操作命令之类的;那么,我们可以为工具增加一个配置类用来实例化不同的操作命令,配置类如下:

///利用C#的反射机制,通过给定的字符串来实例化相应的的命令
public class ToolConfig : MonoBehaviour {public BaseCommand command;public CommandType commandType;void Start () {Type type = Type.GetType (commandType.ToString ());if (type != null) {var temp = Activator.CreateInstance (type);command = temp as BaseCommand;}else{Debug.LogError("未找到要实例化的类,请检查类名是否和枚举值相同");}}
}
//通过枚举来定义命令类型
public enum CommandType
{ClickCommand,//锤子工具的命令DragCommand//刷子工具的命令
}

接下来就是具体的调用工具命令的类:
(控制器根据当前选择的工具来实例化相应的命令)

public class ToolController : MonoBehaviour {public BaseCommand _currentBasecommand;public Transform currentTran;public ToggleGroup _toggleGroup;public Toggle[] _toggles;void Start () {foreach (var item in _toggles) {item.onValueChanged.AddListener ((ison) => {_currentBasecommand = ison?item.GetComponent<ToolConfig> ().command : null;});}}void Update () {if (_currentBasecommand!=null){_currentBasecommand.Execute(currentTran);}}
}

Demo演示如下:


扫描关注->当前文章末尾->获取工程地址:


命令模式在游戏开发中的应用相关推荐

  1. [命令模式]在游戏开发中的应用

    设计模式中的每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心.这样,你就能一次又一次地使用该方案而不必做重复劳动. 一个设计模式,它的服务对象是高层模块,在设计模式中称为客 ...

  2. 中介者模式在游戏开发中的应用

    中介者模式: 定义一个接口用来封装一群对象的互动行为.中介者通过移除对象之间引用,来减少它们之间的耦合度,并且能改变它们之间的互动独立性. 意图: 通过中介者来解决对象之间的通信,使一个对象在不需要知 ...

  3. [策略模式]在游戏开发中的应用

    设计模式中的每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心.这样,你就能一次又一次地使用该方案而不必做重复劳动. 设计模式在类间关系这个粒度上给出常见问题的解决方案.属于 ...

  4. 策略模式在游戏开发中的应用

    策略模式 在策略模式中,一个类的行为或者其算法可以在运行时更改.这种类型的设计模式属于行为模式.在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象而改变的Contenxt(上下文对象),策 ...

  5. 为什么在游戏开发中我不喜欢用MVC系列模式了

    为什么在游戏开发中我不喜欢用MVC系列模式了: 1,代码繁冗,当你阅读别人的代码,一个很简单的逻辑,被封装了多次,需要在多个代码文件中索引,阅读效率极低.代码文件分散,一些很简单的逻辑,例如按钮点击, ...

  6. 游戏开发中的策略模式

    游戏开发中的策略模式 博主公司今年的新项目是一个重度养成中度策略的塔防游戏(参考国外的random dice),虽然最后项目算是垮了吧(一测的留存实在太低),但是还是需要总结一下代码(总结才会进步). ...

  7. 游戏开发中常用的设计模式 【game design patterns】

    单例模式(Singleton Pattern):用于确保在游戏中只存在一个实例,例如游戏管理器(Game Manager)或资源管理器(Resource Manager). 工厂模式(Factory ...

  8. MANA框架在wap游戏开发中的应用

    Apache MINA框架 用户 IoService>IoProCessor>IoFilter>IoFilter>IoFilter>IoHandler 从左至右Reads ...

  9. 游戏开发中的人工智能(六):基本路径寻找及航点应用

    接上文:游戏开发中的人工智能(五):以势函数实现移动 本文内容:游戏开发人员使用很多技术在游戏环境中寻找路径.本章要谈几种方法,包括航点应用. 基本路径寻找及航点应用 寻找路径的问题有很多不同类型.没 ...

最新文章

  1. linux中js文件有乱码,解决node.js读取文件时中文乱码问题
  2. LR模型常见问题小议
  3. 基于朴素贝叶斯的书籍评价信息分类
  4. 一个不错的游戏 - flash webgame
  5. C#LeetCode刷题之#453-最小移动次数使数组元素相等(Minimum Moves to Equal Array Elements)
  6. Bootstrap 标签导航的布局
  7. linux socket编程web服务器实现报文解析,[Socket][网络编程]程序范例:Linux下连接WEB服务器...
  8. C++socket编程(八):8.2简单的基于UDP的客户端和服务端
  9. css3 rem的用法
  10. Python网络编程笔记二
  11. 机器人潘森护盾_新版潘森无伤抗塔 还能抵消死歌大招?E技能护盾机制全解析...
  12. python实现计算标准偏差函数
  13. 关于srand函数的疑问
  14. 安装Hadoop3.2.1(很多坑)
  15. 新手如何对文件进行简单的上传
  16. android贪食蛇详细教程实现加源码
  17. SQL SERVER 变量赋值
  18. .NFT Framework简介
  19. 煤炭企业内部调拨物资称重问题如何管理(一)
  20. R语言ggplot2可视化:使用patchwork包将多个ggplot2可视化结果组合起来、使用plot_spacer函数在组合结果图像中的指定位置加入空白区域(不包含任何内容,纯粹空白图)

热门文章

  1. 查看centos7系统资源使用情况
  2. 文件捆绑器的原理(转)
  3. Live Stream Technologies
  4. React之 常见的hooks
  5. 线性代数 --- 线性方程组的相容与不相容(个人笔记扫描版)
  6. postgresql 连接超时_解决PostgreSQL 执行超时的情况
  7. 3Dmax和maya模型导入OGRE全解析
  8. 第11节 Kali Linux系统网络信息查看与配置
  9. LINUX平台高级调试和优化(2018上海站)
  10. 数字整除(大数整除)