StrangeIoc MVCS Game Framework

StrangeIoC Framework is an Extension of MVC Framework

Using a MVCS framework, it has been well applied in Unity3d

The following is a frame diagram of StrangeIoC:


[ROOT module]

Open the whole framework boot module

[MVCS Context Module]

To reduce the coupling of the whole framework, dependency bindings can be made between modules.

It can implement injection Binder, command Binder and command Binder.

[CONTROLLER module]

It can be considered as the communication link between VIEW module and MODEL, SERVICE module in the figure.

It can implement multiple commands, trigger commands in VIEW module, and respond commands in MODEL and SERVICE.

[VIEW Module]

VIEW module will be divided into view and mediator sub-modules.

View mainly implements client interface interaction, mediator is the link between VIEW and COMMAND

[MODEL module]

Manage, process and store the data in the game

[SERVICE module]

If your game is a click game, this module can be ignored

In the SERVICE module, game data can be communicated with the server.

Use a network framework to deploy and communicate with web projects


Next I implement a Demo to walk through the StrangeIoC framework process

Through this Demo, I believe you will have a clearer idea of the whole StrangeIoC.

Demo project source code can be downloaded Click Open Link

Say before:

First of all, I will explain that this service is only a module that I simulate a data interaction locally. You can change it according to the project requirements.

The following is the structure of the whole Demo.


[Development Environment]

StrangeIoC framework is well integrated into Unity, as long as you download it in AssetStore

And imported into their own project projects

[Launching Framework]

In the framework flowchart introduced earlier

The framework is started in the ROOT module

First create two C scripts named MySelfContextRoot (inheriting ContextView) and MySelfContext (inheriting MVCSContext)

MySelfContextRoot.cs

using UnityEngine;
using System.Collections;
using strange.extensions.context.impl;

public class MySelfContextRoot : ContextView//ContextView inherits MonoBehavior
{

	void Start()
	{
		Debug.Log("Start the framework");

		//Start StrangeIoC Framework
		this.context = new MySelfContext(this);
	}
	
}

Create a new empty game object and mount MySelfContextRoot.cs (be sure to mount it on an empty object, or report an error)


MySelfContext.cs

using UnityEngine;
using System.Collections;
using strange.extensions.context.impl;
using strange.extensions.context.api;


//Bind the script to an empty game object
public class MySelfContext : MVCSContext
{
	public MySelfContext(MonoBehaviour root) : base(root)
	{
		Debug.Log("Framework Startup Completion");
	}

	/// <summary>
	/// Mapping bindings
	/// </summary>
	protected override void mapBindings()
	{
	}
}



Next, write a command binding to check if the framework started properly.

Binding commands to mapBindings functions

//Command
        //Bind a start event and call it only once
		commandBinder.Bind(ContextEvent.START).To<StartCommand>().Once();

StartCommand object is a class written by itself, which corresponds to the CONTROLLER module.

StartCommand.cs

using UnityEngine;
using System.Collections;
using strange.extensions.command.impl;

public class StartCommand : Command
{
	/// <summary>
	/// When the event is bound, the function is executed
	/// </summary>
	public override void Execute()
	{
		Debug.Log("Complete binding");
	}
}

[Development of View Layer]

In the game scenario, there is a Cube. Demo will make a request to the server after running, and the server will randomly generate a random number and send it to the View side for display.

Click Cube on the client to trigger the response, process the data to the server, and display the updated data in View after processing.


Create a new Cube in the Hierarchy view and a subobject Text under Cube

Modify the Canvas attribute as follows


Create a new C# script for CubeView. Drag the script under Cube and you will see that Cube will shake.

CubeView.cs

using UnityEngine;
using System.Collections;
using strange.extensions.mediation.impl;
using UnityEngine.UI;
using strange.extensions.dispatcher.eventdispatcher.api;

public class CubeView : View//View inherits from Monobehavior
{
	public GameObject showScore;

    //Define a local dispatcher
    [Inject]
    public IEventDispatcher dispatcher
    {
        get;
        set;
    }

	/// <summary>
	/// Initialization (Getting Text Components)
	/// </summary>
	public void Init()
	{
		Debug.Log("Cube Initialization complete");
        showScore = GameObject.FindGameObjectWithTag("MySelfText");
	}

	private void Update()
	{
		this.transform.Translate(new Vector3(Random.Range(-1,2), Random.Range(-1, 2), Random.Range(-1, 2))*0.02f);
	}

	private void OnMouseDown()
	{
		Debug.Log("Mouse Click");
        dispatcher.Dispatch(CubeEvent.MouseClick);
	}

	public void UpdateScoreData(int newSore)
	{
        Debug.Log(newSore.ToString());
        showScore.GetComponent<Text>().text = newSore.ToString();
	}
}

Create a new CubeMediator.cs

CubeMediator.cs

using UnityEngine;
using System.Collections;
using strange.extensions.mediation.impl;
using strange.extensions.dispatcher.eventdispatcher.api;
using strange.extensions.context.api;

public class CubeMediator : Mediator
{
	/// <summary>
	/// Injection component means that the CubeView component on the game object is automatically added to the cubeView variable, so StrangeIoC automatically assigns the game component to the variable.
	/// Note that the variable needs to be given get,set attributes, or compile errors
	/// </summary>
	[Inject]
	public CubeView cubeView
	{
		get;
		set;
	}

    [Inject]
    public ScoreModel sm
    {
        get;
        set;
    }

    [Inject(ContextKeys.CONTEXT_DISPATCHER)]
    public IEventDispatcher dispatcher
    {
        get;
        set;
    }



	//When all attribute variables are injected into the object successfully, the function is called.
	public override void OnRegister()
	{
		cubeView.Init();

        //The listener function of the dispatcher is placed before the dispatcher, otherwise the listener function will not be callback.
        dispatcher.AddListener(CubeEvent.GetScore, GetScoreData);
        cubeView.dispatcher.AddListener(CubeEvent.MouseClick,GetMouseDown);

        dispatcher.Dispatch(CubeEvent.RequestScore);//The dispatcher is defined in EventMediator and the dispatch is global       
	}

	//When the CubeView component is destroyed, the function is called
	public override void OnRemove()
	{
        dispatcher.RemoveListener(CubeEvent.GetScore,GetScoreData);
	}

    public void GetScoreData(IEvent iev)
    {
        Debug.Log("helloword");
        cubeView.UpdateScoreData((int)iev.data);
        
        //Generally, the following method is not used to transfer data, in order to reduce the coupling of data.
        //cubeView.UpdateScoreData((int)sm.score);
    }


    public void GetMouseDown()
    {
        dispatcher.Dispatch(CubeEvent.AddScore);
    }
}




[Development of Command Layer]

At this point the dispatcher issues the command

Back to MySelfContext.cs

using UnityEngine;
using System.Collections;
using strange.extensions.context.impl;
using strange.extensions.context.api;


//Bind the script to an empty game object
public class MySelfContext : MVCSContext
{
	public MySelfContext(MonoBehaviour root) : base(root)
	{
		Debug.Log("Framework Startup Completion");
	}



	/// <summary>
	/// Mapping bindings
	/// </summary>
    protected override void mapBindings()
	{
		base.mapBindings();

		//Model
        injectionBinder.Bind<ScoreModel>().To<ScoreModel>().ToSingleton();

		//Mediator
        //Bind the View object to the Mediator object so that the CubeMediator component will be generated on the game object with the CubeView component
        mediationBinder.Bind<CubeView>().To<CubeMediator>();

		//Command
        //Bind a start event and call it only once
		commandBinder.Bind(ContextEvent.START).To<StartCommand>().Once();

        commandBinder.Bind(CubeEvent.RequestScore).To<RequestScoreCommand>();
        commandBinder.Bind(CubeEvent.AddScore).To<AddScoreCommand>();

		//Service
        //Injection bindings, when calling interface functions, access functions corresponding to inherited interface classes
        //Because the classes that implement the InterfaceScoreService interface may be quite right, they need to be specifically bound.
        injectionBinder.Bind<InterfaceScoreService>().To<ScoreService>().ToSingleton();//Singleton mode, indicating that the interface is implemented only once
	}
}

Inside
commandBinder.Bind(CubeEvent.RequestScore).To<RequestScoreCommand>();
The code will initiate the RequestScoreCommand command

RequestScoreCommand.cs

using UnityEngine;
using System.Collections;
using strange.extensions.command.impl;
using strange.extensions.dispatcher.eventdispatcher.api;
using strange.extensions.context.api;

public class RequestScoreCommand :EventCommand 
{
    [Inject]
    public InterfaceScoreService ifss//Binding in MySelfContext
    {
        get;
        set;
    }

    [Inject]
    public ScoreModel sm
    {
        get;
        set;
    }

    /*[Inject(ContextKeys.CONTEXT_DISPATCHER)]//Set dispatcher to global
    public IEventDispatcher dispatcher
    {
        get;
        set;
    }*/

    //The function is executed when the command is triggered
    public override void Execute()
    {
        Retain();//Prevent this class from being destroyed automatically. After listening to dispatcher, destroy it in OnComplete function.

        ifss.dispatcher.AddListener(ServiceEvent.Request,OnComplete);
        ifss.OnRequestScore("127.0.0.1");
    }

    private void OnComplete(IEvent iet)//This parameter is the fractional information. 
    {
        Debug.Log("Achieve success in scoring, with a score of ___________:"+iet.data);

        sm.score = (int)iet.data;

        dispatcher.Dispatch(CubeEvent.GetScore, iet.data);
        ifss.dispatcher.RemoveListener(ServiceEvent.Request,OnComplete);
        
        Release();
    }
}


[Development of Service and Model Layer]

InterfaceServiceScore.cs

using UnityEngine;
using System.Collections;
using strange.extensions.dispatcher.eventdispatcher.api;

public interface InterfaceScoreService
{
	/// <summary>
	/// Send Score Request to Server
	/// </summary>
	void OnRequestScore(string URL);


	/// <summary>
	/// Receive the score information from the server
	/// </summary>
	void OnReceiveScore();


	/// <summary>
	/// Update Score Information
	/// </summary>
	/// <param name="URL">server address </param>
	/// <param name="score">score </param>
	void UpdateScore(string URL,int score);


    /// <summary>
    /// Define a distributor for callbacks
    /// </summary>
    IEventDispatcher dispatcher
    {
        get;
        set;
    }
}

ServiceScore.cs

using UnityEngine;
using System.Collections;
using System;
using strange.extensions.dispatcher.eventdispatcher.api;

public class ScoreService : InterfaceScoreService
{   
    [Inject]
    public IEventDispatcher dispatcher
    {
        get;
        set;
    }

	public void OnRequestScore(string URL)
	{
		Debug.Log("To address"+URL+"Server sends requests");
		OnReceiveScore();
	}


	public void OnReceiveScore()
	{
		int score = UnityEngine.Random.Range(0, 100);
        dispatcher.Dispatch(ServiceEvent.Request,score);//Put the scores back together
	}

	
	public void UpdateScore(string URL, int score)
	{
		Debug.Log("On the server:"+URL+" The updated data are as follows:"+score.ToString());
	}
}

ScoreModel.cs

using UnityEngine;
using System.Collections;

public class ScoreModel
{
	public float score
	{
		get;
		set;
	}
}

Download Demo source code for details

The whole question is not clear in one or two articles.

If you have any questions, please feel free to contact me.

If this article is helpful to you, please support me a lot. Thank you.











Keywords: Attribute network Unity

Added by rockinaway on Sat, 13 Jul 2019 20:57:54 +0300