状态模式
当我在电脑前做我的独立游戏的时候,忽然嗅到让人放松的香味,又温柔又甜,不用想,她又想偷偷的在后面捂住我的眼睛,然后傻傻的问我她是谁. 果不其然,她捂住了我的眼睛,然后在我的耳边说:"猜猜我是谁呀" 我笑了笑,"哈哈,你是谁呀" 她也不回答,从我的手臂下钻过来,坐在我的腿上.开始自顾自的玩弄自己的头发.
一会儿她转头问我:"你在写什么呢?"
我说:"我在写一个状态机."
她又问:"什么是状态机呀?"
我说:"状态机也就是切换状态的机器,属于状态模式,在游戏开发中十分常见,"状态"在游戏中许多环节都有,比如游戏中的AI,它就会有攻击状态,巡逻状态,等等."
她又问:"那是怎么从攻击到巡逻呢?" 我回答:"通过外部环境的影响然后自身内部完成状态的切换.举个例子:假如我现在设计一个游戏,游戏的主人公有个特殊的属性,就是每当月圆之夜,他一遇到月光,他就会变成一个狼人,他的攻击模式就会变成"利爪攻击","超远弹跳","血量加厚"等技能或属性 ,但是如果月光消息就会变回自身的人类状态.那他的攻击就有"利剑攻击","手枪攻击","长矛攻击",血量也比较少,那么这个时候这种就基本是一个状态模式了."
"哦.",她似乎听懂了,她继续说:"就是外部环境影响,然后切换成被影响的状态,对吧."
"对,这个切换一般是在内部切换,换句话说就是这个人变成狼人是从他内部变化的,他受到了月光的影响,自己从内部从人变成了狼人."
"那你一般怎么写呀?"她问.
"在代码中写的话就是首先要有一个"外部环境"的一个类,这个类就是用来影响这个状态的,我们可以这么写:
public class Context { }
"
"这样写就是一个类了嘛?"
"对,类的关键字"class,接着还要再写一个抽象类 State"
public abstract class State { }
"
"什么叫抽象类啊?"她迫不及待的问我.
我说抽象类就是专门给子类继承用的,抽象类里面必须要有抽象方法,而且里面只能有抽象方法,这个抽象方法只有签名没有方法体.
"啊?什么是签名,什么是方法体呀?"
我看了看她,眼睛里都是迷惑,此时她的表情真的很美,真的很想亲一口,但是我必须要把这些给她讲明白,我咽了一口口水,继续和她说道:"方法的签名就是方法的名字,方法体就是这个函数的实体,换句话说就是{}里面的东西,叫方法体,那么这个抽象方法就是
public abstract class State { public abstract void Handle(int value); }
"
"这样的就是子类必须实现这个Handle的虚方法是吗?"
"是的"我接着说但是,光有状态的行为还不行,这个行为就是Handle方法,状态也需要知道"环境"的具体情况,才好根据环境来切换状态".
"啊,为什么不是自动的呢?当环境变化的时候,State自动的知道啊"
我说,因为在计算机世界中还是和我们现实世界中有区别的,因为计算机是没有"眼睛"的,我们可以看到,但是在计算机的世界中,我们是没有办法看到某个状态的改变的,只有通过拿到某个类或者方法的引用,才能知道这个类或者方法的状态.
"啊,那,引用又是什么啊?"
她有些气馁甚至想跳下去,我双臂收小一点,防止她真的跑了.我继续说道:"引用就相当于这个类或者这个方法的分身,这个分身和原先的本体是一样的,引用能感知到本体的一切变化,可以理解成代言人"
"哦哦"
"嗯,那么我们再将环境和状态类补全"
public class Context { State m_state = null; public void SetState(State state) { Debug.Log("Context.Setstate :" + state); m_state = state; } public void Request(int value) { m_state.Handle(value); } } public abstract class State { protected Context context = null; public State(Context context) { this.context = context; } public abstract void Handle(int value); }
然后我们再写状态的具体实现:
//具体状态A public class ConcreteStateA : State { public ConcreteStateA(Context context) : base(context) { } public override void Handle(int value) { Debug.Log("ConcreteStateA .Handle"); if (value == ) { context.SetState(new ConcreteStateB(context)); } } } //具体状态B public class ConcreteStateB : State { public ConcreteStateB(Context context) : base(context) { } public override void Handle(int value) { Debug.Log("ConcreteStateB .Handle"); if (value == ) { context.SetState(new ConcreteStateC(context)); } } } //具体状态C public class ConcreteStateC : State { public ConcreteStateC(Context context) : base(context) { } public override void Handle(int value) { Debug.Log("ConcreteStateC .Handle"); if (value == ) { context.SetState(new ConcreteStateA(context)); } }
"那个base是干嘛的呀"
我一猜她就会问这个,我说:"这个base就是代表父类.括号里面的值就是代表这个子类用的就是就是父类中的值.简单点来说就是在派生类中调用基类构造函数."
3个子类实现了state父类中的抽象方法.
那么这个时候他的Handle,里面也实现了状态转换的功能.如果我们在unity中来测试一下的话我们只需新建一个脚本实例一下context然后再通过context中的setstate方法设置状态就可以了.
void Start () { Context context = new Context(); context.SetState(new ConcreteStateA(context)); context.Request(); context.Request(); context.Request(); }
你看,运行之后就是这样的.
她看了看,说:"emmm,一点儿也不好玩".
说着就跳了下去,顺便问了问我今天想吃什么.我看着她笑着说:"你煮什么我吃什么".
…END…
前提条件 请您在购买前确保已完成注册和充值。详细操作请参见 如何注册公有云管...
【51CTO.com快译】 数据可视化工具不断发展,提供更强大的功能,同时改善可访问...
建站 什么 虚拟主机 够用?这要看搭建的是什么类型的网站。比如个人博客类型的网...
信息化2.0时代提出开展智慧教育创新发展行动。2019年2月,中共中央、国务院印发...
Docker生成新镜像版本的两种方式 There are two ways Docker can generate new m...
从 10.0.0 版开始,异步迭代器就出现在 Node 中了,在本文中,我们将讨论异步迭...
在Python语言中有如下3种方法: 成员方法 类方法(classmethod) 静态方法(staticm...
摘要 元旦期间 订单业务线 告知 推送系统 无法正常收发消息,作为推送系统维护者...
本文整理自直播《Hologres 数据导入/导出实践-王华峰(继儒)》 视频链接: https:/...
2021年3月24日,主题为《数据的世界,世界的数据》的星环科技2021春季新品发布会...