积累提供所有操作(的实现)来定义子类的行为
用一个最简单的例子来讲解这个模式
玩家操纵的英雄也就是这个游戏的主角会有许多技能,我们想定义许多不同的技能,来让玩家使用。

先我们定义一个skillBase类作为基类,我们所有技能的动作都在这里实现。我们可以从这些基本元动作中组合出各种各样的技能,甚至成百上千种,可以
设计一个doc文档来设计各种技能的操作,及操作顺序。这就是之所以为什么叫子类沙盒的原因,把实现技能的方法作为沙盒,向这个沙盒里加入各种各样的元动
作来组成各种各样的技能。
以传说系列的凤凰天驱为例,如下图(源自世界传说-换装迷宫2),这个技能分为,后移、跳跃、播放动画、前冲、粒子效果、播放动画等等元动作组成的

如果我们不使用子类沙盒模式,而一个一个写技能的话会有如下缺点:
1.    会产生大量重复代码,造成代码冗余,因为每个技能都有重复的地方,比如说播放声音,播放动画等。使用这种模式之后各个操作方法就像一个一个的组件一样,随意使用,不会有重复。
2.

每一个技能类都会与游戏系统和游戏引擎耦合,比如声音、动画播放,而如果把操作实现都写在基类里让子类组合的话就只有基类与之耦合而已。这个原因这种模
式带来的好处是,如果有某个操作增删改的话,就不用每个技能类都增删改一遍,而只改基类就好,方便简单,简约。而且重用性相当好,这些代码能用在大量游戏
上(比如说传说系列每个系列的传承->魔神剑)
在基类skillBase中,我们需要实现一些技能的元动作,比如move移动,jump跳,playAnimation播放动画,playSound播放声音等等,我们把他们组合在一起实现各种技能,这些方法是受保护的。
然后我们需要一个virtual 方法action是最终的技能在子类中定义实现,这就是为什么上面的原方动作是受保护的了,因为我们不需要调用这些元动作,只需要他们组合成的技能action()方法就好,所以只让子类获取元动作方法用protected标记。
于是乎我们做一些受保护的方法,在子类中拼装实现一个组合在一起的整体。
我们要做这些技能类
1.    建立一个继承于基类skillBase的技能类起名为skill1
2.    重写skillBase的action方法
3. 把元动作在action中实现

类(skillBase)中提供了一个抽象的沙盒方法(action)和一些标记为protected的元动作操作(move、jump、
playSound等),这个类派生了一些沙盒子类,每个沙盒子类(skill1、skill2。。。)都实现了沙盒方法(action),沙盒方法包含
着各种元动作(move、jump、playSound等)。
当符合以下条件时可以使用子类沙盒模式
1.    一个基类和大量派生子类
2.    基类可以提供所有派生子类需要的操作
3.    子类之间的操作、方法有重复
4.    想要减少子类和游戏系统、游戏引擎等的耦合

注意:因为此时子类与基类密切相关,所以可能会产生brittle base class问题,也就是你看似安全的修改了基类,但是子类却可能因此发生问题。

代码实现

代码如下:
在skillBase中简单实现几个元动作和抽象的沙盒方法:

   protected void act(int actID)
{
hero.Act(actID);//播放攻击动画
}
protected void playSound(int soundID)
{
audioSource.PlayOneShot(audio[soundID]);
} protected void move(Vector3 dir, float moveSpeed, bool isRun)
{
moveFunc.move(dir, moveSpeed, isRun);
}
protected void jump()
{
moveFunc.jump();
}
protected void particalEffect()
{
。。粒子效果。。
} virtual public void action()//沙盒方法
{ }

再看skill1实现的沙盒方法,比如说我们想实现一个跳斩,就把这些元动作组合在一起

    override public void action()
{
playSound();
act();
jump();
particalEffect();
}

很简单对吧
我们再来看看基类初始化的方法
基类的初始化
方法一:构造函数
通过构造函数传参来赋值,但是这种有参构造函数必须要在每个沙盒子类中base一下,所以如果base类的构造函数这些参数有个增删改,子类也得跟着全部增删改。

    public SkillBase(AudioSource _audioSource, AudioClip[] _audio, Move1 _moveFunc, Hero2 _hero, GameObject _heroObject)
{
this.audio = _audio;
this.audioSource = _audioSource;
this.moveFunc = _moveFunc;
this.hero = _hero;
this.heroObject = _heroObject;
}

方法二:初始化函数init
不过记得要在一开始调用,否则小心游戏崩溃

    public void init(AudioSource _audioSource, AudioClip[] _audio, Move1 _moveFunc, Hero2 _hero, GameObject _heroObject)
{
this.audio = _audio;
this.audioSource = _audioSource;
this.moveFunc = _moveFunc;
this.hero = _hero;
this.heroObject = _heroObject;
}

方法三:静态初始化方法init和类变量(静态变量)

这样所有沙盒子类也就是所有skill都共用一种变量了,有好处也有坏处

   static private AudioSource audioSource;
static private AudioClip[] audio;
static private Move1 moveFunc;
static private Hero2 hero;
static protected GameObject heroObject; static public void init(AudioSource _audioSource, AudioClip[] _audio, Move1 _moveFunc, Hero2 _hero, GameObject _heroObject)
{
audio = _audio;
audioSource = _audioSource;
moveFunc = _moveFunc;
hero = _hero;
heroObject = _heroObject;
}

总结

小模式,大用处。很简单的一个设计模式,却很有用处,成功的减少了沙盒子类与其他类之间的耦合,也增加了重用性,更重要的是这种组合的方式增加了多样性,这正是游戏所需要的。

全部代码已上传至GitHub

博主近期渲染:最近用unity5弄的一些渲染

---- by wolf96 

游戏开发设计模式之子类沙盒模式(unity3d 示例实现)的更多相关文章

  1. 游戏开发设计模式之状态模式 & 有限状态机 & c#委托事件(unity3d 示例实现)

    命令模式:游戏开发设计模式之命令模式(unity3d 示例实现) 对象池模式:游戏开发设计模式之对象池模式(unity3d 示例实现) 原型模式:游戏开发设计模式之原型模式 & unity3d ...

  2. 游戏开发设计模式之原型模式 & unity3d JSON的使用(unity3d 示例实现)

    命令模式:游戏开发设计模式之命令模式(unity3d 示例实现) 对象池模式:游戏开发设计模式之对象池模式(unity3d 示例实现) 实现原型模式 原型模式带来的好处就是,想要构建生成任意独特对象的 ...

  3. 游戏开发设计模式之对象池模式(unity3d 示例实现)

    前篇:游戏开发设计模式之命令模式(unity3d 示例实现) 博主才学尚浅,难免会有错误,尤其是设计模式这种极富禅意且需要大量经验的东西,如果哪里书写错误或有遗漏,还请各位前辈指正. 原理:从一个固定 ...

  4. APNS IOS 消息推送沙盒模式和发布模式

    在做.NET向IOS设备的App进行消息推送时候,采用的是PushSharp开源类库进行消息的推送,而在开发过程中,采用的是测试版本的app,使用的是测试的p12证书采用的是ApnsConfigura ...

  5. 游戏开发设计模式之命令模式(unity3d 示例实现)

    博主才学尚浅,难免会有错误,尤其是设计模式这种极富禅意且需要大量经验的东西,如果哪里书写错误或有遗漏,还请各位前辈指正. 打 算写设计模式的目的就是,首先自己可以理清思路,还有就是国内的设计模式资料很 ...

  6. iOS 开发查看应用的沙盒文件

    在iOS开发中,常常需要将一些信息保存到本地,比如说用户的一些搜索历史等.那么,如何查看所保存的文件呢? 这里介绍两种途径来查看应用的沙盒文件. 方法一:通过Xcode来查看,步骤如下: (1): X ...

  7. JavaScript 沙盒模式

    微前端已经成为前端领域比较火爆的话题,在技术方面,微前端有一个始终绕不过去的话题就是前端沙箱 什么是沙箱 Sandboxie(又叫沙箱.沙盘)即是一个虚拟系统程序,允许你在沙盘环境中运行浏览器或其他程 ...

  8. iOS开发 - 获取真机沙盒数据

    今天要获取之前真机測试时写入沙盒的数据, 本来以为挺麻烦的. 后来捣腾了一下, 才知道原来这么简单... 以下直接看详细步骤. 前提: 真机已经通过USB和你的电脑连接上了! 1.进入Organize ...

  9. 开发设计模式(九)门面模式(Facade Pattern)

    什么是门面模式? 门面模式要求一个子系统的外部与其内部的通信必须通过一个统一的门面(Facade)对象进行.门面模式提供一个高层次的接口,使得子系统更易于使用. 大家都写过纸质的信件吧,比如给女朋友写 ...

随机推荐

  1. [GDI+] C# ImageClass帮助类教程与源码下载 (转载)

    点击下载 ImageClass.rar 功能如下图片 主要功能有:缩略图片,图片水印,文字水印,调整光暗,反色处理,浮雕处理,拉伸处理,左右翻转,上下翻转,压缩图片,图片灰度化,转换为黑白图片,获取图 ...

  2. Andriod ADT v22.6.2版本中在Mainactivity.java中使用fragment_main.xml中TextView控件对象的问题

    众所周知,我们既可以在 activity_main.xml文件中控制activity中的view,也可以使用java代码的set..()方法控制它.在学习过程中,发现在ADT新版本中,和以前版本有区别 ...

  3. VS2010对Excel操作---DLL向

    最近公司有个项目要用到Excel的操作,于是自己就对VC中关于Excel的操作进行整理了下.而这里我是直接做成DLL方便他人调用的. 创建一个MFC Dll项目. 选择MFC扩展DLL. 在“类视图” ...

  4. pom.xml中<dependency>

    当想下载jar包时,需要在pom.xml追加<dependency>即可. 通过如下餐叙: 如下图 http://mvnrepository.com/artifact/cglib/cgli ...

  5. javascript之事件详解2

    1.事件对象: 在触发DOM事件的时候都会产生一个对象. 2.事件对象event: (1).type:获取事件类型 (2).target:获取事件目标 (3).stopPropagation():阻止 ...

  6. Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (111)解决方法

    登陆mysql的时候,出现了这个问题: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' ( ...

  7. HDU 3006 The Number of set(位运算 状态压缩)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3006 题目大意:给定n个集合,每个集合都是由大于等于1小于等于m的数字组成,m最大为14.由给出的集合 ...

  8. jquery ajax 后台响应成功,返回正确json但不执行success方法,执行error的问题

    昨天被这问题卡了好几个小时.查看http状态码:是200.而且返回了预想的json字符串.但执行的是error方法,不执行success方法.在网上查了一下,才发现是后台页面返回的json字符串格式不 ...

  9. 如何更有效学习php开源项目的源码

    一.先把源代码安装起来,结合它的文档和手册,熟悉其功能和它的应用方式. 二.浏览源代码的目录结构,了解各个目录的功能. 三.经过以上两步后相信你对这个开源的产品有了一个初步的了解了,那现在就开始分析它 ...

  10. 注册表和ODBC

         注册表使用的是树型体系结构,树中的每个结点称键.每个键也可以包含其他的键或子键.它允许进一步的分支,也即为值,它用来存储有效的数据.在注册表中,注册表用键来组织数据,一个键中的值用它们的名来 ...