Asset Store 搜 StrangeIoc 下载 导入api
新建一个Unity3D工程,3D的,用StrangeIoc框架去实现咱们最原始的打砖块!服务器
Project文件:框架
Scripts-> Framework存的全是咱们框架相关的C#脚本文件ide
01-StrangeIoc是StrangeIoc场景下的普通C#脚本即与框架无关,或关系不大this
StrangeIocContextView对应着spa
StrangeIocMVCSContextView对应着3d
代码以下:code
StrangeIocContextView
orm
using strange.extensions.context.impl; using System.Collections; using System.Collections.Generic; using UnityEngine; public class StrangeIocContextView : ContextView { /// <summary> /// ContextView绑定MVCSContext /// </summary> private void Awake() { this.context = new StrangeIocMVCSContextView(this); } }StrangeIocMVCSContextView
using strange.extensions.context.api; using strange.extensions.context.impl; using System.Collections; using System.Collections.Generic; using UnityEngine; public class StrangeIocMVCSContextView : MVCSContext { /// <summary> /// 构造MVCSContext须要ContextView /// </summary> /// <param name="view"></param> public StrangeIocMVCSContextView(MonoBehaviour view):base(view) { } /// <summary> /// 初始化捆绑关系(类与类,接口与类,消息(enum)与类之间) /// </summary> protected override void mapBindings() { //inject injectionBinder.Bind<ILocalDataService>().To<LocalDataService>().ToSingleton(); injectionBinder.Bind<GameModel>().To<GameModel>().ToSingleton(); //command commandBinder.Bind(CommandEvent.RequestScore).To<RequestScoreCommand>();//这样就能够用全局发送器的Dispatch方法发送RequestScore消息,去到RequestScoreCommand处理了 commandBinder.Bind(CommandEvent.HitCube).To<HitCubeCommand>(); //START消息是启动StrangeIoc框架时发送的,这样会触发StartCommand中的Execute方法 commandBinder.Bind(ContextEvent.START).To<StartCommand>().Once(); //mediator mediationBinder.Bind<PlayerView>().To<PlayerMediator>();//这样Mediator便可直接使用Inject注入方式获取到View } }
先不用管方法中的具体内容究竟是什么意思,看方法前面的注释去好好地理解一下,咱们这样就实现了对象
将StrangeIocContextView挂载到一个空物体身上,空物体随你命名。(必定要作这一步!)
这样,咱们每次启动游戏的时候就由StrangeIocContextView启动了StrangeIoc框架,能够发现咱们就只是在Awake写了一条代码而已,即这条代码
this.context = new StrangeIocMVCSContextView(this);
意思是将ContextView与MVCSContextView捆绑,同时也实例化MVCSContextView.整个框架主要仍是靠MVCSContextView来管理的。ContextView只是启动框架的。
存游戏数据的普通脚本:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class GameModel { public int Score { get; set; }//咱们须要一个分数来显示集中球体后的得分,假设击中就有一分 }
PlayerView是一个视图类,继承于框架提供的View,挂载于主摄像机Main Camera身上,做用是射球,与PlayerMediator交互更新分数。(View继承于Monobehaviour,因此它能够挂载到游戏物体身上)
PlayerMediator是一个Mediator类,继承于框架提供的Mediator,它不能挂载到游戏物体上,它充当PlayerView的“传话人”
MediatorMessage是一个枚举类,保存了Mediator消息类型。(其实这个我不发代码,大家也能懂,就是个枚举类嘛)
下面的很难一口气讲解完,须要配合其余的框架脚本解释,不过,只要你跟着思路走就没什么难度。
代码以下:
PlayerView
using strange.extensions.dispatcher.eventdispatcher.api; using strange.extensions.mediation.impl; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class PlayerView : View { //局部发送器:PlayerView利用它与PlayerMediator交互,在下面的HitCube方法中使用到,传话给Mediator,执行Mediator的HitCub方法 具体流程下面说 [Inject] //Inject注入,框架特性之一,使用了该特性的属性,都是框架自动赋值的,目前,我所知的只有发送器是不须要捆绑关系的,也就是内置捆绑好了。 public IEventDispatcher dispatcher { get; set; }//注意必定要是属性,才能用[Inject]注入的方法给它赋值 public GameObject bullet; public float speed; public Text scoreText;//直接外部拖拽赋值 protected override void Start() { base.Start(); } //功能:点击鼠标左击时,射线检测到Cube方块,实例化子弹,给子弹一个冲击力Impulse,方向是dir(这个你们都懂吧,A-B 就是B指向A的向量) private void Update() { if (Input.GetMouseButtonDown(0)) { Ray ray; ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if(Physics.Raycast(ray,out hit)) { if(hit.collider.tag=="Cube") { GameObject bulletGo = Instantiate(bullet, transform.position, Quaternion.identity); bulletGo.GetComponent<Bullet>().cameraGo = this.gameObject; Vector3 dir = hit.transform.position - transform.position;//获取从摄像机指向射线撞击点的方向,下面还要对dir作一步标准化normalized bulletGo.GetComponent<Rigidbody>().AddForce(dir.normalized * speed, ForceMode.Impulse);//Impulse是冲击力 } } } } public void UpdateScoreText(int score)//更新分数 { scoreText.text = score.ToString(); } public void HitCube()//子弹撞到Cube后 子弹会调用该方法 { //发送 撞击到方块 事件 dispatcher.Dispatch(MediatorMessage.CallPlayerMediator_HitCube); //Debug.Log("PlayerViewHitCube"); } }
PlayerMediator
using strange.extensions.context.api; using strange.extensions.dispatcher.eventdispatcher.api; using strange.extensions.mediation.impl; using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerMediator : Mediator { //建立一个全局Dispatcher发送器 [Inject(ContextKeys.CONTEXT_DISPATCHER)] public IEventDispatcher Dispatcher { get; set; } [Inject] public PlayerView PlayerView { get; set; } //咱们是用注入的方法获得PlayerView的,注意咱们在StrangeIocMVCSContextView对PlayerView与PlayerMediator作了捆绑才有这个效果 public override void PreRegister() { //Debug.Log("PlayerMediator捆绑以前"); } public override void OnRegister() { //Debug.Log("PlayerMediator捆绑以后");//这个方法是StrangeIocMVCSContextView里的mapBindings的mediationBinder.Bind<PlayerView>().To<PlayerMediator>();执行后会马上执行 Dispatcher.AddListener(MediatorMessage.CallPlayerMediator_UpdateScore, UpdateScore);//全局发送器注册一个消息事件,消息是第一个参数,事件是第二个参数(局部发送器同样道理),这里就是让其余类可以直接调用UpdateScore方法。 PlayerView.dispatcher.AddListener(MediatorMessage.CallPlayerMediator_HitCube,HitCube);//给PlayerView的局部发送器添加一个监听,消息是第一个参数,事件是第二个参数,这样PlayerView就可以发送这个消息,去调用PlayerMediator的HitCube方法了,是否是颇有意思!彻底隔离全靠消息。 //发送 AddScore事件 Dispatcher.Dispatch(CommandEvent.RequestScore);//用全局发送器的Dispatch方法发送一个消息,事件是什么呢?好!让咱们回到StrangeIocContextView类的mapBindings方法是否是有个捆绑是关于RequestScore消息捆绑的,它对应事件是RequestScoreCommand } public override void OnRemove() { //Debug.Log("PlayerMediator移除以前"); Dispatcher.RemoveListener(MediatorMessage.CallPlayerMediator_UpdateScore, UpdateScore); //销毁了当前Mediator,咱们也应该把全局发送器的相关监听给销毁。 } private void UpdateScore(IEvent ie) { PlayerView.UpdateScoreText((int)ie.data); } public void HitCube() { //发送 碰撞方块事件 Dispatcher.Dispatch(CommandEvent.HitCube); //Debug.Log("PlayerMediatorHitCube"); } }
4.Command文件夹的框架脚本:
RequestScoreCommand
using strange.extensions.command.impl; using strange.extensions.dispatcher.eventdispatcher.api; using System.Collections; using System.Collections.Generic; using UnityEngine; //继承于EventCommand 是可以用它里面定义的一个全局发送器,全局发送器是全局惟一的。 public class RequestScoreCommand : EventCommand { [Inject] public GameModel gameModel { get; set; }//注入方式,咱们捆绑了这个GameModel,因此咱们会自动地用这个GameModel来注入给这个gameModel对象,并且是全局惟一的。 [Inject] public ILocalDataService localDataService { get; set; }//注入,同上,在捆绑处的To<LocalDataService>() 会注入Bind<ILocalDataService>()里面。好好地理解我这一句话,To注入到Bind //用全局发送器发送它捆绑的消息后会调用该方法 public override void Execute() { Retain();//保持该Command的存在,只要没有Release(),那么就不会销毁该Command localDataService.dispatcher.AddListener(CommandMessage.CallRequestScoreCommand, OnCompleteRequestScore);//localDataService的局部发送器注册监听 //从本地服务器获取分数请求 localDataService.RequestScore(); } //从本地服务器获取到了分数以后的操做 private void OnCompleteRequestScore(IEvent ie) { localDataService.dispatcher.RemoveListener(CommandMessage.CallRequestScoreCommand, OnCompleteRequestScore); int score = (int)ie.data; gameModel.Score = score; dispatcher.Dispatch(MediatorMessage.CallPlayerMediator_UpdateScore, score); Release(); } }
ILocalDataService:
using strange.extensions.dispatcher.eventdispatcher.api; using System.Collections; using System.Collections.Generic; using UnityEngine; public interface ILocalDataService { void RequestScore(); void OnRequestScore(int score); void UpdateScore(int score); IEventDispatcher dispatcher { get; set; } }
LocalDataService:
using System.Collections; using System.Collections.Generic; using strange.extensions.dispatcher.eventdispatcher.api; using UnityEngine; using System.IO; public class LocalDataService : ILocalDataService { [Inject] public GameModel gameModel { get; set; } //局部发送器,用于返回Command [Inject] public IEventDispatcher dispatcher { get; set; } //请求本地文本分数 public void RequestScore() { int score = 0; string path = Application.dataPath + "/Resources/" + GameStatic.PlayerData + ".txt"; //从本地加载分数 if (File.Exists(path)) { string str = Resources.Load<TextAsset>(GameStatic.PlayerData).text; if (string.IsNullOrEmpty(str)==false) { score = int.Parse(str); } } else { Debug.LogWarning("本地保存文件不存在,正在帮您生成中"); File.WriteAllText(path, "0"); score = 0; } //拿到分数以后要作的事情 OnRequestScore(score); } public void OnRequestScore(int score) { //发送回去RequestScoreCommand,把分数做为参数发送回去 dispatcher.Dispatch(CommandMessage.CallRequestScoreCommand, score); } /// <summary> /// 更新本地文本分数 /// </summary> public void UpdateScore(int score) { string path = Application.dataPath + "/Resources/" + GameStatic.PlayerData + ".txt"; File.WriteAllText(path, score.ToString()); } }
上面的一大坨代码,用框架流程图来解释一下,咱们到底干了什么事情!
还有一个没画出来,更新GameModel的Score,你能理解上面的,基本上,就OK了。服务器我随便弄了个脚原本作的,终结!