Unity3D控制反转之Get Start StrangeIOC.docx
- 文档编号:5511966
- 上传时间:2022-12-17
- 格式:DOCX
- 页数:8
- 大小:21.62KB
Unity3D控制反转之Get Start StrangeIOC.docx
《Unity3D控制反转之Get Start StrangeIOC.docx》由会员分享,可在线阅读,更多相关《Unity3D控制反转之Get Start StrangeIOC.docx(8页珍藏版)》请在冰豆网上搜索。
Unity3D控制反转之GetStartStrangeIOC
Unity3D控制反转之GetStartStrangeIOC
Strange是一个Unity3D中用于控制反转的第三方框架,控制反转(IOC-InversionofControl)思想是类间解耦的一个重要方法,对于我来说,任何解耦技术都值得去学习。
什么是IOC?
这里有详细解答。
IOC框架已经在企业级开发和其他非游戏软件的开发中成为了主流,并且可以说已经非常成熟。
我觉得它可以帮助游戏开发变得更加容易测试,更好的进行协作开发。
我非常想尝试它看看到底可以在游戏开发过程中起到多大的帮助程度。
Strange使用起来真的像他的名字一样,非常"奇怪"。
我发现它对于初学者来说,使用起来真的非常"闹心",比如你想试着去写一个"HelloWorld"都非常不容易。
这里是StrangeIOC框架的说明页面,但是这上面并没有一个真正意义上的"新手引导"来帮助我们了解Strange的工作机制,这就是你现在看到现在这篇文章的意义-用StrangeIOC框架写一个HelloWorld。
一些提醒:
∙在阅读本篇文章之前,最好先去上面提到的官方说明页面了解一下Strange框架的架构(看看它的每个部分的功能以及怎么整合到一块工作的)。
∙这篇文档使用的是signal(消息)而非event(事件)(因为相比event我更喜欢signal)
∙我不会把文档中的Unity项目提供出来,因为我希望大家自己动手去做,这样肯定会学到更多:
)
∙这个HelloWorld示例只是简单的提供注入绑定(injectionbinding)、命令绑定(commandbinding)、调解绑定(mediationbinding)的示例。
Signal
建立一个空Unity项目,下载并且解压Strange框架到Assets文件夹中,我们只需要框架的脚本,把"examples"和".doc"文件夹去除,在Unity的的结构应该是这样的:
AssetsStrangeIoCscripts
在Assets文件夹下创建"Game"文件夹,即用来创建HelloWorld示例的文件夹。
文件夹的的结构应该是这样的:
AssetsGameScenesScripts
在Scripts文件夹下新建名为HelloWorldSignals.cs的c#脚本,这个类将包含所有用到的signal,让我们coding起来:
usingSystem;usingstrange.extensions.signal.impl;namespaceGame{publicclassStartSignal:
Signal{}}
在Strange中,这个signal的概念非常像观察者模式(observerpattern)中的事件(events)。
在这里,它以命名类的方式实现了继承Strange的Signal类.别急,我们马上会看到怎么去使用它。
Strange采用"Contexts"的概念来识别不同的问题域或者子模块。
在实际的游戏项目中,你可以有多个"Contexts",比如游戏逻辑、资源、持久层、统计分析、社交模块等等。
我们在这个实例中只用了一个"Context"。
一个预构建的context在Strange中称为MVCSContext,MVCSContext默认使用event机制,我们来创建另外一种context父类,改造成使用signal机制,我们其他的context要继承这个SignalContext。
在Scripts下创建名为SignalContext.cs的脚本:
文章出处狗刨学习网
usingSystem;usingUnityEngine;usingstrange.extensions.context.impl;usingmand.api;usingmand.impl;usingstrange.extensions.signal.impl;namespaceGame{publicclassSignalContext:
MVCSContext{/***Constructor*/publicSignalContext(MonoBehaviourcontextView):
base(contextView){}protectedoverridevoidaddCoreComponents(){base.addCoreComponents();//bindsignalcommandbinderinjectionBinder.Unbind
在"Scripts"文件夹下创建一个新文件夹"Controller",到这里有了一点MVC模式的特征。
Strange作者建议我们应该以指令类(CommandClass)的形式实现各个Controller接口,这个文件夹将包含所有的Command类,现在我们创建一个在StartSignal指令调用时执行的指令。
在Controller文件夹下创建名为HelloWorldStartCommand.cs的类:
usingSystem;usingUnityEngine;usingstrange.extensions.context.api;usingmand.impl;namespaceGame{publicclassHelloWorldStartCommand:
Command{publicoverridevoidExecute(){//performallgamestartsetuphereDebug.Log("HelloWorld");}}}
现在我们为这个HelloWorld示例创建一个自定义的context类HelloWorldContext.cs:
usingSystem;usingUnityEngine;usingstrange.extensions.context.impl;namespaceGame{publicclassHelloWorldContext:
SignalContext{/***Constructor*/publicHelloWorldContext(MonoBehaviourcontextView):
base(contextView){}protectedoverridevoidmapBindings(){base.mapBindings();//webindacommandtoStartSignalsinceitisinvokedbySignalContext(theparentclass)onLaunch()commandBinder.Bind
在这里,我们把StartSignal类绑定(bind)给了HelloWorldStartCommand类。
这样在StartSignal的实例被调用时,HelloWorldStartCommand会进行实例化(instantiated)和执行(executed),注意在我们的示例中StartSignal信号会在SignalContext.Launch()方法中调用发出。
最后一步就是创建一个MonoBehaviour来在Unity中管理context,在Scripts文件夹下创建HelloWorldBootstrap.cs:
usingSystem;usingUnityEngine;usingstrange.extensions.context.impl;namespaceGame{publicclassHelloWorldBootstrap:
ContextView{voidAwake(){this.context=newHelloWorldContext(this);}}}
用于在Unity中管理Strangecontext的接口类通常命名为“xxxBootstrap”,当然这只是一个建议,如果你乐意你可以随意起名字。
这里唯一需要注意的是继承Strange框架的ContextView类的类需要是一个MonoBehaviour,我们在Awake()里分配了一个我们自定义好的context实例给继承的变量"context"。
创建一个空场景命名为"HelloStrange",创建一个EmptyObject命名为Bootstrap,把我们之前创建的HelloWorldBootstrap add上来。
可以跑一下这个场景,之前程序正确的话,你应该看到控制台的"HelloWorld"输出了。
InjectioninMediator
到目前为止写这么一大堆东西只是输出一句“HelloWorld”,是不是被Strange搞得头都大了?
其实做到现在这一步已经大致为你梳理出来Strange的一些机制了。
首先我们有了一个能跑的context,从这一步开始,我们就可以添加view和相应的mediator,还可以使用injectionbinder把一个实例映射到一些可注入controllers/commands和mediators的接口中,而这些接口并不需要关心这个实例是怎么来的。
接下来就是见证奇迹的时刻了!
一般我们做游戏编程的时候,会有一堆单例管理器(singletonmanagers)比如EnemyManager、AsteroidManager、CombatManager等等,假如需要同一个实例给任意一个管理器去调用有很多解决方案,比如我们可以使用GameObject.Find()或者为这个类添加一个静态单例(GetInstance()staticmethod),OK,让我们看看有了Strange以后,这样的情形可以怎么去解决:
创建一个名为"ISomeManager"的接口,模拟一个上面说的那种manager,在Scripts文件夹创建ISomeManager.cs脚本
namespaceGame{publicinterfaceISomeManager{/***Performsomemanagement*/voidDoManagement();}}
这就是我们示例当中的manager接口,注意:
Strange的作者建议我们总是使用一个接口然后通过injectionBinder将它映射到一个真正的实现类,当然,你也可以使用多对多的映射。
接下来我们创建一个具体实现类,在Scripts文件夹下创建ManagerAsNormalClass.cs脚本:
usingSystem;usingUnityEngine;namespaceGame{publicclassManagerAsNormalClass:
ISomeManager{publicManagerAsNormalClass(){}#regionISomeManagerimplementationpublicvoidDoManagement(){Debug.Log("Managerimplementedasanormalclass");}#endregion}}
如果你仔细在看你可能会发现这是一个没有MonoBehaviour的manager,别急,一会再介绍怎么bind有MonoBehaviour的
现在我们来创建一个简单的交互场景,效果是当一个Button按下时,ISomeManager的DoManagement函数执行,这里我们有一个要求:
用MVC思想---对controll层(ISomeManager)和view层(控制Button触发事件的脚本)完全解耦,view层只需要通知controll层:
"hey!
button被点击了",至于接下来发生什么交由controll层进行逻辑处理。
现在缺一个view层,把它创建出来吧---在Game文件夹下创建"View"文件夹,创建HelloWorldView.cs脚本:
usingSystem;usingUnityEngine;usingstrange.extensions.mediation.impl;usingstrange.extensions.signal.impl;namespaceGame{publicclassHelloWorldView:
View{publicSignalbuttonClicked=newSignal();privateRectbuttonRect=newRect(0,0,200,50);publicvoidOnGUI(){if(GUI.Button(buttonRect,"Manage")){buttonClicked.Dispatch();}}}}
这里继承的Strange框架中的View类已经包含了MonoBehaviour。
所有使用Strangecontext的View层类都必须继承这个Strange的View类,我们刚刚创建的View类只有一个交互功能:
在点击名为"Manage"的Button后,调用一个genericsignal(通用信号)。
Strange作者建议对每个View创建对应的Mediator。
Mediator是一个薄层,他的作用是让与之对应的View和整个程序进行交互。
mediationbinder的作用是把View映射到它对应的mediator上。
所以接下来为View层创建对应的mediator---在"view"文件夹下创建HelloWorldMediator.cs脚本:
usingSystem;usingUnityEngine;usingstrange.extensions.mediation.impl;namespaceGame{publicclassHelloWorldMediator:
Mediator{[Inject]publicHelloWorldViewview{get;set;}[Inject]publicISomeManagermanager{get;set;}publicoverridevoidOnRegister(){view.buttonClicked.AddListener(delegate(){manager.DoManagement();});}}}
在这段代码里我们可以看到神奇的"Inject"标注(Injectattribute)。
这个"Inject"标注只能和变量搭配使用,当一个变量上面有"Inject"标注时,意味着Strange会把这个变量的一个实例自动注入到它对应映射的context中。
据此从我们上面的代码来分析,在这里我们获取到了"view"和"manager"的实例,并且不用去关心这些个实例是怎么来的。
OnRegister()是一个可以被重写的方法,它用来标记实例注入完成已经可以使用了,它的意义主要是进行初始化,或者说做准备。
在上面的类中,OnRegister方法中为HellowWorldView.buttonClickedsignal添加了一个监听器,这个监听器的逻辑是按下就执行manager.DoManagement方法。
文章出处狗刨学习网
接下来就是最后的工作,我们需要把待绑的类映射到StrangeContext中。
打开我们之前写的HelloWorldContext脚本,在mapBindings()方法中添加代码:
protectedoverridevoidmapBindings(){base.mapBindings();//webindacommandtoStartSignalsinceitisinvokedbySignalContext(theparentclass)duringonLaunch()commandBinder.Bind
在HelloWorldscene中,添加一个名为"View"的GameObject,add HelloWorldView脚本,运行场景,你应该能看到当我们按下"Manage"按钮时,控制台输出"Managerimplementedasanormalclass"。
文章出处狗刨学习网
你会发现Strange自动把HelloWorldMediator脚本挂载到了"View"GameObject上面。
注意我们之前并没有手动把HelloWorldMediator脚本挂载到"View"GameObject上。
MonoBehaviourManager
大部分时候,我们需要类似于上面的manager但是实现类是一个MonoBehaviour,这样我们才能使用例如协程、序列化的Unity特性。
接下来创建实现MonoBehaviour接口的manager实例,看看怎么在Strange中进行bind。
创建一个实现MonoBehaviour接口的manager,在Script文件夹下,命名为ManagerAsMonobehaviour.cs
usingSystem;usingUnityEngine;namespaceGame{publicclassManagerAsMonoBehaviour:
MonoBehaviour,ISomeManager{#regionISomeManagerimplementationpublicvoidDoManagement(){Debug.Log("ManagerimplementedasMonoBehaviour");}#endregion}}
在HelloStrangeScene中,创建一个新的GameObject名为"Manager",add上面创建好的ManagerAsMonobehaviour脚本
编辑HelloWorldContext脚本的mapBindings()方法:
protectedoverridevoidmapBindings(){base.mapBindings();//webindacommandtoStartSignalsinceitisinvokedbySignalContext(theparentclass)duringonLaunch()commandBinder.Bind
!
!
//injectionBinder.Bind
与把ISomeManager映射为一个类型相反,我们把这个ManagerAsMonobehaviour映射为一个实例值(instancevalue)。
InjectioninCommand
到目前为止我们为HelloWorldMediator注入了一个ISomeManager的一个实例,并且可以直接使用它。
这样做其实并不是很理想,一个Mediator应该是在view层和controller层之间的一个薄层。
我们需要尽量使Mediator层不去关心应该在Manager类去做的那部分复杂的逻辑处理代码。
虽然这么做也可以,我们还是用signal把这部分映射到command层吧。
编辑HelloWorldSignals.cs脚本,添加一个DoManagementSignal:
usingSystem;usingstrange.extensions.signal.impl;namespaceGame{publicclassStartSignal:
Signal{}publicclassDoManagementSignal:
Signal{}//Anewsignal!
}
我们创建command映射到signal:
在Controller文件夹下创建一个脚本DoManagementCommand.cs
usingSystem;usingUnityEngine;usingstrange.extensions.context.api;usingmand.impl;namespaceGame{publicclassDoManagementCommand:
Command{[Inject]publicISomeManagermanager{get;set;}publicoverridevoidExecute(){manager.DoManagement();}}}
在这个类,我们把ISome
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Unity3D控制反转之Get Start StrangeIOC Unity3D 控制 反转 Get