2.准备工作

2.准备工作


2.1 知识点

创建Unity和FGUI工程

FGUI导入美术资源 项目设置中设计分辨率

导入Unity商店中FGUI的SDK

导入UIManager 删除之前Teach和注册组件相关

导入二进制相关的包


2.2 知识点代码

UIManager

using FairyGUI;
using Login;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIManager
{
    private static UIManager instance = new UIManager();
    public static UIManager Instance => instance;
    //用于存储已经显示的 UI面板
    private Dictionary<string, GComponent> panelDic = new Dictionary<string, GComponent>();
    //用于存储已经显示的 窗口
    private Dictionary<string, Window> windowDic = new Dictionary<string, Window>();
        
    private UIManager()
    {
        //默认字体
        UIConfig.defaultFont = "UI/STHUPO";
        //默认音效
        UIPackage.AddPackage("UI/Public");
        UIConfig.buttonSound = (NAudioClip)UIPackage.GetItemAssetByURL("ui://Public/btnMusic");

        //适配相关的设置
        GRoot.inst.SetContentScaleFactor(1365, 768, UIContentScaler.ScreenMatchMode.MatchHeight);

        //设置模态半透明程度
        UIConfig.modalLayerColor = new Color(0, 0, 0, 0.5f);

        //注册相关的代码
        LoginBinder.BindAll();
    }

    //组件名和面板类名 是一致的 
    public T ShowPanel<T>(string packageName) where T:GComponent
    {
        Type panelType = typeof(T);
        string panelName = panelType.Name;
        //如果字典中有该面板的名字 证明已经创建过了 直接返回即可
        if (panelDic.ContainsKey(panelName))
        {
            panelDic[panelName].visible = true;
            return panelDic[panelName] as T;
        }

        //加载包和依赖包 
        //由于从Resources文件夹中加载包 会帮助我们判断重复没有 所以 这里既是重复执行也没什么问题
        UIPackage package = UIPackage.AddPackage("UI/" + packageName);
        foreach (var item in package.dependencies)
        {
            UIPackage.AddPackage("UI/" + item["name"]);
        }

        //创建组件面板
        GComponent panel = UIPackage.CreateObject(packageName, panelName).asCom;
        //把组件的尺寸设置的和逻辑分辨率一致
        panel.MakeFullScreen();
        GRoot.inst.AddChild(panel);
        //和父对象建立 宽高关联 这样 分辨率变化时 面板也不会出问题
        panel.AddRelation(GRoot.inst, RelationType.Size);

        //进行批处理 DC优化 开关开启
        panel.fairyBatching = true;
        //把当前显示的面板存起来 用于之后的隐藏
        panelDic.Add(panelName, panel);

        //把父类转换成对应的 子类
        return panel as T;
    }

    //显示窗口方法
    public T ShowWindow<T>() where T:Window,new()
    {
        Type type = typeof(T);
        string windowName = type.Name;

        //判断有没有面板
        if (windowDic.ContainsKey(windowName))
        {
            windowDic[windowName].Show();
            return windowDic[windowName] as T;
        }

        //创建并显示面板
        T win = new T();
        //记录字典中
        windowDic.Add(windowName, win);

        //当存储了再去显示 避免显示时调用隐藏不执行
        win.Show();

        

        return win;
    }

    public void HidePanel<T>(bool isDispose = false) where T:GComponent
    {
        Type panelType = typeof(T);
        string panelName = panelType.Name;
        //如果没有面板显示着  就直接返回
        if (!panelDic.ContainsKey(panelName))
            return;
        //希望移除面板
        if( isDispose )
        {
            //移除面板 并且从字典中移除
            panelDic[panelName].Dispose();
            panelDic.Remove(panelName);
        }
        //希望只是失活
        else
        {
            panelDic[panelName].visible = false;
        }
    }

    //隐藏窗口方法
    public void HideWindow<T>(bool isDispose = false)
    {
        Type type = typeof(T);
        string windowName = type.Name;

        if (windowDic.ContainsKey(windowName))
        {
            if(isDispose)
            {
                windowDic[windowName].Dispose();
                windowDic.Remove(windowName);
            }
            else
            {
                windowDic[windowName].Hide();
            }
        }
            
    }

    public T GetPanel<T>() where T:GComponent
    {
        Type panelType = typeof(T);
        string panelName = panelType.Name;
        //如果有这个面板 直接返回
        if (panelDic.ContainsKey(panelName))
            return panelDic[panelName] as T;

        return null;
    }

    //得到窗口
    public T GetWindow<T>() where T:Window
    {
        Type type = typeof(T);
        string windowName = type.Name;

        if (windowDic.ContainsKey(windowName))
        {
            return windowDic[windowName] as T;
        }

        return null;
    }

    //主要用于销毁所有面板 和 资源垃圾回收的方法
    public void ClearPanel(bool isGC = false)
    {
        //销毁所有面板 并且清空字典
        foreach (var item in panelDic.Values)
        {
            item.Dispose();
        }
        panelDic.Clear();

        if(isGC)
        {
            //释放所有包资源
            UIPackage.RemoveAllPackages();
            //垃圾回收
            GC.Collect();
        }
    }

    //清除所有窗口
    public void ClearWindow(bool isGC = false)
    {
        //销毁所有面板 并且清空字典
        foreach (var item in windowDic.Values)
        {
            item.Dispose();
        }
        windowDic.Clear();
        if(isGC)
        {
            //释放所有包资源
            UIPackage.RemoveAllPackages();
            //垃圾回收
            GC.Collect();
        }
    }


    /// <summary>
    /// 加载组件 
    /// </summary>
    /// <param name="packageName">包名</param>
    /// <param name="componentName">组件名</param>
    /// <returns></returns>
    public GComponent LoadComponent(string packageName, string componentName)
    {
        //加载包
        UIPackage package = UIPackage.AddPackage("UI/" + packageName);
        //加载依赖包
        foreach (var item in package.dependencies)
        {
            UIPackage.AddPackage("UI/" + item["name"]);
        }

        GComponent component = UIPackage.CreateObject(packageName, componentName).asCom;
        //component.MakeFullScreen();

        //优化dc,只需要把面板组件fairyBatching设置为true
        component.fairyBatching = true;
        return component;
    }
}

BinaryDataMgr

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using UnityEngine;

/// <summary>
/// 2进制数据管理器
/// </summary>
public class BinaryDataMgr
{
    /// <summary>
    /// 2进制数据存储位置路径
    /// </summary>
    public static string DATA_BINARY_PATH = Application.streamingAssetsPath + "/Binary/";

    /// <summary>
    /// 用于存储所有Excel表数据的容器
    /// </summary>
    private Dictionary<string, object> tableDic = new Dictionary<string, object>();

    /// <summary>
    /// 数据存储的位置
    /// </summary>
    private static string SAVE_PATH = Application.persistentDataPath + "/Data/";

    private static BinaryDataMgr instance = new BinaryDataMgr();
    public static BinaryDataMgr Instance => instance;

    private BinaryDataMgr()
    {
        InitData();
    }

    public void InitData()
    {
        LoadTable<ServerInfoContainer, ServerInfo>();
    }

    /// <summary>
    /// 加载Excel表的2进制数据到内存中 
    /// </summary>
    /// <typeparam name="T">容器类名</typeparam>
    /// <typeparam name="K">数据结构类类名</typeparam>
    public void LoadTable<T,K>()
    {
        //读取 excel表对应的2进制文件 来进行解析
        using (FileStream fs = File.Open(DATA_BINARY_PATH + typeof(K).Name + ".tao", FileMode.Open, FileAccess.Read))
        {
            byte[] bytes = new byte[fs.Length];
            fs.Read(bytes, 0, bytes.Length);
            fs.Close();
            //用于记录当前读取了多少字节了
            int index = 0;

            //读取多少行数据
            int count = BitConverter.ToInt32(bytes, index);
            index += 4;

            //读取主键的名字
            int keyNameLength = BitConverter.ToInt32(bytes, index);
            index += 4;
            string keyName = Encoding.UTF8.GetString(bytes, index, keyNameLength);
            index += keyNameLength;

            //创建容器类对象
            Type contaninerType = typeof(T);
            object contaninerObj = Activator.CreateInstance(contaninerType);
            //得到数据结构类的Type
            Type classType = typeof(K);
            //通过反射 得到数据结构类 所有字段的信息
            FieldInfo[] infos = classType.GetFields();

            //读取每一行的信息
            for (int i = 0; i < count; i++)
            {
                //实例化一个数据结构类 对象
                object dataObj = Activator.CreateInstance(classType);
                foreach (FieldInfo info in infos)
                {
                    if( info.FieldType == typeof(int) )
                    {
                        //相当于就是把2进制数据转为int 然后赋值给了对应的字段
                        info.SetValue(dataObj, BitConverter.ToInt32(bytes, index));
                        index += 4;
                    }
                    else if (info.FieldType == typeof(float))
                    {
                        info.SetValue(dataObj, BitConverter.ToSingle(bytes, index));
                        index += 4;
                    }
                    else if (info.FieldType == typeof(bool))
                    {
                        info.SetValue(dataObj, BitConverter.ToBoolean(bytes, index));
                        index += 1;
                    }
                    else if (info.FieldType == typeof(string))
                    {
                        //读取字符串字节数组的长度
                        int length = BitConverter.ToInt32(bytes, index);
                        index += 4;
                        info.SetValue(dataObj, Encoding.UTF8.GetString(bytes, index, length));
                        index += length;
                    }
                }

                //读取完一行的数据了 应该把这个数据添加到容器对象中
                //得到容器对象中的 字典对象
                object dicObject = contaninerType.GetField("dataDic").GetValue(contaninerObj);
                //通过字典对象得到其中的 Add方法
                MethodInfo mInfo = dicObject.GetType().GetMethod("Add");
                //得到数据结构类对象中 指定主键字段的值
                object keyValue = classType.GetField(keyName).GetValue(dataObj);
                mInfo.Invoke(dicObject, new object[] { keyValue, dataObj });
            }

            //把读取完的表记录下来
            tableDic.Add(typeof(T).Name, contaninerObj);

            fs.Close();
        }
    }

    /// <summary>
    /// 得到一张表的信息
    /// </summary>
    /// <typeparam name="T">容器类名</typeparam>
    /// <returns></returns>
    public T GetTable<T>() where T:class
    {
        string tableName = typeof(T).Name;
        if (tableDic.ContainsKey(tableName))
            return tableDic[tableName] as T;
        return null;
    }

    /// <summary>
    /// 存储类对象数据
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="fileName"></param>
    public void Save(object obj, string fileName)
    {
        //先判断路径文件夹有没有
        if (!Directory.Exists(SAVE_PATH))
            Directory.CreateDirectory(SAVE_PATH);

        using (FileStream fs = new FileStream(SAVE_PATH + fileName + ".tao", FileMode.OpenOrCreate, FileAccess.Write))
        {
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(fs, obj);
            fs.Close();
        }
    }

    /// <summary>
    /// 读取2进制数据转换成对象
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="fileName"></param>
    /// <returns></returns>
    public T Load<T>(string fileName) where T:class
    {
        //如果不存在这个文件 就直接返回泛型对象的默认值
        if( !File.Exists(SAVE_PATH + fileName + ".tao") )
            return default(T);

        T obj;
        using (FileStream fs = File.Open(SAVE_PATH + fileName + ".tao", FileMode.Open, FileAccess.Read))
        {
            BinaryFormatter bf = new BinaryFormatter();
            obj = bf.Deserialize(fs) as T;
            fs.Close();
        }

        return obj;
    }
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏