strangeioc test learn

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框架學習,所以本文難免有疏漏之處,還望多多見諒。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章