7.选服面板和功能串联

  1. 7.选服面板
    1. 7.1 数据准备
      1. 拼接背景图片。左右各创建列表。各创建左右按钮作为资源。添加动效后发布。
    2. 7.2 知识点代码
      1. 查看Excel工具说明
      2. 在对应路径配置好服务器配置数据,点击生成按钮生产容器类和对应的数据结构类
      3. 在二进制数据管理器类添加初始化获得服务器数据的代码
        1. 在二进制数据管理器类添加初始化获得服务器数据的代码
    3. 7.3 左侧按钮功能
      1. 修改左侧按钮图片名字,重新发布代码才会生成对应的组件拖拽类。否则全是n什么什么的或者title、icon这种发布过后不会自动生成代码。修改后发布。
      2. 在左侧按钮脚本中添加开始结束区号变量。提供一个给外部使用的初始化左侧按钮区间的方法。点击当前按钮通知选服面板改变右侧的区间内容待补充。
    4. 7.4 右侧按钮功能
      1. 在右侧按钮脚本中添加服务器信息变量,代表当前按钮的服务器信息。点击当前按钮时记录选择的服务器ID,隐藏选服面板,显示服务器面板。提供根据外部传入的服务器数据来更新内容的方法,解析服务器数据让自己根据信息来显示
    5. 7.5 动态创建按钮
      1. 创建选服面板脚本
      2. 登录面板的点击登录按钮事件和显示时补充第一次登录实际显示选服面板的逻辑
      3. 重写选服面板脚本初始化方法。关联对应组件。通过得到服务器数据,动态创建左侧按钮。
      4. 选服面板脚本创建更新右侧按钮的方法,外部传入开始和结束id。设置服务器文本。删除之前右侧列表所有item。遍历得到服务器容器的字典中每个索引对应的服务器信息,动态创建按钮并传入服务器信息初始化
      5. 重写选服面板脚本显示方法。判断之前进入的服务器id是否为0,不为0从服务器容器中的字典拿数据,来刷新上方上次进入服务器的item。调用刷新右侧按钮方法。初始化是传入1-5区,不够区对应减少。
      6. 左侧按钮脚本中添加实际点击刷新右侧按钮的监听
    6. 7.6 功能串联
      1. 在右侧按钮点击事件中添加隐藏选服面板的实际操作
      2. 在服务器面板选服按钮点击事件中添加显示选服面板的实际操作
      3. 在服务器面板显示函数时通过得到当前选择的服务器id,读取服务器数据字典得到当前服务器数据,刷新显示
      4. 在登录管理器添加注册成功时清空登录相关的数据,让上次登录的服务器id为0,记住密码和自动登录清空,注册成功后调用
    7. 7.7 代码
      1. BinaryDataMgr
      2. UI_ServerLeftItem
      3. UI_ServerRightItem
      4. ServerChooseWindow
      5. ServerWindow
      6. LoginWindow
      7. LoginMgr

7.选服面板


7.1 数据准备

拼接背景图片。左右各创建列表。各创建左右按钮作为资源。添加动效后发布。


7.2 知识点代码

查看Excel工具说明

在对应路径配置好服务器配置数据,点击生成按钮生产容器类和对应的数据结构类


在二进制数据管理器类添加初始化获得服务器数据的代码

在二进制数据管理器类添加初始化获得服务器数据的代码

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

7.3 左侧按钮功能

修改左侧按钮图片名字,重新发布代码才会生成对应的组件拖拽类。否则全是n什么什么的或者title、icon这种发布过后不会自动生成代码。修改后发布。

在左侧按钮脚本中添加开始结束区号变量。提供一个给外部使用的初始化左侧按钮区间的方法。点击当前按钮通知选服面板改变右侧的区间内容待补充。

public partial class UI_ServerLeftItem : GButton
{
    public GImage m_imgBK;
    public const string URL = "ui://ffsx6r1gtwkm1h";

    //开始的区号
    private int beginIndex;
    //结束的区号
    private int endIndex;

    public static UI_ServerLeftItem CreateInstance()
    {
        return (UI_ServerLeftItem)UIPackage.CreateObject("Login", "ServerLeftItem");
    }

    public override void ConstructFromXML(XML xml)
    {
        base.ConstructFromXML(xml);

        m_imgBK = (GImage)GetChild("imgBK");

        this.onClick.Add(() =>
        {
            //通知选服面板 改变右侧的区间内容
        });
    }

    /// <summary>
    /// 提供给外部使用的初始化左侧按钮 区间的方法
    /// </summary>
    /// <param name="beginIndex"></param>
    /// <param name="endIndex"></param>
    public void InitInfo(int beginIndex, int endIndex)
    {
        //记录范围
        this.beginIndex = beginIndex;
        this.endIndex = endIndex;

        //改变按钮显示内容
        this.text = beginIndex + " - " + endIndex + "区";
    }

}

7.4 右侧按钮功能

在右侧按钮脚本中添加服务器信息变量,代表当前按钮的服务器信息。点击当前按钮时记录选择的服务器ID,隐藏选服面板,显示服务器面板。提供根据外部传入的服务器数据来更新内容的方法,解析服务器数据让自己根据信息来显示

public partial class UI_ServerRightItem : GButton
{
    public GImage m_imgNew;
    public const string URL = "ui://ffsx6r1gtwkm1i";

    //当前按钮 代表是哪一个服务器 记录服务器数据
    public ServerInfo nowServerInfo;

    public static UI_ServerRightItem CreateInstance()
    {
        return (UI_ServerRightItem)UIPackage.CreateObject("Login", "ServerRightItem");
    }

    public override void ConstructFromXML(XML xml)
    {
        base.ConstructFromXML(xml);

        m_imgNew = (GImage)GetChild("imgNew");

        //自己被点击时 做什么
        this.onClick.Add(() =>
        {
            //记录选择的服务器ID
            LoginMgr.Instance.loginData.frontServerID = nowServerInfo.id;

            //隐藏选服面板

            //显示服务器面板
            UIManager.Instance.ShowWindow<ServerWindow>();
        });
    }

    /// <summary>
    /// 根据外部传入的服务器数据 来更新内容
    /// </summary>
    /// <param name="info"></param>
    public void InitInfo(ServerInfo info)
    {
        //记录下数据
        this.nowServerInfo = info;

        //更新按钮上显示的服务器名
        this.text = info.id + "区" + info.name;

        //更新是否是新服
        m_imgNew.visible = info.isNew;

        //更新 当前的状态
        switch (info.state)
        {
            case 0://流畅
                this.icon = "ui://Login/ui_DL_liuchang_01";
                break;
            case 1://繁忙
                this.icon = "ui://Login/ui_DL_fanhua_01";
                break;
            case 2://火爆
                this.icon = "ui://Login/ui_DL_huobao_01";
                break;
            case 3://维护
                this.icon = "ui://Login/ui_DL_weihug_01";
                break;
        }
    }
}

7.5 动态创建按钮

创建选服面板脚本

public class ServerChooseWindow : Window
{
}

登录面板的点击登录按钮事件和显示时补充第一次登录实际显示选服面板的逻辑

//第一次登录 需要打开 选服面板
if (LoginMgr.Instance.loginData.frontServerID == 0)
{
    //打开选服面板
    UIManager.Instance.ShowWindow<ServerChooseWindow>();
}

重写选服面板脚本初始化方法。关联对应组件。通过得到服务器数据,动态创建左侧按钮。

protected override void OnInit()
{
    base.OnInit();
    
    //先关联对应组件
    this.contentPane = UIManager.Instance.LoadComponent("Login", "ServerChooseWindow");
    this.contentPane.MakeFullScreen();
    
    UI_ServerChooseWindow panel = this.contentPane as UI_ServerChooseWindow;
    
    //动态创建左侧 区间按钮
    
    //具体有多少条服务器数据
    int serverNum = BinaryDataMgr.Instance.GetTable<ServerInfoContainer>().dataDic.Count;
    
    //得到一共要循环创建多少个区间按钮
    //由于是向下取整 所以加1 就代表 平均分成了 num个按钮
    int num = serverNum / 5 + 1;
    
    //循环创建 左侧区间按钮
    for (int i = 0; i < num; i++)
    {
        //通过list的 缓存池方法 得到对象 创建
        UI_ServerLeftItem item = panel.m_listLeft.AddItemFromPool() as UI_ServerLeftItem;
        
        //初始化左侧创建的按钮
        //得到开始和结束索引
        int beginIndex = i * 5 + 1;//1 6
        int endIndex = 5 * (i + 1);//5 10
        //判断 最大 是不是超过了 服务器的总数
        if (endIndex > serverNum)
            endIndex = serverNum;
        item.InitInfo(beginIndex, endIndex);
    }
}

选服面板脚本创建更新右侧按钮的方法,外部传入开始和结束id。设置服务器文本。删除之前右侧列表所有item。遍历得到服务器容器的字典中每个索引对应的服务器信息,动态创建按钮并传入服务器信息初始化

/// <summary>
/// 更新右侧按钮信息 根据索引值 创建对应的服务器按钮
/// </summary>
/// <param name="beginIndex">开始id</param>
/// <param name="endIndex">结束ID</param>
public void UpdatePanel(int beginIndex, int endIndex)
{
    UI_ServerChooseWindow panel = this.contentPane as UI_ServerChooseWindow;
    //更新 服务器区间显示
    panel.m_txtRange.SetVar("string", "服务器" + beginIndex + " - " + endIndex);
    panel.m_txtRange.FlushVars();
    
    //创建之前 应该把老的按钮 删除了 
    //利用list中api 移除所有对象 放入缓存池
    panel.m_listRight.RemoveChildrenToPool();
    
    //第二步:创建新的按钮
    ServerInfoContainer serverInfoContainer = BinaryDataMgr.Instance.GetTable<ServerInfoContainer>();
    for (int i = beginIndex; i <= endIndex; i++)
    {
        //根据id获取服务器数据 创建按钮 初始化
        ServerInfo nowInfo = serverInfoContainer.dataDic[i];
        
        //动态创建右侧按钮
        UI_ServerRightItem item = panel.m_listRight.AddItemFromPool() as UI_ServerRightItem;
        item.InitInfo(nowInfo);
    }
}

重写选服面板脚本显示方法。判断之前进入的服务器id是否为0,不为0从服务器容器中的字典拿数据,来刷新上方上次进入服务器的item。调用刷新右侧按钮方法。初始化是传入1-5区,不够区对应减少。

protected override void OnShown()
{
    base.OnShown();
    //处理 动态更新信息的内容
    UI_ServerChooseWindow panel = this.contentPane as UI_ServerChooseWindow;
    //第一:上方信息
    int id = LoginMgr.Instance.loginData.frontServerID;
    if(id == 0)
    {
        //为0代表没有选择过任何服务器
        panel.m_txtName.text = "无";
        panel.m_imgState.visible = false;
    }
    else
    {
        //不为0根据ID得到服务器数据 然后进行更新
        //得到服务器数据
        ServerInfo info = BinaryDataMgr.Instance.GetTable<ServerInfoContainer>().dataDic[id];
        //更新上一次登录的服务器名字
        panel.m_txtName.text = info.id + "区  " + info.name;
        //显示状态装载器
        panel.m_imgState.visible = true;
        //更新 当前的状态
        switch (info.state)
        {
            case 0://流畅
                panel.m_imgState.url = "ui://Login/ui_DL_liuchang_01";
                break;
            case 1://繁忙
                panel.m_imgState.url = "ui://Login/ui_DL_fanhua_01";
                break;
            case 2://火爆
                panel.m_imgState.url = "ui://Login/ui_DL_huobao_01";
                break;
            case 3://维护
                panel.m_imgState.url = "ui://Login/ui_DL_weihu_01";
                break;
        }
    }
    
    //第二:右侧按钮信息
    int serverNum = BinaryDataMgr.Instance.GetTable<ServerInfoContainer>().dataDic.Count;
    UpdatePanel(1, 5 > serverNum ? serverNum : 5);
}

左侧按钮脚本中添加实际点击刷新右侧按钮的监听

this.onClick.Add(()=> {
    
    //通知选服面板 改变右侧的区间内容嘛
    ServerChooseWindow panel = UIManager.Instance.GetWindow<ServerChooseWindow>();
    panel.UpdatePanel(beignIndex, endIndex);
});

7.6 功能串联

在右侧按钮点击事件中添加隐藏选服面板的实际操作

//自己被点击时 做什么
this.onClick.Add(() =>
{
    //记录选择的服务器ID
    LoginMgr.Instance.loginData.frontServerID = nowServerInfo.id;

    //隐藏选服面板
    UIManager.Instance.HideWindow<ServerChooseWindow>();

    //显示服务器面板
    UIManager.Instance.ShowWindow<ServerWindow>();
});

在服务器面板选服按钮点击事件中添加显示选服面板的实际操作

//点击换区按钮 点击做什么
panel.m_btnChange.onClick.Add(()=> {
    //有了服务器选择面板 才能做
    //显示选服面板
    UIManager.Instance.ShowWindow<ServerChooseWindow>();
    //隐藏自己
    UIManager.Instance.HideWindow<ServerWindow>();
});

在服务器面板显示函数时通过得到当前选择的服务器id,读取服务器数据字典得到当前服务器数据,刷新显示

protected override void OnShown()
{
    base.OnShown();
    //处理 服务器当前名字内容
    int id = LoginMgr.Instance.loginData.frontServerID;
    UI_ServerWindow panel = this.contentPane as UI_ServerWindow;
    if (id == 0)
    {
        panel.m_txtName.text = "无选择";
    }
    else
    {
        //读取服务器数据表 进行名字的更新
        ServerInfo info = BinaryDataMgr.Instance.GetTable<ServerInfoContainer>().dataDic[id];
        panel.m_txtName.text = info.id + "区 " + info.name;
    }
}

在登录管理器添加注册成功时清空登录相关的数据,让上次登录的服务器id为0,记住密码和自动登录清空,注册成功后调用

/// <summary>
/// 用于注册时 清除上一个玩家记录的一些关键信息
/// </summary>
public void ClearLoginData()
{
    loginData.frontServerID = 0;
    loginData.autoLogin = false;
    loginData.rememberPw = false;
}

/// <summary>
/// 注册用户方法
/// </summary>
/// <param name="userName">用户名</param>
/// <param name="passWord">密码</param>
/// <returns>true注册成功 false 注册失败</returns>
public bool RegisterUser(string userName, string passWord)
{
    //判断是否有同名账号
    if(registerData.registerDic.ContainsKey(userName))
    {
        return false;
    }

    //如果没有重名 那么直接注册
    registerData.registerDic.Add(userName, passWord);
    //本地存储
    SaveRegisterData();

    //注册成功 情况登录相关的一些数据
    ClearLoginData();

    //注册成功
    return true;
}

7.7 代码

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;
    }
}

UI_ServerLeftItem

/** This is an automatically generated class by FairyGUI. Please do not modify it. **/

using FairyGUI;
using FairyGUI.Utils;

namespace Login
{
    public partial class UI_ServerLeftItem : GButton
    {
        public GImage m_imgBK;
        public const string URL = "ui://ffsx6r1gtwkm1h";

        //开始的区号
        private int beignIndex;
        //结束的区号
        private int endIndex;

        public static UI_ServerLeftItem CreateInstance()
        {
            return (UI_ServerLeftItem)UIPackage.CreateObject("Login", "ServerLeftItem");
        }

        public override void ConstructFromXML(XML xml)
        {
            base.ConstructFromXML(xml);

            m_imgBK = (GImage)GetChild("imgBK");

            this.onClick.Add(()=> {

                //通知选服面板 改变右侧的区间内容嘛
                ServerChooseWindow panel = UIManager.Instance.GetWindow<ServerChooseWindow>();
                panel.UpdatePanel(beignIndex, endIndex);
            });
        }

        /// <summary>
        /// 提供给外部使用的初始化左侧按钮 区间的方法
        /// </summary>
        /// <param name="beginIndex"></param>
        /// <param name="endIndex"></param>
        public void InitInfo(int beginIndex, int endIndex)
        {
            //记录范围
            this.beignIndex = beginIndex;
            this.endIndex = endIndex;

            //改变按钮显示内容
            this.text = beginIndex + " - " + endIndex + "区";
        }

    }
}

UI_ServerRightItem

/** This is an automatically generated class by FairyGUI. Please do not modify it. **/

using FairyGUI;
using FairyGUI.Utils;

namespace Login
{
    public partial class UI_ServerRightItem : GButton
    {
        public GImage m_imgNew;
        public const string URL = "ui://ffsx6r1gtwkm1i";

        //当前按钮 代表是哪一个服务器 记录服务器数据
        public ServerInfo nowServerInfo;

        public static UI_ServerRightItem CreateInstance()
        {
            return (UI_ServerRightItem)UIPackage.CreateObject("Login", "ServerRightItem");
        }

        public override void ConstructFromXML(XML xml)
        {
            base.ConstructFromXML(xml);

            m_imgNew = (GImage)GetChild("imgNew");

            //自己被点击时 做什么
            this.onClick.Add(() =>
            {
                //记录选择的服务器ID
                LoginMgr.Instance.loginData.frontServerID = nowServerInfo.id;

                //隐藏选服面板
                UIManager.Instance.HideWindow<ServerChooseWindow>();

                //显示服务器面板
                UIManager.Instance.ShowWindow<ServerWindow>();
            });
        }

        /// <summary>
        /// 根据外部传入的服务器数据 来更新内容
        /// </summary>
        /// <param name="info"></param>
        public void InitInfo(ServerInfo info)
        {
            //记录下数据
            this.nowServerInfo = info;

            //更新按钮上显示的服务器名
            this.text = info.id + "区" + info.name;

            //更新是否是新服
            m_imgNew.visible = info.isNew;

            //更新 当前的状态
            switch (info.state)
            {
                case 0://流畅
                    this.icon = "ui://Login/ui_DL_liuchang_01";
                    break;
                case 1://繁忙
                    this.icon = "ui://Login/ui_DL_fanhua_01";
                    break;
                case 2://火爆
                    this.icon = "ui://Login/ui_DL_huobao_01";
                    break;
                case 3://维护
                    this.icon = "ui://Login/ui_DL_weihu_01";
                    break;
            }
        }
    }
}

ServerChooseWindow

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

public class ServerChooseWindow : Window
{
    protected override void OnInit()
    {
        base.OnInit();

        //先关联对应组件
        this.contentPane = UIManager.Instance.LoadComponent("Login", "ServerChooseWindow");
        this.contentPane.MakeFullScreen();

        UI_ServerChooseWindow panel = this.contentPane as UI_ServerChooseWindow;

        //动态创建左侧 区间按钮

        //具体有多少条服务器数据
        int serverNum = BinaryDataMgr.Instance.GetTable<ServerInfoContainer>().dataDic.Count;

        //得到一共要循环创建多少个区间按钮
        //由于是向下取整 所以加1 就代表 平均分成了 num个按钮
        int num = serverNum / 5 + 1;

        //循环创建 左侧区间按钮
        for (int i = 0; i < num; i++)
        {
            //通过list的 缓存池方法 得到对象 创建
            UI_ServerLeftItem item = panel.m_listLeft.AddItemFromPool() as UI_ServerLeftItem;

            //初始化左侧创建的按钮
            //得到开始和结束索引
            int beginIndex = i * 5 + 1;//1 6
            int endIndex = 5 * (i + 1);//5 10
            //判断 最大 是不是超过了 服务器的总数
            if (endIndex > serverNum)
                endIndex = serverNum;
            item.InitInfo(beginIndex, endIndex);
        }
    }

    protected override void OnShown()
    {
        base.OnShown();
        //处理 动态更新信息的内容
        UI_ServerChooseWindow panel = this.contentPane as UI_ServerChooseWindow;
        //第一:上方信息
        int id = LoginMgr.Instance.loginData.frontServerID;
        if(id == 0)
        {
            //为0代表没有选择过任何服务器
            panel.m_txtName.text = "无";
            panel.m_imgState.visible = false;
        }
        else
        {
            //不为0根据ID得到服务器数据 然后进行更新
            //得到服务器数据
            ServerInfo info = BinaryDataMgr.Instance.GetTable<ServerInfoContainer>().dataDic[id];
            //更新上一次登录的服务器名字
            panel.m_txtName.text = info.id + "区  " + info.name;
            //显示状态装载器
            panel.m_imgState.visible = true;
            //更新 当前的状态
            switch (info.state)
            {
                case 0://流畅
                    panel.m_imgState.url = "ui://Login/ui_DL_liuchang_01";
                    break;
                case 1://繁忙
                    panel.m_imgState.url = "ui://Login/ui_DL_fanhua_01";
                    break;
                case 2://火爆
                    panel.m_imgState.url = "ui://Login/ui_DL_huobao_01";
                    break;
                case 3://维护
                    panel.m_imgState.url = "ui://Login/ui_DL_weihu_01";
                    break;
            }
        }

        //第二:右侧按钮信息
        int serverNum = BinaryDataMgr.Instance.GetTable<ServerInfoContainer>().dataDic.Count;
        UpdatePanel(1, 5 > serverNum ? serverNum : 5);
    }

    /// <summary>
    /// 更新右侧按钮信息 根据索引值 创建对应的服务器按钮
    /// </summary>
    /// <param name="beginIndex">开始id</param>
    /// <param name="endIndex">结束ID</param>
    public void UpdatePanel(int beginIndex, int endIndex)
    {
        UI_ServerChooseWindow panel = this.contentPane as UI_ServerChooseWindow;
        //更新 服务器区间显示
        panel.m_txtRange.SetVar("string", "服务器" + beginIndex + " - " + endIndex);
        panel.m_txtRange.FlushVars();

        //创建之前 应该把老的按钮 删除了 
        //利用list中api 移除所有对象 放入缓存池
        panel.m_listRight.RemoveChildrenToPool();

        //第二步:创建新的按钮
        ServerInfoContainer serverInfoContainer = BinaryDataMgr.Instance.GetTable<ServerInfoContainer>();
        for (int i = beginIndex; i <= endIndex; i++)
        {
            //根据id获取服务器数据 创建按钮 初始化
            ServerInfo nowInfo = serverInfoContainer.dataDic[i];

            //动态创建右侧按钮
            UI_ServerRightItem item = panel.m_listRight.AddItemFromPool() as UI_ServerRightItem;
            item.InitInfo(nowInfo);
        }
    }

    protected override void DoShowAnimation()
    {
        base.DoShowAnimation();
        this.contentPane.GetTransition("show").Play();
    }

    protected override void DoHideAnimation()
    {
        this.contentPane.GetTransition("hide").Play(base.DoHideAnimation);
    }
}

ServerWindow

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

public class ServerWindow : Window
{
    protected override void OnInit()
    {
        base.OnInit();

        this.contentPane = UIManager.Instance.LoadComponent("Login", "ServerWindow");
        this.contentPane.MakeFullScreen();

        UI_ServerWindow panel = this.contentPane as UI_ServerWindow;
        //进入游戏按钮 点击做什么
        panel.m_btnBegin.onClick.Add(()=> {

            //保存登录数据
            LoginMgr.Instance.SaveLoginData();

            //隐藏所有的面板
            UIManager.Instance.ClearWindow(true);

            //切场景
            SceneManager.LoadScene("GameScene");
        });

        //点击换区按钮 点击做什么
        panel.m_btnChange.onClick.Add(()=> {
            //有了服务器选择面板 才能做
            //显示选服面板
            UIManager.Instance.ShowWindow<ServerChooseWindow>();
            //隐藏自己
            UIManager.Instance.HideWindow<ServerWindow>();
        });

        //返回按钮 点击做什么
        panel.m_btnClose.onClick.Add(() => {

            //避免自动登录勾选时 返回了登录界面 又会回到服务器界面 
            //所以返回登录界面之前 我们把自动登录 改成false
            LoginMgr.Instance.loginData.autoLogin = false;

            //显示登录面板
            UIManager.Instance.ShowWindow<LoginWindow>();
            //隐藏自己
            UIManager.Instance.HideWindow<ServerWindow>();
        });
    }


    protected override void OnShown()
    {
        base.OnShown();
        //处理 服务器当前名字内容
        int id = LoginMgr.Instance.loginData.frontServerID;
        UI_ServerWindow panel = this.contentPane as UI_ServerWindow;
        if (id == 0)
        {
            panel.m_txtName.text = "无选择";
        }
        else
        {
            //读取服务器数据表 进行名字的更新
            ServerInfo info = BinaryDataMgr.Instance.GetTable<ServerInfoContainer>().dataDic[id];
            panel.m_txtName.text = info.id + "区 " + info.name;
        }
    }

    protected override void DoShowAnimation()
    {
        base.DoShowAnimation();
        this.contentPane.GetTransition("show").Play();
    }

    protected override void DoHideAnimation()
    {
        this.contentPane.GetTransition("hide").Play(base.DoHideAnimation);
    }
}

LoginWindow

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

public class LoginWindow : Window
{
    protected override void OnInit()
    {
        base.OnInit();

        this.contentPane = UIManager.Instance.LoadComponent("Login", "LoginWindow");
        this.contentPane.MakeFullScreen();

        //得到组件拓展类对象
        UI_LoginWindow panel = this.contentPane as UI_LoginWindow;

        //确定按钮点击后 做什么
        panel.m_btnSure.onClick.Add(() => { 
            //判断 输入内容的合法性
            if( panel.m_inputAN.text.Length <= 6 ||
                panel.m_inputPW.text.Length <= 3)
            {
                UIManager.Instance.ShowWindow<TipWindow>().ChangeInfo("账号必须大于6位,密码必须大于3位");
                return;
            }

            //验证用户名和密码 是否输入正确
            //之后完成了注册功能 再回过头来写
            if( LoginMgr.Instance.CheckInfo(panel.m_inputAN.text, panel.m_inputPW.text) )
            {
                //登录成功
                //记录登录相关数据
                //记录账号和密码数据
                LoginMgr.Instance.loginData.userName = panel.m_inputAN.text;
                LoginMgr.Instance.loginData.passWord = panel.m_inputPW.text;
                //记录两个复选按钮选中情况
                LoginMgr.Instance.loginData.rememberPw = panel.m_cbPW.selected;
                LoginMgr.Instance.loginData.autoLogin = panel.m_cbAuto.selected;
                //保存到本地 下一次运行游戏时
                LoginMgr.Instance.SaveLoginData();

                //决定打开哪个面板
                //第一次登录 需要打开 选服面板
                if( LoginMgr.Instance.loginData.frontServerID == 0 )
                {
                    //打开选服面板
                    UIManager.Instance.ShowWindow<ServerChooseWindow>();
                }
                else
                {
                    //打开服务器面板
                    UIManager.Instance.ShowWindow<ServerWindow>();
                }

                //隐藏自己
                UIManager.Instance.HideWindow<LoginWindow>();
            }
            else
            {
                //登录失败
                UIManager.Instance.ShowWindow<TipWindow>().ChangeInfo("账号或密码错位");
            }
        });

        //注册按钮点击后 做什么
        panel.m_btnRe.onClick.Add(()=> {
            //显示注册面板
            UIManager.Instance.ShowWindow<RegisterWindow>();
            //隐藏自己
            UIManager.Instance.HideWindow<LoginWindow>();
        });

        //当记住密码状态改变时 做什么
        panel.m_cbPW.onChanged.Add(()=> {
            //记住密码取消勾选时 强行取消勾选自动登录
            if (!panel.m_cbPW.selected)
                panel.m_cbAuto.selected = false;
        });

        //当自动登录时 做什么
        panel.m_cbAuto.onChanged.Add(() =>
        {
            //自动登录勾选上 强行勾选上 记住密码
            if (panel.m_cbAuto.selected)
                panel.m_cbPW.selected = true;

        });
    }

    /// <summary>
    /// 显示时会自动调用的方法
    /// </summary>
    protected override void OnShown()
    {
        base.OnShown();
        //初始化面板基础内容
        //得到登录相关数据
        LoginData data = LoginMgr.Instance.loginData;

        //得到组件拓展类对象
        UI_LoginWindow panel = this.contentPane as UI_LoginWindow;
        //两个复选按钮 是否选中
        panel.m_cbPW.selected = data.rememberPw;
        panel.m_cbAuto.selected = data.autoLogin;

        //账号密码 显示的内容
        panel.m_inputAN.text = data.userName;
        panel.m_inputPW.text = data.passWord;

        //如果需要自动登录 
        if(data.autoLogin)
        {
            //之后完成了注册功能 再回过头来写 自动登录
            //验证用户名和密码 是否输入正确
            //之后完成了注册功能 再回过头来写
            if (LoginMgr.Instance.CheckInfo(panel.m_inputAN.text, panel.m_inputPW.text))
            {
                //决定打开哪个面板
                //第一次登录 需要打开 选服面板
                if (LoginMgr.Instance.loginData.frontServerID == 0)
                {
                    //打开选服面板
                    UIManager.Instance.ShowWindow<ServerChooseWindow>();
                }
                else
                {
                    //打开服务器面板
                    UIManager.Instance.ShowWindow<ServerWindow>();
                }

                //隐藏自己
                UIManager.Instance.HideWindow<LoginWindow>();
            }
            else
            {
                //登录失败
                UIManager.Instance.ShowWindow<TipWindow>().ChangeInfo("账号或密码错位");
            }
        }
    }

    /// <summary>
    /// 提供给外部设置账号和密码输入框内容的方法
    /// </summary>
    /// <param name="userName"></param>
    /// <param name="passWord"></param>
    public void SetInfo(string userName, string passWord)
    {
        UI_LoginWindow panel = this.contentPane as UI_LoginWindow;
        panel.m_inputAN.text = userName;
        panel.m_inputPW.text = passWord;
    }

    protected override void DoShowAnimation()
    {
        base.DoShowAnimation();
        this.contentPane.GetTransition("show").invalidateBatchingEveryFrame = true;
        this.contentPane.GetTransition("show").Play();
    }

    protected override void DoHideAnimation()
    {
        this.contentPane.GetTransition("hide").Play(base.DoHideAnimation);
    }
}

LoginMgr

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 用于管理登录相关数据的管理器
/// </summary>
public class LoginMgr 
{
    private static LoginMgr instance = new LoginMgr();
    public static LoginMgr Instance => instance;

    //登录数据对象
    public LoginData loginData;

    //注册数据对象
    private RegisterData registerData;

    private LoginMgr()
    {
        loginData = BinaryDataMgr.Instance.Load<LoginData>("LoginData");
        if (loginData == null)
            loginData = new LoginData();

        //从本地得到注册数据 如果没有得到 那么证明没有 直接new一个 数据即可
        registerData = BinaryDataMgr.Instance.Load<RegisterData>("RegisterData");
        if (registerData == null)
            registerData = new RegisterData();
    }

    /// <summary>
    /// 存储登录数据2进制文件到本地
    /// </summary>
    public void SaveLoginData()
    {
        BinaryDataMgr.Instance.Save(loginData, "LoginData");
    }

    /// <summary>
    /// 存储注册相关数据2进制到本地
    /// </summary>
    public void SaveRegisterData()
    {
        BinaryDataMgr.Instance.Save(registerData, "RegisterData");
    }

    /// <summary>
    /// 注册用户方法
    /// </summary>
    /// <param name="userName">用户名</param>
    /// <param name="passWord">密码</param>
    /// <returns>true注册成功 false 注册失败</returns>
    public bool RegisterUser(string userName, string passWord)
    {
        //判断是否有同名账号
        if(registerData.registerDic.ContainsKey(userName))
        {
            return false;
        }

        //如果没有重名 那么直接注册
        registerData.registerDic.Add(userName, passWord);
        //本地存储
        SaveRegisterData();

        //注册成功 情况登录相关的一些数据
        ClearLoginData();

        //注册成功
        return true;
    }

    /// <summary>
    /// 验证登录是否成功的方法
    /// </summary>
    /// <param name="userName"></param>
    /// <param name="passWord"></param>
    /// <returns></returns>
    public bool CheckInfo(string userName, string passWord)
    {
        //首先判断有没有这个用户
        if(registerData.registerDic.ContainsKey(userName))
        {
            //密码是否相同
            if(registerData.registerDic[userName] == passWord)
            {
                return true;
            }
        }
        //用户名和密码至少有一个不合法
        return false;
    }


    /// <summary>
    /// 用于注册时 清楚上一个玩家记录的一些关键信息
    /// </summary>
    public void ClearLoginData()
    {
        loginData.frontServerID = 0;
        loginData.autoLogin = false;
        loginData.rememberPw = false;
    }
}


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

×

喜欢就点赞,疼爱就打赏