strangeioc test learn

来源:互联网 发布:电视直播点播软件 编辑:程序博客网 时间:2024/06/09 23:52

strangeioc test learn

文中所有步骤根据StrangeIoc框架示意图来的,这个图得下载地址:http://pan.baidu.com/s/1hs3bOAo

我们首先要创建root,作为启动框架的脚本,资料里面说这个类还做了初始化,到底是什么初始化,暂时也还不了解,先创建出来再修改。

/// <summary>/// 图解上面的ROOT创建完成,用作启动框架/// </summary>public class Demo1ContextView : ContextView {    void Awake()    {        this.context=new Demo1Context(this);    }}

挂载在层次面板中的空物体身上:


按照图解第二步应该是创建MVCSContext,这个脚本做了为框架做了哪些职责?用来做模块绑定映射的,映射是StrangeIoc框架一个核心点

/// <summary>/// 框架中的MVCS Context创建完成,用来做 进行绑定映射/// </summary>public class Demo1Context : MVCSContext {    public Demo1Context(MonoBehaviour view) : base(view)    {            }    //进行绑定映射    protected override void mapBindings()    {        //绑定映射分为四类绑定        //model        injectionBinder.Bind<ScoreModel>().To<ScoreModel>().ToSingleton();//数据模型绑定        //server        injectionBinder.Bind<IScoreService>().To<ScoreService>().ToSingleton();//指定执行IScoreService绑定ScoreService        //command        commandBinder.Bind(Demo1CommandEvent.REQUEST_SCORE).To<RequestScoreCommand>();        commandBinder.Bind(Demo1CommandEvent.UPDATE_SCORE).To<UpdateScoreCommand>();        //mediator         mediationBinder.Bind<CubeView>().To<CubeMediator>();//完成view和mediator的绑定        //既然我们已经创建了一个开始命令*(StartCommand),这个命名        //是要立即调用的,接下来做命令绑定        commandBinder.Bind(ContextEvent.START).To<StartCommand>().Once();         //once 表示只会触发一次    }}
因为StartCommand是要首先立即调用的,前面的model,server,command,mediator绑定之后不是立即调用,model,server..都是后续完善的。

/// <summary>/// 这是我们的开始命名,需要继承控制器  做一些初始化操作/// </summary>public class StartCommand : Command{    /// <summary>    /// 当这个命名被执行的时候,会默认调用Excute方法    /// </summary>    public override void Execute()    {        Debug.LogError("Start StrangeIoc FrameWork...");    }}

点击运行游戏,测试效果图:


创建分数模型,和Iscoreservice接口

/// <summary>/// 数据模型 承载数据就行,并不需要继承/// </summary>public class ScoreModel{    public int Score { get; set; }}

/// <summary>/// 创建service接口/// </summary>public interface IScoreService  {    //模拟连接服务器请求分数    void RequestScore(string url);    //模拟收到分数    void OnReceiveScore();    //模拟更新分数    void UpdateScore(string url, int score);    IEventDispatcher dispatcher { get; set; }}

接下来在service中创建Scoreservice用来实现接口

public class ScoreService : IScoreService {    public void RequestScore(string url)    {        Debug.LogError("Request score from url:" + url);        OnReceiveScore();    }    public void OnReceiveScore()    {        //模拟服务器接收到的数据        int score = Random.Range(1, 100);        //开始派送事件(通知事件)        dispatcher.Dispatch(Demo1ServiceEvent.REQUEST_SCORE,score);    }    public void UpdateScore(string url, int score)    {        Debug.LogError("Update score to url" + url + "new score" + score);//给服务器更新分数    }    /*        注入    */    [Inject]    public IEventDispatcher dispatcher { get; set; }}

第二部分 视图层 view 和mediator

public class CubeView : View{    private float mCountTimer = 0f;    public Text mText;    [Inject]    public IEventDispatcher dispatcher { get; set; } //局部的派送器    /// <summary>    /// 初始化函数(由对应的mediator来调用,如CubeMediator)    /// </summary>    public void Init()    {            }    /// <summary>    /// 游戏体自身控制逻辑    /// </summary>    void Update()    {        mCountTimer += Time.deltaTime;        if (mCountTimer > 0.5f)        {            this.transform.position = (new Vector3(Random.Range(-11, 10), Random.Range(-2, 5), 0));            mCountTimer = 0f;        }    }    /// <summary>    /// 玩家交互    /// </summary>    void OnMouseDown()    {        print("click this gameobject.");        //in...        //玩家点击之后开始要涨分数,所以从这里开始调用框架        // 其实内部逻辑是一个事件管理器的注册与通知,同时事件id为枚举类型        dispatcher.Dispatch(Demo1MediatorEvent.CLICKDOWN);    }    /// <summary>    /// 提供给外界用来更新UI分数的方法(由对应的mediator来调用,如CubeMediator)    /// </summary>    /// <param name="score"></param>    public void UpdateScore(int score)    {        mText.text = score.ToString();    }}


view层和外界的交互是通过mediator,一个view对应一个mediator

/// <summary>/// 每个模块(view)对应一个自身的mediator/// </summary>public class CubeMediator : Mediator{    /*    注入:是为了方便访问数据,比如注入view,model.....    */    [Inject] //依赖注入    //将对应的view注入进来,这个脚本会自动添加到view模块上面    //见下面图示    public CubeView cubeView { get; set; }     [Inject]    public ScoreModel scoreModel { get; set; }    [Inject(ContextKeys.CONTEXT_DISPATCHER)]//全局dispatch //一定要添加任何地方都可以这么访问到全局派发器    public IEventDispatcher dispatcher { get; set; }    /// <summary>    /// 注册,模块激活时调用,当挂载到对应模块上面时候    /// </summary>    public override void OnRegister()    {        cubeView.Init();        dispatcher.AddListener(Demo1MediatorEvent.SCORECHANGE, OnScoreChange);        cubeView.dispatcher.AddListener(Demo1MediatorEvent.CLICKDOWN, OnClickDown);        //通过dispatcher发起请求分数的命令        dispatcher.Dispatch(Demo1CommandEvent.REQUEST_SCORE);    }    /// <summary>    /// 解注册 模块销毁时候调用,解注册所有之前添加的事件    /// </summary>    public override void OnRemove()    {        dispatcher.RemoveListener(Demo1MediatorEvent.SCORECHANGE, OnScoreChange);        cubeView.dispatcher.RemoveListener(Demo1MediatorEvent.CLICKDOWN, OnClickDown);    }    /// <summary>    /// CubeMediator向CubeView回传数据的CallBack    /// </summary>    /// <param name="varEvt">回传的服务器数据</param>    public void OnScoreChange(IEvent varEvt)    {        //int varData = (int) varEvt.data;//解包数据        //scoreModel.Score = (int) varEvt.data; 这里也可与注入数据模型        //取数据模型当中数据        cubeView.UpdateScore(scoreModel.Score);        // cubeView.UpdateScore(varData);    }    /// <summary>    /// 加分函数    /// </summary>    public void OnClickDown()    {        dispatcher.Dispatch(Demo1CommandEvent.UPDATE_SCORE);    }}


第三部分 创建Command命令,模块之间的通信通过dispatch来进行...在mediator里面访问dispatch,这样就降低了模块的耦合性。在此之前我们先定义好事件id类型

/// <summary>/// 命令类型/// </summary>public enum Demo1CommandEvent{    REQUEST_SCORE,    UPDATE_SCORE,}

/// <summary>/// 分数模块的事件类型/// </summary>public enum Demo1MediatorEvent{    SCORECHANGE,//1    CLICKDOWN,}

/// <summary>/// 服务器事件类型/// </summary>public enum Demo1ServiceEvent{    REQUEST_SCORE,}

看看是如何进行绑定的,没有绑定模块之间的通信就构建不起来。

/// <summary>/// Command要和事件id绑定起来,在context里面进行绑定/// </summary>public class RequestScoreCommand : EventCommand {    //please check context binding......    /*       //绑定映射分为四类绑定        //model        injectionBinder.Bind<ScoreModel>().To<ScoreModel>().ToSingleton();//数据模型绑定        //server        injectionBinder.Bind<IScoreService>().To<ScoreService>().ToSingleton();//指定执行IScoreService绑定ScoreService        //command        commandBinder.Bind(Demo1CommandEvent.REQUEST_SCORE).To<RequestScoreCommand>();        commandBinder.Bind(Demo1CommandEvent.UPDATE_SCORE).To<UpdateScoreCommand>();        //mediator         mediationBinder.Bind<CubeView>().To<CubeMediator>();//完成view和mediator的绑定              */    [Inject]    public IScoreService scoreService { get; set; }    /// <summary>    /// 注入数据模型    /// </summary>    [Inject]    public ScoreModel scoreModel { get; set; }    /* 访问全局派发器的方式    /// <summary>    /// 访问全局派发器    /// </summary>    [Inject(ContextKeys.CONTEXT_DISPATCHER)]    public IEventDispatcher dispatcher { get; set; }    或者将command继承修改成eventCommand    */    public override void Execute()    {        /*            tip:prevent destory.        */        Retain();        //注册派送器:派送标签 Demo1ServiceEvent.REQUEST_SCORE 派送事件:OnComplete        /*            notice:waring register dispatcher handler pos.        */        scoreService.dispatcher.AddListener(Demo1ServiceEvent.REQUEST_SCORE, OnComplete);        scoreService.RequestScore("http://www.ciso.com");            }    /// <summary>    /// 服务器回包    /// </summary>    /// <param name="varEvt">回包数据</param>     void OnComplete(IEvent varEvt)    {        Debug.LogError("Request score from server :" + varEvt.data);        //销毁注册的派送器        scoreService.dispatcher.RemoveListener(Demo1ServiceEvent.REQUEST_SCORE,OnComplete);        //将服务器回包数据存于数据模型中        scoreModel.Score = (int) varEvt.data;        //将回包数据传递给 CubeMediator        dispatcher.Dispatch(Demo1MediatorEvent.SCORECHANGE, varEvt.data);        /*             tip:release,used to save resources        */        Release();    }}

只有通过了绑定才能在mediator里面通过事件注册通知的方式去发送请求。

        //通过dispatcher发起请求分数的命令        dispatcher.Dispatch(Demo1CommandEvent.REQUEST_SCORE);

好接下来我们通过图解来更加深入的了解一下这个流程:







创建更新分数Command命令,并进行绑定。

public class UpdateScoreCommand : EventCommand{    [Inject]    public ScoreModel scoreModel { get; set; }    [Inject]    public IScoreService scoreService { get; set; }    public override void Execute()    {        int varData=scoreModel.Score++;        scoreService.UpdateScore("http://www.ciso.com", varData);        dispatcher.Dispatch(Demo1MediatorEvent.SCORECHANGE,varData);    }}

所有的数据请求,数据回传都是通过全局的dispatch来实现的,这样能够将各个模块之间的耦合性降低,提高效率。最后还是使用图解和文字将“请求分数”“回传分数”“显示分数”进行解释,能够使自己对这个流程能够有更加深入细致的理解,了解游戏分层思想!

首先,模块入口是从下面这个玩家交互开始的:


接下里开始寻找哪里注册了这个事件类型,由于我们知道Cubeview视图层,每个视图层都有一个Mediator进行对应,主要用来处理模块之前的沟通通信,那我们来到这个脚本,可以看到对应的事件类型(Demo1MediatorEvent.CLICKDOWN),前请提示,之所以我们能这么做是因为我们在ContextView里面进行了view和各自mediator的绑定


好,我们接着看CubeMediator脚本


由于这里只是在模块激活时进行了提前注册,所以当玩家点击事件之后,全局派发器进行事件派发(通知),我们就会来到这里执行后面的对应的函数(/委托),那我们看看OnClickDown函数执行了什么?


我们回到ContextView可以看到,到底是谁和上面的事件id进行绑定


这里我们需要知道,当全局派发器进行派发的时候,根据事件id进行派发的,比如上面这个,很明显它是和UpdateScoreCommand这个脚本进行了绑定,所以全局派发器执行后,会自动跳转到这个脚本内部执行excute函数:


接着我们再看哪里注册对应这个事件id类型,很明显我们又在CubeMediator里面找到注册的地方


开始执行OnScoreChange函数:


好了,这里就完成服务器数据的回传。其实整体结构流程和MVC框架大致相同,不同的是StrangeIOC开创了binding方式和全局派发器的使用,关于请求分数的部分,自己可以多多练习,这里就不详细叙述了。

ps:

我也是第一次开始接触strangeioc框架学习,所以本文难免有疏漏之处,还望多多见谅。

0 0