目次
1. BagPanel で Canvas を見つけて、高い結合率で、RolePanel を呼び出します。
2. 最初、RolePanel は非表示状態にあり、transform.Find() を使用してもオブジェクトが見つからない可能性があります。
3. 改善: 各パネルのステータスを制御および管理するための UIManager をセットアップします。
1. 各パネルのリファレンスを個別に記述する必要があり、プロジェクトの複雑さへの対応が困難
2. メモリが急増し、統合シャットダウンの効率が低下します。
3. 各パネルに関数を個別に記述する必要があり、後の展開が貧弱すぎる
序文: 基礎が必要: MVC アイデア、UGUI、XML 基礎
小さな知識ポイント:
1.リソース: パッケージ化プロセス中、フォルダー内のリソースが有用であるかどうかに関係なく、それらはパッケージ化されます。パッケージ化後、このフォルダーは圧縮された形式で存在し、パッケージ化されたファイルには見つかりません (上限、最大4Gファイルのみ保存可能)
2. 一般的な制約
struct、class、クラス名、インターフェイス名 (継承制約)、new(): パラメーターのないパブリック コンストラクターが必要です
3. UIコンポーネント - グリッドレイアウトグループ
パート 1: UIFrame_1.0
1. UI インターフェイスと要件を構築する
1. 右下のアイコンをクリックしてパネルを表示します
2. パネル内に十字 ❌ があります。❌ をクリックしてパネルを閉じます
3. バックパックパネルにボタンが必要です。ボタンをクリックすると、キャラクター属性パネルが開き、キャラクター属性 (RolePanel) が表示されます。
実装コード: MainPanel
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class MainPanel : MonoBehaviour
{
Button btn_setting;
Button btn_skill;
Button btn_bag;
Button btn_role;
GameObject mainPanel;
GameObject rolePanel;
GameObject bagPanel;
GameObject settingPanel;
GameObject skillPanel;
Transform BtnGroup;
Transform Canvas;
void Awake()
{
BtnGroup = transform.Find("BtnGroup");
Canvas = transform.parent;
Debug.Log(Canvas);
btn_setting = BtnGroup.Find("Btn_Setting").GetComponent<Button>();
btn_skill = BtnGroup.Find("Btn_Skill").GetComponent<Button>();
btn_bag = BtnGroup.Find("Btn_Bag").GetComponent<Button>();
btn_role = BtnGroup.Find("Btn_Role").GetComponent<Button>();
settingPanel = Canvas.Find("SettingPanel").gameObject;
skillPanel = Canvas.Find("SkillPanel").gameObject;
bagPanel = Canvas.Find("BagPanel").gameObject;
rolePanel = Canvas.Find("RolePanel").gameObject;
}
// Start is called before the first frame update
void Start()
{
btn_setting.onClick.AddListener(() => { settingPanel.SetActive(!settingPanel.activeSelf); });
btn_skill.onClick.AddListener(() => { skillPanel.SetActive(!skillPanel.activeSelf); });
btn_bag.onClick.AddListener(() => { bagPanel.SetActive(!bagPanel.activeSelf); });
btn_role.onClick.AddListener(() => { rolePanel.SetActive(!rolePanel.activeSelf); });
}
// Update is called once per frame
void Update()
{
}
}
バッグパネル:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class BagPanel : MonoBehaviour
{
Transform RolePanel;
Button btn_RolePanel;
Transform Canvas;
Transform Btn_close;
Button btn_close;
private void Awake()
{
Canvas = transform.parent;
RolePanel = Canvas.Find("RolePanel");
btn_RolePanel = transform.Find("Btn_RolePanel").GetComponent<Button>();
Btn_close = GameObject.Find("Btn_close").transform;
btn_close = Btn_close.GetComponent<Button>();
}
// Start is called before the first frame update
void Start()
{
btn_close.onClick.AddListener(() => {gameObject.SetActive(false); });
btn_RolePanel.onClick.AddListener(() => { RolePanel.gameObject.SetActive(true); });
}
// Update is called once per frame
void Update()
{
}
}
次に、上記の関数コードの欠点に注意してください。
1. BagPanel で Canvas を見つけて、高い結合率で、RolePanel を呼び出します。
2. 最初、RolePanel は非表示状態にあり、transform.Find() を使用してもオブジェクトが見つからない可能性があります。
3. 改善: 各パネルのステータスを制御および管理するための UIManager をセットアップします。
UIManager脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class UIManager : MonoBehaviour
{
//UIManager一般会绑定在GameRoot脚本上面
GameObject Canvas;
GameObject mainPanel;
GameObject rolePanel;
GameObject bagPanel;
GameObject settingPanel;
GameObject skillPanel;
Button btn_setting;
Button btn_skill;
Button btn_bag;
Button btn_role;
Transform BtnGroup;
private static UIManager _instance;
public static UIManager Instance
{
get
{
return _instance;
}
}
private void Awake()
{
_instance = this;
Canvas = GameObject.Find("Canvas");
mainPanel = Canvas.transform.Find("MainPanel").gameObject;
settingPanel = Canvas.transform.Find("SettingPanel").gameObject;
skillPanel = Canvas.transform.Find("SkillPanel").gameObject;
bagPanel = Canvas.transform.Find("BagPanel").gameObject;
rolePanel = Canvas.transform.Find("RolePanel").gameObject;
BtnGroup = mainPanel.transform.Find("BtnGroup");
btn_setting = BtnGroup.Find("Btn_Setting").GetComponent<Button>();
btn_skill = BtnGroup.Find("Btn_Skill").GetComponent<Button>();
btn_bag = BtnGroup.Find("Btn_Bag").GetComponent<Button>();
btn_role = BtnGroup.Find("Btn_Role").GetComponent<Button>();
}
public void showSettingPanel()
{
btn_setting.onClick.AddListener(() => { settingPanel.SetActive(!settingPanel.activeSelf); });
}
public void showMainPanel()
{
}
public void showSkillPanel()
{
btn_skill.onClick.AddListener(() => { skillPanel.SetActive(!skillPanel.activeSelf); });
}
public void showBagPanel()
{
btn_bag.onClick.AddListener(() => { bagPanel.SetActive(!bagPanel.activeSelf); });
}
public void showRollPanel(bool isShowRollPanel)
{
if (isShowRollPanel)
{
//btn_role.onClick.AddListener(() => { rolePanel.SetActive(true); });
rolePanel.SetActive(true);
return;
}
else
btn_role.onClick.AddListener(() => { rolePanel.SetActive(!rolePanel.activeSelf); });
}
// Start is called before the first frame update
void Start()
{
rolePanel.SetActive(false);
bagPanel.SetActive(false);
settingPanel.SetActive(false);
skillPanel.SetActive(false);
}
// Update is called once per frame
void Update()
{
}
}
実行結果:
UIManager1
第 4 に、UIFrame1.0 にはまだ欠点があります。
1. 各パネルのリファレンスを個別に記述する必要があり、プロジェクトの複雑さへの対応が困難
解決策: 各参照はコンテナーに保管され、必要なときにコンテナーから取り出されます。
2. メモリが急増し、統合シャットダウンの効率が低下します。
最初に見つけられるようにするには、最初に各パネルを開いて、見つけたら閉じる必要があるため、ゲームを開始するとメモリが急増し、起動時の効率が悪くなります。均一に閉じた。
解決策: ゲームの実行を開始するとき、すべてのパネルを開くのではなく、各パネルをプレハブにし、最初に必要なときにロードしてコンテナーに保管し、コンテナーから取り出して再度使用します。
3. 各パネルに関数を個別に記述する必要があり、後の展開が貧弱すぎる
解決策: コンテナ検索メソッドを使用して、操作の特定の参照に対応させます。
2 番目の部分: UIFrame_2.0
1. 新しい要件:
1. UI パネルごとに異なる開閉効果を実現 (移動して開く、回転して開く、拡大・縮小してシェイクして開くなど)
2. 属性パネル内のバックパックパネル => 属性パネル = "火属性パネル" を開き、属性パネル => 属性パネル = "バックパックパネル" 内の火属性パネルを閉じるボタンをクリックして閉じます。
3. UIFrame_1.0の問題を改善し、パネルをプレハブ読み込み方式にし、コンテナを使用して格納する
4. 右下隅のアイコンをクリックすると、残りのアイコンがグレー表示になりクリックできなくなります。
注: Unity で XML ファイルを読み取るときは、XML をどこに配置する必要がありますか? Assets フォルダーの下にありますか? Application.Datapath を使用してファイルを読み取る必要がありますか?
プロジェクトがパッケージ化されると、Assets フォルダーは Unity によってバイナリ ファイルとしてパッケージ化されるため、Application.DataPath は Assets フォルダーの下に xml ファイルを見つけることができず、Resources フォルダーに配置する必要があります。
コード部分:
ファイル読み込みモジュール: XML 設定ファイルを読み込みます
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public static class ResourcesManager
{
public static Dictionary<string,GameObject> ResourcesDic = new Dictionary<string,GameObject>();
/// <summary>
/// 加载资源:加载预制体
/// 1、判断容器中是否存在该路径,
/// 2、如果有的话,直接返回GameObj-------------ect
/// 3、如果没有的话,调用Resources.Load()加载资源,然后再存入在存入到容器中
/// </summary>
/// <param name="path"> 传入一个资源路径 </param>
/// <returns></returns>
public static GameObject Load(string path)
{
if (ResourcesDic.ContainsKey(path))
{
return ResourcesDic[path];
}
GameObject gobj= Resources.Load(path) as GameObject;
//ResourcesDic.Add(path, gobj);
//索引器
ResourcesDic[path] = gobj;
return gobj;
}
/// <summary>
/// 重载:加载非预制体的资源
/// </summary>
/// <typeparam name="Object"></typeparam>
/// <param name="path"></param>
/// <returns></returns>
/// Hashtable : 非泛型键值对容器,键名和键值都可以是任意的数据类型
public static Hashtable ResHtb = new Hashtable();
//泛型函数
public static T Load<T>(string path) where T : Object
{
if (ResHtb.ContainsKey(path))
{
//as:只能是引用类型之间的转换,这里必须约束T为引用类型
return ResHtb[path] as T ;
}
//Resources.Load()方法能返回的东西必须继承自Object:需要保证T可以隐式转换为Object
T t= Resources.Load<T>(path);
ResHtb[path] = t;
return t;
}
}
MyUIManager: すべての UI インターフェイスの開閉を管理します。これは、MVC のコントロール層に相当します。
using System.Collections;
using System.Collections.Generic;
using System.Xml;
using UnityEngine;
public enum MyUIEnum
{
MainPanel=1,
RolePanel,
SkillPanel,
BagPanel,
SettingPanel
}
/// <summary>
/// 管理所有UI界面的开启和关闭
/// </summary>
public static class MyUIManager
{
public static Transform canvas = null;
public static Transform ThisCanvas
{
get
{
if (canvas ==null)
{
canvas = GameObject.Find("Canvas").transform;
}
return canvas;
}
}
//
private static Dictionary<MyUIEnum, string> prefabDic = new Dictionary<MyUIEnum, string>();
private static Dictionary<MyUIEnum, BasePanel> panelDic = new Dictionary<MyUIEnum, BasePanel>();
private static Stack<BasePanel> UIStack = new Stack<BasePanel>();
/// <summary>
/// 一开始的时候,从xml中读取所有UI预制体的地址和枚举类型的对应关系
/// </summary>
public static void OnloadXml()
{
//TextAsset所有外部加载的文本,使用这个数据类型保存
TextAsset xml = Resources.Load<TextAsset>("Configs/UIPanel");
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml.text);//加载xml文件中的内容
XmlNodeList list = xmlDoc.SelectSingleNode("root").ChildNodes;
foreach (XmlElement item in list)
{
MyUIEnum uiEnum =(MyUIEnum) int.Parse(item.GetAttribute("id"));
string path ="Prefabs/"+ item.GetAttribute("path");
prefabDic.Add(uiEnum, path);
}
}
/// <summary>
/// 根据枚举(编号)拿到对应的ui预制体
/// </summary>
/// <param name="uiEnum"></param>
/// <returns></returns>
static BasePanel GetPanel(MyUIEnum uiEnum,Transform parent=null)
{
if (panelDic.ContainsKey(uiEnum))
{
return panelDic[uiEnum];
}
//如果这个界面从来没有被打开过
string path = prefabDic[uiEnum];
GameObject prefab = ResourcesManager.Load(path);
GameObject go = GameObject.Instantiate(prefab);//拿到并实例化预制体
if (parent ==null)
{
parent = ThisCanvas;
}
go.transform.SetParent(parent);
BasePanel panel = go.GetComponent<BasePanel>();
panelDic.Add(uiEnum, panel);
return panel;
}
public static void Load(MyUIEnum uiEnum,Transform parent = null)
{
if (UIStack.Count>0)
{
BasePanel topPanel = UIStack.Peek();//拿到栈顶元素但不出栈
topPanel.Pause();
}
BasePanel panel = GetPanel(uiEnum,parent);
UIStack.Push(panel);
panel.Enter();
}
public static void UnLoad()
{
if (UIStack.Count<=0)
{
return;
}
BasePanel topPanel = UIStack.Pop();
topPanel.Close();
if (UIStack.Count > 0)
{
BasePanel resumePanel = UIStack.Peek();
resumePanel.Resume();
}
}
public static void Clear()
{
canvas = null;
UIStack.Clear();
}
}