preface

Remind: In order to be able to learn the knowledge more thoroughly, remember more firmly I will write down the knowledge by means of teaching on Because can let a person in the process from students to the teacher This process will be dug up new knowledge and ideas is a self thinking mining switch and a depth of knowledge and the process of ascension If you can help to everyone that is the best If there is a mistake, please give me more advice! I’m just a vegetable chicken thanks for understanding!


Why use a UI framework

There are a lot of panels in the game: the backpack panel, the shop panel, the Settings panel,

Frequent calls and switches are needed between these panels. For example, there are various items in the backpack panel, the prompt box of item information will appear when we mouse over the items, and the Settings panel can only be switched back to the main menu panel by pressing the return button. Then how do we realize the communication between interfaces? My previous practice was to write a script on each panel I needed to use to implement the corresponding function. I believe many novice developers have come to this way. (Is Nani really me?)

Although this function is realized, the maintainability is reduced and the repetitive code is increased. In order to more conveniently manage and call the panels in the scene, we need to write a set of complete framework to restrict them, otherwise it is easy to appear the coexistence of panels, or switch failure and other problems.

It just so happens that Siki has a small UI framework course for beginners that is very good, and the most important thing is simplicity!! It’s really friendly for a novice like me! Let’s learn together!


The idea of framework

First, a brief introduction to the idea of this framework, the framework is mainly to achieve the panel reading storage and management, to help us better switch management between panels

First of all,

1. We store all the panel information we need through JSON files, such as the name of the panel, the type of the panel, the loading path of the panel, etc., according to the actual project requirements

2. Create a panel abstract class (which is the base class for all panels) to implement methods common to the panel, such as things to do when the panel enters and things to do when the panel exits

3. The code reads the JSON file to get all the panel information, and then we can use that information to manipulate the panel

4. The core of the framework is how to efficiently manage these panels. First, let’s walk through the process of creating and closing our panels

At this point, the player can only use the backpack panel, not the character panel (think about how many games do this). When we want to use the character panel, we need to close the backpack panel before we can use the character panel

Let me draw another picture here to illustrate it

Now we are at the top of the Settings menu neutron menu interface, at this time we can only operate the sub-menu interface, if we want to operate the Settings menu interface we need to close the sub-menu first, then we can operate the Settings menu

Now that the submenu is closed, we can operate the Settings menu!

Similarly, if we want to operate the main menu, we have to close the Settings menu in order to operate the main menu

So how does Siki manage the switching between panels? The students who have known about the data structure may immediately understand the above diagram! That’s right, Stack, Stack is a collection of last in, first out objects last in, first out, first in, first out, right? Doesn’t this just work for storing and managing our panels

First in and out is the main menu, so we put it at the bottom of the container, and then the player clicks on the Settings menu, so we put it on top of the main menu, and then the player clicks on a sub-menu in the Settings menu, and we put it on top of the Settings menu

We made the top panel on the stack only accessible to the player, pushing the top panel on the stack (panel in) and popping the top panel off the stack (panel out) made it easy to switch between the panels

Well, to be honest, I think what I’m talking about is a piece of shit. (Maybe only I can understand.)


In field

The train of thought manages once! Now let’s do it step by step!

1. Create a JSON file and write the panel information into JSON

So let’s do step one

We use JSON files to store all the panel information we need, such as the name of the panel, the type of the panel, the loading path of the panel, etc., according to the actual project requirements

So before we create a JSON file, we need to preform the panels that we’re going to use and put them in our Resources path and then we need to use Resources to load the panels that we’re going to use, and I’ve created a new panel here to show you, Name it “SettingPanel” and place it in the UIPanel folder of Resources

OK, so now we’re going to create a new JSON file. JSON is a JSON file, remember to put the JSON file in the Resources folder because we will get it from Resources later) and put the information of our panel in it, but I will make it simple for you to understand

Json file

{
    "data":
    [
       {"uiPanelType":"settingPanel","uiPanelPath":"UIPanel/SettingPanel"}
    ]
}

Here’s a quick look at the format of the JSON file

Curly braces {} hold objects: Objects can contain a variety of data, including arrays. Square brackets [] hold arrays: Arrays can contain objects. Data is separated by commas

Don’t understand we can directly find a parse the Json web site online Here recommend https://www.bejson.com/conver…

Let’s go ahead and select JSON to C# Entity Class and see if we can copy our JSON data and click Create Entity Class to see if we can

So I’m just going to make a copy of the generated entity for you to see

public class DataItem { public string uiPanelType { get; set; } public string uiPanelPath { get; set; } } public class Root { public List <DataItem> data { get; set; }}

I don’t know if these two classes map exactly the data in the JSON file

Contrast carefully to see what it means

It is important to note that the data must correspond to the information in the JSON file you are writing (and vice versa – in any case, the JSON and mapping class information names must be the same). One wrong word will cause JSON parsing to fail

Public String UIPanelType {get; set; } public string uiPanelPath { get; set; } public List <DataItem> data { get; set; } "UIPanelType ":" SettingPanel"," UIPanelPath ":"UIPanel/SettingPanel";}" UIPanelPath ":"UIPanel/SettingPanel" PanelType { get; set; } public string PanelPath { get; set; } public List <DataItem> paneldata { get; set; } "uiPanelType":"settingPanel","uiPanelPath":"UIPanel/SettingPanel"}

What I have said may be the same as a piece of shit or even worse (I have explained it for you). The best thing is to go to Baidu or Google to check the information by myself. Now I will do the most basic operation.

That’s the mapping class that we generated with one click and now let’s write it down ourselves

PanelData class

Public String UIPanelType {/// <summary> // </summary> public String UIPanelType; /// </summary> public String UIPanelPath; }

UIPanelDataList class

public class UIPanelDataList
{
    public PanelData[] data;
}

Now that we have two mapping classes, we need to write a UIPanelType enumeration class that defines our panel type, and then we get the UIPanelType data from the JSON file, and we convert the String to the enumeration type to get the panel type

UIPanelType class:

Public Enum UIPanelType {SettingPanel // SettingPanel}

Create the base class for the panel

Create a panel abstract class (which is the base class for all panels) to implement methods common to the panel, such as things to do when the panel enters and things to do when the panel exits

The UIPanelBase class is a little bit simpler and I don’t really want to talk about it because I want to define some of the methods that the panel has in common, right

UIPanelBase class:

using UnityEngine; public class UIPanelBase : MonoBehaviour {/// < Summary > public virtual void pushState () {debug. Log(" Stack state "); } /// </ Summary > public void popState () {debug.log ();} /// < Summary > public void popState () {debug.log (); } /// <summary> public virtual void remotState () {debug.log (" restore state "); }}

3. Read the JSON file

The code reads the JSON file to get information about all the panels, which we can then use to manipulate the panels

I recommend litJSON here, but you can also use Unity’s own JsonUtility, which you can use whenever you feel comfortable.

To use litJSON you need to refer to it, download litJSON.dll, and place it in your Plugins folder. If you don’t have it, create your own

Now we can create the core UIManager class

MainUIManager class

The first step is to reference litJSON, which is very simple. Just say “using litJSON;”

Then make the MainuiManager class a singleton.

using System.Collections.Generic; using UnityEngine; using LitJson; public class MainUIManager : MonoBehaviour {/// <summary> /// </summary> public static MainUIManager Instance; public void Awake() { Instance = this; }}

After the singleton is done we need two dictionaries, one to store the data parsed from JSON and one to store the UIPanelBase class of the panel (we need to add a script to each panel we want to operate on and inherit from the UIPanelBase class) We’re getting the UIPanelBase class on the panel, we’re getting an instance of the panel.)

using System.Collections.Generic; using UnityEngine; using LitJson; public class MainUIManager : MonoBehaviour {/// <summary> /// </summary> public static MainUIManager Instance; // </ Summary > Private Dictionary<UIPanelType, </ Summary > Private Dictionary<UIPanelType string> oriPanelDataDic = new Dictionary<UIPanelType, string>(); // </summary> private Dictionary<UIPanelType, </summary> private Dictionary<UIPanelType, UIPanelBase> newPanelDataDic = new Dictionary<UIPanelType, UIPanelBase>(); public void Awake() { Instance = this; }}

My English is not very good and the name will be a little bad

Now we are ready to read the data in the JSON file

using System.Collections.Generic; using UnityEngine; using LitJson; public class MainUIManager : MonoBehaviour {/// <summary> /// </summary> public static MainUIManager Instance; // </ Summary > Private Dictionary<UIPanelType, </ Summary > Private Dictionary<UIPanelType string> oriPanelDataDic = new Dictionary<UIPanelType, string>(); // </summary> private Dictionary<UIPanelType, </summary> private Dictionary<UIPanelType, UIPanelBase> newPanelDataDic = new Dictionary<UIPanelType, UIPanelBase>(); // </summary> private TextAsset UIpanelJSON; // </summary> private TextAsset UIpanelJSON; public void Awake() { Instance = this; } /// < Summary > private void initJSON () {// < Summary > private void initJSON () {// < Summary > private void initJSON () {// < Summary > private void initJSON = Resources.Load<TextAsset>("UIPanelData"); // Parse JSON UI PanelDatalist panelData = JsonMapper.toobject < UIPanelDatalist >(UIPanelJson.text); Foreach (panelData item in panelData.data) {// Convert the String type to an enumeration type and store it in the dictionary oriPanelDataDic.Add((UIPanelType)System.Enum.Parse(typeof(UIPanelType), item.uiPanelType.ToString()), item.uiPanelPath); }}}

Now we’re going to take the Canvas Transform component and so on and we’re going to write the logic for generating the panel and we’re going to set the parent of the panel to the Canvas and the Canvas I’ve set a Tag called “UICANVas” so I’m going to look it up directly through the Tag

using System.Collections.Generic; using UnityEngine; using LitJson; public class MainUIManager : MonoBehaviour {/// <summary> /// </summary> public static MainUIManager Instance; // </ Summary > Private Dictionary<UIPanelType, </ Summary > Private Dictionary<UIPanelType string> oriPanelDataDic = new Dictionary<UIPanelType, string>(); // </summary> private Dictionary<UIPanelType, </summary> private Dictionary<UIPanelType, UIPanelBase> newPanelDataDic = new Dictionary<UIPanelType, UIPanelBase>(); // </summary> private TextAsset UIpanelJSON; // </summary> private TextAsset UIpanelJSON; private Transform uiCanvasTran; public void Awake() { Instance = this; InitJson(); Init(); } /// < Summary > private void initJSON () {// < Summary > private void initJSON () {// < Summary > private void initJSON () {// < Summary > private void initJSON = Resources.Load<TextAsset>("UIPanelData"); // Parse JSON UI PanelDatalist panelData = JsonMapper.toobject < UIPanelDatalist >(UIPanelJson.text); Foreach (panelData item in panelData.data) {// Convert the String type to an enumeration type and store it in the dictionary oriPanelDataDic.Add((UIPanelType)System.Enum.Parse(typeof(UIPanelType), item.uiPanelType.ToString()), item.uiPanelPath); }} /// < Summary > private void Init() {if (UICanVastran == null) {UICanVastran == null GameObject.FindGameObjectWithTag("UICanvas").transform; }}}

It is also simple to write the logic to generate the panel

using System.Collections.Generic; using UnityEngine; using LitJson; public class MainUIManager : MonoBehaviour {/// <summary> /// </summary> public static MainUIManager Instance; // </ Summary > Private Dictionary<UIPanelType, </ Summary > Private Dictionary<UIPanelType string> oriPanelDataDic = new Dictionary<UIPanelType, string>(); // </summary> private Dictionary<UIPanelType, </summary> private Dictionary<UIPanelType, UIPanelBase> newPanelDataDic = new Dictionary<UIPanelType, UIPanelBase>(); // </summary> private TextAsset UIpanelJSON; // </summary> private TextAsset UIpanelJSON; private Transform uiCanvasTran; public void Awake() { Instance = this; InitJson(); Init(); } /// < Summary > private void initJSON () {// < Summary > private void initJSON () {// < Summary > private void initJSON () {// < Summary > private void initJSON = Resources.Load<TextAsset>("UIPanelData"); // Parse JSON UI PanelDatalist panelData = JsonMapper.toobject < UIPanelDatalist >(UIPanelJson.text); Foreach (panelData item in panelData.data) {// Convert the String type to an enumeration type and store it in the dictionary oriPanelDataDic.Add((UIPanelType)System.Enum.Parse(typeof(UIPanelType), item.uiPanelType.ToString()), item.uiPanelPath); }} /// < Summary > private void Init() {if (UICanVastran == null) {UICanVastran == null GameObject.FindGameObjectWithTag("UICanvas").transform; }}} / / / < summary > / / / / / / generates panel < / summary > / / / < param name = "panelType" > panel type < param > / / / < returns > < / returns > public UIPanelBase GeneratePanel(UIPanelType panelType) { UIPanelBase uiPanelBase; newPanelDataDic.TryGetValue(panelType, out uiPanelBase); // if (UIPanelBase == null) {string panelPath; oriPanelDataDic.TryGetValue(panelType, out panelPath); GameObject newPanel = Instantiate(Resources.Load<GameObject>(panelPath)); newPanel.transform.SetParent(uiCanvasTran, false); uiPanelBase = newPanel.GetComponent<UIPanelBase>(); newPanelDataDic.Add(panelType, uiPanelBase); return uiPanelBase; } return uiPanelBase; }

After generating the panel and returning the UIPanelBase class, we can do the panel push and push operation

using System.Collections.Generic; using UnityEngine; using LitJson; public class MainUIManager : MonoBehaviour {/// <summary> /// </summary> public static MainUIManager Instance; // </ Summary > Private Dictionary<UIPanelType, </ Summary > Private Dictionary<UIPanelType string> oriPanelDataDic = new Dictionary<UIPanelType, string>(); // </summary> private Dictionary<UIPanelType, </summary> private Dictionary<UIPanelType, UIPanelBase> newPanelDataDic = new Dictionary<UIPanelType, UIPanelBase>(); // </summary> private TextAsset UIpanelJSON; // </summary> private TextAsset UIpanelJSON; private Transform uiCanvasTran; private Stack<UIPanelBase> panelStack; public void Awake() { Instance = this; InitJson(); Init(); } /// < Summary > private void initJSON () {// < Summary > private void initJSON () {// < Summary > private void initJSON () {// < Summary > private void initJSON = Resources.Load<TextAsset>("UIPanelData"); // Parse JSON UI PanelDatalist panelData = JsonMapper.toobject < UIPanelDatalist >(UIPanelJson.text); Foreach (panelData item in panelData.data) {// Convert the String type to an enumeration type and store it in the dictionary oriPanelDataDic.Add((UIPanelType)System.Enum.Parse(typeof(UIPanelType), item.uiPanelType.ToString()), item.uiPanelPath); }} /// < Summary > private void Init() {if (UICanVastran == null) {UICanVastran == null GameObject.FindGameObjectWithTag("UICanvas").transform; }} / / / < summary > / / / / / / generates panel < / summary > / / / < param name = "panelType" > panel type < param > / / / < returns > < / returns > public UIPanelBase GeneratePanel(UIPanelType panelType) { UIPanelBase uiPanelBase; newPanelDataDic.TryGetValue(panelType, out uiPanelBase); // if (UIPanelBase == null) {string panelPath; oriPanelDataDic.TryGetValue(panelType, out panelPath); GameObject newPanel = Instantiate(Resources.Load<GameObject>(panelPath)); newPanel.transform.SetParent(uiCanvasTran, false); uiPanelBase = newPanel.GetComponent<UIPanelBase>(); newPanelDataDic.Add(panelType, uiPanelBase); return uiPanelBase; } return uiPanelBase; } /// <summary> // </summary> // <param name="panelType"></param bb3 public void PushPanel(UIPanelType) panelType) { if(panelStack==null) { panelStack = new Stack<UIPanelBase>(); } UIPanelBase uiPanelBase = GeneratePanel(panelType); uiPanelBase.PushState(); panelStack.Push(uiPanelBase); } /// < Summary > public void popPanel () {if (PanelStack == null) return; UIPanelBase = currentuIPanelBase = panelStack.pop (); currentUIpanelBase.PopState(); if (panelStack.Count > 0) { UIPanelBase outUIpanelBase = panelStack.Peek(); outUIpanelBase.RemotState(); }}}

So we have our mainuiManager class written and now it’s very easy to call it so let’s add a script for our SettingPanel “SettingPanel” (remember to inherit from UIPanelBase)

public class SettingPanel : UIPanelBase { public void AddButtonClick() { MainUIManager.Instance.PushPanel(UIPanelType.settingPanel); }}

Once the method is written, bind it to the Button to be clicked (for example, clicking the Settings Button to display the Settings panel binds the Settings panel script to the Button component of the Settings Button)

Oh, it doesn’t bind. Just drag the panel onto OnClick and select the method we just wrote down or you can check it out

Now all of our steps are complete run the game and see how it works! Normally we now click the Settings button will pop up the panel


4, the last

If you pop up the panel That proved successful, popup also don’t be discouraged if you don’t study the code and see an error, in the above case we only do the panel into the stack operation, you can try to complete the panel of stack operation, a very simple only need to write one line of code, code is to think about why, rather than follow anything knock, Try to add some new features to the framework yourself!

Finally, I still want to explain that the article is mainly used to consolidate the knowledge I learned to use, so not those big guys say so detailed, if you see Meng! Then I am very sorry, I suggest you close it and watch the whole tutorial hahaha