实现不同模块或窗口的互相切换,其实用一些代码都可以实现,但是使用UI框架不仅方便后续修改添加删除,同时在做出扩展效果时,也可以快速实现。由于我还是学生,这些搭建UI的材料都是以前玩的一些小游戏里面,比较简陋。
先看一下大体的思维导图。
做出的成果开始的时候只有一个摄像机,
然后开始运行以后出现一个UI界面如下:
然后随便点击几个UI界面:
实现UI窗口的切换。
下面开始正式内容:搭建UI的部分我就不展示了,大家可以自己先搭建几个UI界面,并设成预设体,在Assets内新建文件夹Resources(必须时这个名字不能错),在Resources里新建Panels,将预设体放进去。
设计一个Json文件,里面存放不同模块的信息。我的名字为UIPanelConfig.Json,在Resources文件夹里的Configuration文件夹里,要记住存放的位置,后面要用。Json的内容为:
{
"AllData":
[
{
"SceneName":"MainScene",
"Data":
[
{
"PanelName":"MainPanel",
"PanelPath":"Panels/MainPanel"
},
{
"PanelName":"BagPanel",
"PanelPath":"Panels/BagPanel"
},
{
"PanelName":"HeroEquipPanel",
"PanelPath":"Panels/HeroEquipPanel"
},
{
"PanelName":"HeroMsgPanel",
"PanelPath":"Panels/HeroMsgPanel"
},
{
"PanelName":"NormalWindowPanel",
"PanelPath":"Panels/NormalWindowPanel"
},
{
"PanelName":"SystemPanel",
"PanelPath":"Panels/SystemPanel"
},
{
"PanelName":"TaskPanel",
"PanelPath":"Panels/TaskPanel"
}
]
}
]
}
写因为后面要频繁使用单例,所以先写一个单例框架。定义一个命名空间为UIFrame
using System;
namespace UIFrame
{
public class Singleton<T> where T : class
{
//单例对象
private static T _singleton;
//获取单例
public static T Instance
{
get
{
if (_singleton == null)
{
_singleton= (T)Activator.CreateInstance(typeof(T), nonPublic: true);
}
return _singleton;
}
}
}
}
编写一个资源管理类为:AssetsManager,避免每次资源被调用后直接销毁而产生内存浪费,所以做一个缓存机制。
using System.Collections.Generic;
using UnityEngine;
namespace UIFrame
{
public class AssetsManager : Singleton<AssetsManager>
{
//私有构造
private AssetsManager()
{
assetsCache = new Dictionary<string, Object>();
}
//资源缓存
private Dictionary<string, Object> assetsCache;
public Object GetAssets(string path)
{
//要返回的资源
Object assetObj = null;
//尝试从字典中获取该路径所对应的资源
if (!assetsCache.TryGetValue(path,out assetObj))
{
//通过Resource加载资源
assetObj = Resources.Load(path);
//将资源存进缓存
assetsCache.Add(path, assetObj);
}
return assetObj;
}
private Object TryGetValueTest(string key)
{
Object assetObj = null;
//尝试获取资源
//如果获取到了则isGet==True
//如果没有获取到则isGet==False,assetObj就没有获取到值
bool isGet= assetsCache.TryGetValue(key, out assetObj);
if(isGet)
{
//assetObj已经获取到值了
return assetObj;
}
else
{
//Resource加载该资源
assetObj = Resources.Load(key);
//放入缓存
assetsCache.Add(key, assetObj);
//返回他
return assetObj;
}
}
}
}
写一个类:SystemDefine。在里面存放一些常用的常数或字符串。
namespace UIFrame
{
public static class SystemDefine
{
#region Conciguration Path
public const string PanelConfigPath = "Configuration/UIPanelConfig";
public const string LocalizationConfigPath = "Configuration/UILanguageTextConfig";
#endregion
#region Scene ID
public enum SceneID
{
MainScene = 0
}
#endregion
#region Widget Token
public static string[] WIDGET_TOKEN=new string[] { "_F","_S","_T"} ;
#endregion
}
}
接下来编写一个用来解析和调用Json数据的代码。名字为JsonDataManager。这里面的一些方法就需要调用SystemDefine类里的固定字符串了。解析Json利用Unity自带的类JsonUtility(功能较少,但是简单)。
TextAsset panelConfig = AssetsManager.Instance.GetAssets(SystemDefine.PanelConfigPath) as TextAsset;//将Json转换成TextAsset类型,然后利用JsonUtility.FromJson解析,解析后的结构与JsonPanelModel类型相同。创建一个字典类型panelDataDic,把解析后的数据panelData放入到字典里,然后在下面的FindPanelPath方法内,只要在外界调用时传入一个panelName,则返回原本Json文件里的路径。
using System.Collections.Generic;
using UnityEngine;
namespace UIFrame
{
public class JsonDataManager :Singleton<JsonDataManager>
{
private JsonDataManager()
{
panelDataDic = new Dictionary<int, Dictionary<string, string>>();
localizationDic = new Dictionary<int, Dictionary<string, string[]>>();
ParsePanelData();
ParseLocalizationData();
}
#region Saved Structure
//Panel解析后的数据,不利于检索
private JsonPanelModel panelData;
//本地化内容解析后的数据
private JsonLocalizationModel localizationData;
//Panel解析后的数据当作字典处理,容易检索
private Dictionary<int, Dictionary<string, string>> panelDataDic;