Unity3D控制反转之Get Start StrangeIOCWord文档格式.docx
- 文档编号:8434803
- 上传时间:2023-05-11
- 格式:DOCX
- 页数:8
- 大小:21.62KB
Unity3D控制反转之Get Start StrangeIOCWord文档格式.docx
《Unity3D控制反转之Get Start StrangeIOCWord文档格式.docx》由会员分享,可在线阅读,更多相关《Unity3D控制反转之Get Start StrangeIOCWord文档格式.docx(8页珍藏版)》请在冰点文库上搜索。
∙在阅读本篇文章之前,最好先去上面提到的官方说明页面了解一下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"
的概念来识别不同的问题域或者子模块。
在实际的游戏项目中,你可以有多个"
,比如游戏逻辑、资源、持久层、统计分析、社交模块等等。
我们在这个实例中只用了一个"
Context"
一个预构建的context在Strange中称为MVCSContext,MVCSContext默认使用event机制,我们来创建另外一种context父类,改造成使用signal机制,我们其他的context要继承这个SignalContext。
在Scripts下创建名为SignalContext.cs的脚本:
文章出处狗刨学习网
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<
ICommandBinder>
();
injectionBinder.Bind<
().To<
SignalCommandBinder>
().ToSingleton();
}publicoverridevoidLaunch(){base.Launch();
SignalstartSignal=injectionBinder.GetInstance<
StartSignal>
startSignal.Dispatch();
}}}
在"
Scripts"
文件夹下创建一个新文件夹"
Controller"
,到这里有了一点MVC模式的特征。
Strange作者建议我们应该以指令类(CommandClass)的形式实现各个Controller接口,这个文件夹将包含所有的Command类,现在我们创建一个在StartSignal指令调用时执行的指令。
在Controller文件夹下创建名为HelloWorldStartCommand.cs的类:
usingstrange.extensions.context.api;
namespaceGame{publicclassHelloWorldStartCommand:
Command{publicoverridevoidExecute(){//performallgamestartsetuphereDebug.Log("
);
现在我们为这个HelloWorld示例创建一个自定义的context类HelloWorldContext.cs:
namespaceGame{publicclassHelloWorldContext:
SignalContext{/***Constructor*/publicHelloWorldContext(MonoBehaviourcontextView):
base(contextView){}protectedoverridevoidmapBindings(){base.mapBindings();
//webindacommandtoStartSignalsinceitisinvokedbySignalContext(theparentclass)onLaunch()commandBinder.Bind<
HelloWorldStartCommand>
().Once();
在这里,我们把StartSignal类绑定(bind)给了HelloWorldStartCommand类。
这样在StartSignal的实例被调用时,HelloWorldStartCommand会进行实例化(instantiated)和执行(executed),注意在我们的示例中StartSignal信号会在SignalContext.Launch()方法中调用发出。
最后一步就是创建一个MonoBehaviour来在Unity中管理context,在Scripts文件夹下创建HelloWorldBootstrap.cs:
namespaceGame{publicclassHelloWorldBootstrap:
ContextView{voidAwake(){this.context=newHelloWorldContext(this);
用于在Unity中管理Strangecontext的接口类通常命名为“xxxBootstrap”,当然这只是一个建议,如果你乐意你可以随意起名字。
这里唯一需要注意的是继承Strange框架的ContextView类的类需要是一个MonoBehaviour,我们在Awake()里分配了一个我们自定义好的context实例给继承的变量"
context"
创建一个空场景命名为"
HelloStrange"
,创建一个EmptyObject命名为Bootstrap,把我们之前创建的HelloWorldBootstrap
add上来。
可以跑一下这个场景,之前程序正确的话,你应该看到控制台的"
输出了。
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脚本:
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脚本:
usingstrange.extensions.mediation.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类只有一个交互功能:
在点击名为"
的Button后,调用一个genericsignal(通用信号)。
Strange作者建议对每个View创建对应的Mediator。
Mediator是一个薄层,他的作用是让与之对应的View和整个程序进行交互。
mediationbinder的作用是把View映射到它对应的mediator上。
所以接下来为View层创建对应的mediator---在"
view"
文件夹下创建HelloWorldMediator.cs脚本:
namespaceGame{publicclassHelloWorldMediator:
Mediator{[Inject]publicHelloWorldViewview{get;
set;
}[Inject]publicISomeManagermanager{get;
}publicoverridevoidOnRegister(){view.buttonClicked.AddListener(delegate(){manager.DoManagement();
});
在这段代码里我们可以看到神奇的"
Inject"
标注(Injectattribute)。
这个"
标注只能和变量搭配使用,当一个变量上面有"
标注时,意味着Strange会把这个变量的一个实例自动注入到它对应映射的context中。
据此从我们上面的代码来分析,在这里我们获取到了"
manager"
的实例,并且不用去关心这些个实例是怎么来的。
OnRegister()是一个可以被重写的方法,它用来标记实例注入完成已经可以使用了,它的意义主要是进行初始化,或者说做准备。
在上面的类中,OnRegister方法中为HellowWorldView.buttonClickedsignal添加了一个监听器,这个监听器的逻辑是按下就执行manager.DoManagement方法。
接下来就是最后的工作,我们需要把待绑的类映射到StrangeContext中。
打开我们之前写的HelloWorldContext脚本,在mapBindings()方法中添加代码:
protectedoverridevoidmapBindings(){base.mapBindings();
//webindacommandtoStartSignalsinceitisinvokedbySignalContext(theparentclass)duringonLaunch()commandBinder.Bind<
//bindourviewtoitsmediatormediationBinder.Bind<
HelloWorldView>
HelloWorldMediator>
//bindourinterfacetoaconcreteimplementationinjectionBinder.Bind<
ISomeManager>
ManagerAsNormalClass>
}
在HelloWorldscene中,添加一个名为"
的GameObject,add
HelloWorldView脚本,运行场景,你应该能看到当我们按下"
按钮时,控制台输出"
你会发现Strange自动把HelloWorldMediator脚本挂载到了"
GameObject上面。
注意我们之前并没有手动把HelloWorldMediator脚本挂载到"
GameObject上。
MonoBehaviourManager
大部分时候,我们需要类似于上面的manager但是实现类是一个MonoBehaviour,这样我们才能使用例如协程、序列化的Unity特性。
接下来创建实现MonoBehaviour接口的manager实例,看看怎么在Strange中进行bind。
创建一个实现MonoBehaviour接口的manager,在Script文件夹下,命名为ManagerAsMonobehaviour.cs
namespaceGame{publicclassManagerAsMonoBehaviour:
MonoBehaviour,ISomeManager{#regionISomeManagerimplementationpublicvoidDoManagement(){Debug.Log("
ManagerimplementedasMonoBehaviour"
在HelloStrangeScene中,创建一个新的GameObject名为"
Manager"
,add上面创建好的ManagerAsMonobehaviour脚本
编辑HelloWorldContext脚本的mapBindings()方法:
//REMOVED!
!
//injectionBinder.Bind<
//bindthemanagerimplementedasaMonoBehaviourManagerAsMonoBehaviourmanager=GameObject.Find("
).GetComponent<
ManagerAsMonoBehaviour>
().ToValue(manager);
与把ISomeManager映射为一个类型相反,我们把这个ManagerAsMonobehaviour映射为一个实例值(instancevalue)。
InjectioninCommand
到目前为止我们为HelloWorldMediator注入了一个ISomeManager的一个实例,并且可以直接使用它。
这样做其实并不是很理想,一个Mediator应该是在view层和controller层之间的一个薄层。
我们需要尽量使Mediator层不去关心应该在Manager类去做的那部分复杂的逻辑处理代码。
虽然这么做也可以,我们还是用signal把这部分映射到command层吧。
编辑HelloWorldSignals.cs脚本,添加一个DoManagementSignal:
Signal{}publicclassDoManagementSignal:
Signal{}//Anewsignal!
}
我们创建command映射到signal:
在Controller文件夹下创建一个脚本DoManagementCommand.cs
namespaceGame{publicclassDoManagementCommand:
Command{[Inject]publicISomeManagermanager{get;
}publicoverridevoidExecute(){manager.DoManagement();
在这个类,我们把ISome
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Unity3D控制反转之Get Start StrangeIOC Unity3D 控制 反转 Get