UGUI相关使用

UGUI

1.六大基础组件概述

六大基础组件有哪些:
Canvas对象上依附的:

  • 1.Canvas:画布,用于渲染UI控件
  • 2.Canvas Scaler:画布分辨率自适应
  • 3.Graphic Raycaster:射线事件交互
  • 4.RectTransform:UI对象位置锚点控制,控制位置和对齐方式
    EventSystem对象上依附的:
  • 5.EventSystem:玩家输入事件响应
  • 6.Standalone Input Module:独立输入模块

UGUI是Unity引擎自带的GUI系统,对初学者十分重要,让我们一起来学习UGUI吧。

1.1 Canvas组件

作用:画布。其子对象渲染的根本。
重点知识

  • 1.场景中可以存在多个canvas,分别管理各自UI的显示参数

Render Mode参数解析;

  • 1.Screen Space - Overlay覆盖模式,UI始终在前。
    – a.Pixel Perfect:是否开启无锯齿精确渲染(性能换效果)
    – b.Sort Order:渲染顺序,越后渲染图层越上。
    – c.Target Display:目标显示屏幕。
  • 2.Screen Space - Camera摄像机模式,3D物体显示在UI之前。
    – a.Render Camera:用于渲染UI的摄像机(不建议设置主摄像机)
    – b.Plane Distance:UI在平面距离摄像机的距离。
    一般情况下,单独独立出一个摄像机管理UI。
  • 3.World Space:世界空间,3D模式。主要用于VR,AR。
    一般情况下,该模式下可以关联主摄像机。

1.2 CanvasScaler组件

作用:在不同分辨率下UI控件大小的自适应。不负责位置!位置由之后的RectTransform组件控制。

屏幕分辨率
屏幕分辨率 = 画布尺寸 * 缩放系数
参考分辨率Reference Resolution
在缩放模式的宽高模式中出现的参数,参与分辨率自适应计算。
分辨率大小自适应
通过一定的算法 以 屏幕分辨率参考分辨率 参与计算得出 缩放系数,该结果会影响所有UI控制的缩放大小。

UI Scale Mode参数解析

  • 1.Constant Pixel Size:恒定像素模式,UI大小始终不变。
    – a.图片的尺寸计算:UI原始尺寸 = 图片大小(像素) / (Pixels Per Unit / Reference Pixels Per Unit)
  • 2.Scale With Screen Size:”缩放模式,根据屏幕尺寸进行缩放。
    – a.Expand:水平或垂直拓展画布区域,可能有黑边。最大程度的缩小UI元素,保证都能装下所有UI。该模式下一般会比参考分辨率大,以便展示UI的全部细节。
    – b.Shrink:水平或垂直收缩画布区域,可以有裁剪。最大程度的方法UI元素,该模式下一般会比参考分辨率小,以便使画面填满屏幕。
    – c.Match Width Or Height:用于只有横屏(match = 1)或竖屏模式(match = 0)的游戏。
  • 3.Constant Physical Size:恒定物理模式,UI元素始终保持相同物理大小。
  • 4.3D模式:当Scale中设为 World Space时。该组件中自动变为 World模式,即为3D模式。
    – a.Dynamic Pixels Per Unit:UI中动态创建的位图中,单位像素数(密度)。适当增大该值可以使其上UI组件显示更清晰。

1.3 Graphic Raycaster组件

作用:图形射线投射器,检测UI输入事件的涉嫌发射器,负责通过射线检测玩家和UI元素的交互,判断是否点击到了UI元素。

参数解析

  • 1.Ignore Reversed Graphics:是否忽略反转图型
  • 2.Blocking Objects:射线被哪些类型的碰撞器阻挡(覆盖渲染下无效)
  • 3.Blocking Mask:射线被哪些层级的碰撞器阻挡(覆盖模式下无效)

1.4 Event System组件

作用:事件系统,管理玩家输入事件分发给各UI组件。所有UI事件都通过该组件中轮询检测并做相应的执行。
参数解析

  • 1.First Selected:首先选择的游戏对象
  • 2.Send Navigation Events:是否允许导航事件(键盘移动选择)
  • 3.Drag Threshold:拖拽阈值,移动多少像素算拖拽

1.5 Standalone Input Module组件

作用:独立输入模块
参数解析
在这里插入图片描述
该模块一般不做修改,默认值即可,用于关联Input Manager配合接收用户输入。

1.6 RectTransform组件

作用:专门用来管理UI的位置大小相关组件,在Transform的基础上(继承)加入了矩形相关,引入了中心点,锚点,长宽等属性。

参数解析

  • 1Pivot:轴心点位置,旋转绕轴心点。
  • 2.Anchors:相对于父矩形锚点。max和min取值范围都为0~1。
  • 3.Pos(X,Y,Z):轴心点相对锚点的位置
  • 4.Width/Height:宽高
  • 5.Left/Top/Right/Button:矩形边相对于锚点的位置
  • 6.Blueprint Mode:蓝图模式,编辑旋转和缩放不会影响矩形
  • 7.Raw Edit Mode:原始编辑模式,改变轴心和锚点值不会改变矩形位置
  • 8.快捷设置锚点轴心点以及UI位置(左上)。

2.三大基础控件概述

2.1 图像控件Image

参数解析

  • 1.Source Image:必须是“精灵Sprite”类型。
  • 2.Image Type
    – a.Simple:普通模式,均匀缩放整个图片
    – b.Sliced:切片模式,只拉伸九宫格中间的区域,防止其余部分被拉伸变形。
    –c.Tiled:平铺模式,会重复最基础的图像操作重复填充中央部分
    – d.Filled:填充模式,扇形,圆形,条形填充,适合做血条或经验条…
  • 3.Use Sprite Mesh:使用精灵网格
  • 4.Preserve Aspect:确保图像保持现有尺寸
  • 5.Set Native Size:设置图片资源原始大小

2.2 文本控件Text

参数解析

  • 1.Line Spacing:行之间的垂直间距
  • 2.Horizontal Overflow
    – a.Wrap:包裹模式,字体始终在举行范围内,超出后自动换行
    – b.Overflow:溢出模式,字体可以溢出矩形框
  • 3.Vertical Overflow:同理。
  • 4.富文本写法:(注意勾选rich text)
    在这里插入图片描述
  • 5.给文字加边缘线或阴影:
    给字体加上Outline或者Shadow组件。

2.3 RawImage原始图像组件

与Image区别:主要用于显示大图(背景图),不需要打入图集的图片,网络下载图片等等。

3.七大组合控件

3.1 Button组件

参数解析

  • 1.Interaction:是否开启按钮交互
  • 2.Trasition
    – a.None:无任何点击状态改变
    – b.Color Tint:不同状态的切换有颜色反馈
    – c.Sprite Swap:不同状态的切换有图片反馈
    – d.Animation:不同状态的切换有动画反馈
  • 3.··Navigation``:导航功能(键盘操作选中按钮)

按钮事件添加
可拖入脚本对象但不建议,按钮繁多时浪费时间,建议采用代码的方式加入监听事件。

//获取到按钮组件btn
btn.onClick.AddListener(ClickBtn);

//事件方法
private void ClickBtn()
{
    
    
	print("按钮点击,通过代码的方式");
}

//也可以通过匿名函数或Lambda表达式
btn.onClick.AddListener(() => {
    
    ...})

补充:做UI之前必须先修改Canvas上的内容并且创建一个父类型的画板,改为自适应多类型屏幕大小,否则后期不好改!!!

3.2 Toggle组件

概念:开关对象,处理玩家单选框以及多选框的关键组件。
参数详解

  • 1.Is On:当前的选中状态
  • 2.Graphic:选中时显示的图片
  • 3.Group:单选框分组实现:
    – a.将单选框分组挂载在父对象上,将其一组的单选框关联即可。
    – b.具体操作流程:创建一个父对象ToggleGroup,添加Toggle Group组件。将父节点拖入Toggle中的Group即可。
  • 4.Allow Switch off:允许不选择任何一个单选框

选项框事件与按钮事件类似,此处不多做赘述,关注如果使用带参数事件函数,需要注意在拖入选择时选择动态参数的函数,不是静态!

3.3 InputField组件

参数详解

  • 1.Content Type:输入类型限制
    在这里插入图片描述
    2.其他参数:
    在这里插入图片描述

3.4 Slider滑动条组件

参数解析
在这里插入图片描述

3.5 ScrollBar滚动条组件

参数解析
在这里插入图片描述

3.6 ScrollView滚动视图组件

参数解析
在这里插入图片描述

补充:如果不需要进度条的显示,可以手动删除进度条对象,但一定注意在原对象中将其关联的属性滞空,并调整内容大小以致较舒适的范畴。
代码应用

//获取组件
ScrollRect sr = this.GetComponent<ScrollRect>();
//设置相对位置
sr.normalizedPosition = new Vector2(0, 0.5f);

3.7 DropDown下拉列表组件

参数详解
在这里插入图片描述

4.图集

Q:为什么要打图集
A:目的是减少DC(DrawCall),提高性能。

Q:什么是DC?
A:DC是CPU通知GPU进行一次渲染的命令,如果DC次数较多会导致游戏卡顿,我们可以通过打图集,将小图合成大图,将本应n次DC变成1次来提高性能。

Unity中打图集操作的使用

  • 1.开启打图集功能方式:
    Edit ---> Project Setting ---> Editor ---> Sprite Packer
  • 2.在资源中新建一个图集 SpriteAtlas,UI中建议取消勾选 Allow RotationTight Packing。并加入图片素材并打包即可。
  • 3.代码控制
SpriteAtlas sa = Resources.Load<SpriteAtlas>("路径名字");
sa.GetSprite("图片名");

5.UGUI进阶

5.1 事件接口

概述:目前所有控件都只提供了常用的事件监听列表,如果想实现一些类似长按,双击,拖拽等功能是无法制作的。于此我们引入事件接口的概念,让其能处理更多逻辑。

常用事件接口介绍
在这里插入图片描述
代码实例

public class Test : MonoBehaviour, IPointerEnterHandler
{
    
    
	public void OnPointerEnter(PointerEventData eventData)
	{
    
    
		print("鼠标进入");
	}
}

参数BaseEventData父类详解
常用参数:

在这里插入图片描述

5.2 EventTrigger事件触发器

概念:继承了许多事件接口的组件。
代码添加事件触发器
(案例:在某组件上添加鼠标抬起事件)

//声明一个希望监听的事件对象
EventTrigger.Entry entry = new EventTrigger.Entry();
//申明 事件的类型
entry.eventID = EventTriggerType.PointerUp;
//监听事件关联
entry.callback.AddListener((data) => {
    
    
	print("抬起");
});
//加入到EventTrigger
et.triggers.Add(entry);

总结:对对象的管理更加面向对象,减少了自己实现接口的步骤。

实例:配合拖拽事件实现遥感功能

public void OnDrag(PointerEventData eventData)
{
    
    
	//设置引用对象作为参数nowPos
	Vector2 nowPos;
	//将屏幕坐标转换为UI本地坐标
	//参数一:相对父对象
	//参数二:屏幕点
	//参数三:摄像机
	//参数四:最终得到的点
	RectTransformUtility.ScreenPointToLocalPointInRectangle(
		this.transform.parent as RectTransform,
		eventData.position,
		eventData.enterEventCamera,
		out nowPos
	);
	//将当前物体坐标设置为拖拽位置
	this.transform.localPosition = nowPos;
}

5.3 Mask遮罩

使用

  • 1.通过在父对象上添加Mask组件即可遮罩子对象
  • 2.想要被遮罩的Image需要勾选 Maskable
  • 3.只要父对象添加了Mask组件,那么所有UI子对象都会被遮罩
  • 4.遮罩父对象的图片制作,不透明的地方显示,透明的地方遮罩

5.4 自动布局组件

水平布局组件
在这里插入图片描述
网格布局组件
在这里插入图片描述
内容大小适配器
在这里插入图片描述
宽高比适配器

在这里插入图片描述

5.5 Canvas Group组

在这里插入图片描述

6.UGUI实战

6.1 需求分析

流程图:
在这里插入图片描述
类图分析:
遵循一个面板一个类,使用基类书写统一逻辑,以及一个UI管理器,一个登录管理器。

6.2 准备工作

1.新建Unity项目。
2.导入Json管理器工具。
3.创建重要文件夹。

  • 1.Resources
  • 2.Scripts
  • 3.StreamingAssets
  • 4.ArtRes
    4.导入资源。
    5.新建UI场景,引入必要的 EventSystemCanvas对象,将Canvas的渲染模式改为摄像机模式,并关联一个新建的UI摄像机,设置其仅渲染UI层,并将Clear Flags改为Depth only,并删除Audio Listener组件,将默认背景改为空,并取消主摄像机的UI渲染。
    6.设置画布的自适应(根据美术素材),横屏游戏将适应值拖为1。

6.3 UI基类逻辑

实现功能分析:显示自己,隐藏自己,淡入淡出。

using UnityEngine.Events;

//因为该类不会被初始化,是被子类继承来使用,故可使用抽象类
public abstract class BasePanel : MonoBehaviour
{
    
    
    //整体控制淡入淡出的画布组件
    private CanvasGroup canvasGroup;
    //淡入淡出的速度
    private float alphaSpeed = 10;
    //检测组件是否被显示
    private bool isShow;

    //淡出面板后执行的逻辑
    private UnityAction hideCallBack;


    void Awake()
    {
    
    
        //拿到子类对应的画布组件
        canvasGroup = GetComponent<CanvasGroup>();
        //如果没拿到添加组件
        if (canvasGroup == null)
        {
    
    
            canvasGroup = gameObject.AddComponent<CanvasGroup>();
        }
    }

    protected virtual void Start()
    {
    
    
        Init();
    }

    void Update()
    {
    
    
        //淡入
        if (isShow && canvasGroup.alpha < 1)
        {
    
    
            canvasGroup.alpha += alphaSpeed * Time.deltaTime;
            if (canvasGroup.alpha >= 1)
                canvasGroup.alpha = 1;
        }

        //淡出
        else if (!isShow && canvasGroup.alpha > 0)
        {
    
    
            canvasGroup.alpha -= alphaSpeed * Time.deltaTime;
            if (canvasGroup.alpha <= 0)
            {
    
    
                canvasGroup.alpha = 0;
                //让管理器 剔除自己
                hideCallBack?.Invoke();
            }
        }
    }

    //初始化函数声明
    protected abstract void Init();

    //显示自己
    protected virtual void ShowMe()
    {
    
    
        //修改显示参数为显示状态
        isShow = true;
        //修改Alpha通道(在update中渐变)
        canvasGroup.alpha = 0;
    }

    //隐藏自己
    protected virtual void HideMe( UnityAction callback )
    {
    
    
        //修改显示参数为隐藏状态
        isShow = false;
        //修改Alpha通道(在update中渐变)
        canvasGroup.alpha = 1;
        //开始淡出时将事件注入容器
        hideCallBack = callback;
    }
}

6.4 UI管理器的书写

实现目标:单例模式,面板字典,显示面板,隐藏面板,获取面板。

public class UIManager 
{
    
    
    //单例模式
    private static UIManager instance;

    public static UIManager Instance
    {
    
    
        get {
    
     return instance; }
    }

    //存储当前显示的面板的容器
    private Dictionary<string, BasePanel> panelDic = new Dictionary<string, BasePanel>();

    //声明父对象
    private Transform canvasTrans;

    private UIManager()
    {
    
    
        //拿到父对象结点
        canvasTrans = GameObject.Find("Canvas").transform;
        //过场景时不删除Canvas对象
        GameObject.DontDestroyOnLoad(canvasTrans.gameObject);
    }

    //显示面板
    public T ShowPanel<T>() where T : BasePanel
    {
    
    
        //保证泛型T的类型和面板名字一致
        string panelName = typeof(T).Name;

        //场景中是否已经存在显示的同类面板,如果有,不用单独创建了
        if (panelDic.ContainsKey(panelName))
        {
    
    
            return panelDic[panelName] as T;
        }

        //显示面板就是动态创建面板预制体,设置父对象即可
        GameObject panelObj = GameObject.Instantiate(Resources.Load<GameObject>("UI/" + canvasTrans));
        panelObj.transform.SetParent(canvasTrans, false);

        //得到对应的面板脚本,存储起来即可
        T panel = panelObj.GetComponent<T>();
        panelDic.Add(panelName, panel);

        //调用显示自己逻辑
        panel.ShowMe();

        return panel;
    }

    //隐藏面板
    //参数isFade:是否希望淡出
    public void HidePanel<T>(bool isFade) where T : BasePanel
    {
    
    
        //根据泛型类型得到面板名字
        string panelName = typeof(T).Name;
        //如果当前显示面板是否存在希望删除面板
        if (panelDic.ContainsKey(panelName))
        {
    
    
            if (isFade)
            {
    
    
                panelDic[panelName].HideMe(() =>
                {
    
    
                    //面板淡出成功后,删除该面板
                    GameObject.Destroy(panelDic[panelName].gameObject);
                    //删除面板后从字典中移除
                    panelDic.Remove(panelName);
                });
            }
            else
            {
    
    
                //面板淡出成功后,删除该面板
                GameObject.Destroy(panelDic[panelName].gameObject);
                //删除面板后从字典中移除
                panelDic.Remove(panelName);
            }
        }

    }

    //获得面板
    public T GetPanel<T>() where T : BasePanel
    {
    
    
        string panelName = typeof(T).Name;
        if (panelDic.ContainsKey(panelName))
        {
    
    
            return panelDic[panelName] as T;
        }
        return null;
    }
}

6.5 制作提示面板

1.如图拼凑出该模型
在这里插入图片描述

2.分析该面板需要实现的功能

  • 1.显示隐藏该界面均继承基类即可
  • 2.修改提示内容
using UnityEngine.UI;

//提示面板类
public class TipPanel : BasePanel
{
    
    
    //绑定确认按钮
    public Button btn_Sure;
    //绑定提示内容
    public Text txt_Tip;

    //初始化给其面板的确认按钮加上确认逻辑
    protected override void Init()
    {
    
    
        btn_Sure.onClick.AddListener(() =>
        {
    
    
            UIManager.Instance.HidePanel<TipPanel>(true);
        });
    }

    //修改提示文字内容
    public void ChangeInfo(string info)
    {
    
    
        txt_Tip.text = info;
    }
}

6.6 制作登录面板

1.如图拼凑出如图模型
在这里插入图片描述
2.分析该面板要实现的功能

  • 1.显示隐藏该界面均继承基类即可
  • 2.登录数据相关类
//存储登录时玩家提交的数据
public class LoginData
{
    
    
    //用户名
    public string userName;
    //密码
    public string password;

    //是否记住密码
    public bool rememberPwd;
    //是否自动登录
    public bool autoLogin;
}
  • 3.登录面板相关逻辑
using UnityEngine.UI;

public class LoginPanel : BasePanel
{
    
    
    //登录注册按钮组件
    public Button btn_Register;
    public Button btn_Login;

    //输入框组件
    public InputField input_UserName;
    public InputField input_Password;

    //单选框组件
    public Toggle toggle_RememberPwd;
    public Toggle toggle_AutoLogin;


    protected override void Init()
    {
    
    
        //点击注册逻辑
        btn_Register.onClick.AddListener(() =>
        {
    
    
            //显示注册面板

            //隐藏当前面板
            UIManager.Instance.HidePanel<LoginPanel>(true);
        });

        //点击登录逻辑
        btn_Login.onClick.AddListener(() =>
        {
    
    
            //验证用户名和密码是否正确

        });
        //点击记住密码逻辑
        toggle_RememberPwd.onValueChanged.AddListener((isOn) =>
        {
    
    
            //当取消选中记住密码时,如果选择了自动登录,应该自动取消
            if (!isOn)
            {
    
    
                toggle_AutoLogin.isOn = false;
            }
        });
        //自动登录逻辑
        toggle_AutoLogin.onValueChanged.AddListener((isOn) =>
        {
    
    
            //当选中自动登录时,如果记住密码未被选中,应该让它被选中
            if (isOn)
            {
    
    
                toggle_RememberPwd.isOn = true;
            }
        });
    }

    public override void ShowMe()
    {
    
    
        base.ShowMe();
        //拿到存储的登录数据,并初始化
        LoginData loginData = LoginManager.Instance.LoginData;
        //初始化单选框
        toggle_RememberPwd.isOn = loginData.rememberPwd;
        toggle_AutoLogin.isOn = loginData.autoLogin;

        //初始化账号密码
        input_UserName.text = loginData.userName;
        //密码的初始化需要判断是否记住密码
        if (toggle_RememberPwd.isOn)
        {
    
    
            input_Password.text = loginData.password;
        }

        //如果勾选了自动登录,则自动验证账号密码
    }
}

6.7 注册面板实现

1.如图拼凑出如图模型
在这里插入图片描述
2.分析该面板要实现的功能

  • 1.显示隐藏该界面均继承基类即可
  • 2.登录数据相关类

6.8 值得注意的一些事

1.背景的比例适配可以将背景单独做成一张面板,然后添加 Aspect Ratio Filter组件自动适配。

6.9 源码展示

6.9.1 LoginManager登录管理器

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


//登录管理器:用于存储与读取用户的登录信息
public class LoginManager
{
    
    
    //实现单例模式
    private static LoginManager instance = new LoginManager();

    public static LoginManager Instance
    {
    
    
        get {
    
     return instance; }
    }

    //登录数据
    private LoginData loginData;
    
    public LoginData LoginData
    {
    
    
        get {
    
     return loginData; }
    }

    //注册数据
    private RegisterData registerData;

    public RegisterData RegisterData
    {
    
    
        get {
    
     return registerData; }
    }

    //服务器数据
    private List<ServerInfo> serverInfos;

    public List<ServerInfo> ServerInfos
    {
    
    
        get {
    
     return serverInfos; }
    }

    //私有构造(防止外部初始化该管理类)
    private LoginManager()
    {
    
    
        //如果之前没有登陆数据,则返回默认值
        loginData = JsonMgr.Instance.LoadData<LoginData>("LoginData");
        //读取注册数据
        registerData = JsonMgr.Instance.LoadData<RegisterData>("RegisterData");
        //读取服务器数据
        serverInfos = JsonMgr.Instance.LoadData<List<ServerInfo>>("ServerInfo");
    }

    //对外提供保存登陆数据接口
    public void SaveLoginData()
    {
    
    
        JsonMgr.Instance.SaveData(loginData, "LoginData");
    }

    //注册成功后清理数据逻辑
    public void ClearLoginData()
    {
    
    
        LoginData.frontServerID = 0;
        LoginData.autoLogin = false;
        LoginData.rememberPwd = false;
    }

    //对外提供保存注册数据接口
    public void SaveRegisterData()
    {
    
    
        JsonMgr.Instance.SaveData(registerData, "RegisterData");
    }

    

    //注册逻辑
    public bool Register(string userName,string password)
    {
    
    
        //判断是否存有userName
        if (registerData.registerInfo.ContainsKey(userName))
        {
    
    
            //无法注册,用户名已存在
            return false;
        }
        //可以注册,注册逻辑
        registerData.registerInfo.Add(userName, password);
        //存储数据
        SaveRegisterData();

        return true;
    }

    //检测输入的账号密码长度是否合法
    public bool CheckLength(string userName,string password)
    {
    
    
        if (userName.Length > 6 && password.Length > 6)
        {
    
    
            return true;
        }
        return false;
    }

    //检测输入的账号密码对应
    public bool CheckInfo (string userName,string password)
    {
    
    
        //如果检测到用户名存在则继续逻辑
        if (registerData.registerInfo.ContainsKey(userName))
        {
    
    
            //再次检测密码是否一致,一致则登录成功
            if (registerData.registerInfo[userName] == password)
            {
    
    
                //登录成功
                return true;
            }
        }
        return false;
    }
}

6.9.2 BasePanel面板基类

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

//因为该类不会被初始化,是被子类继承来使用,故可使用抽象类
public abstract class BasePanel : MonoBehaviour
{
    
    
    //整体控制淡入淡出的画布组件
    private CanvasGroup canvasGroup;
    //淡入淡出的速度
    private float alphaSpeed = 10;
    //检测组件是否被显示
    private bool isShow;

    //淡出面板后执行的逻辑
    private UnityAction hideCallBack;


    void Awake()
    {
    
    
        //拿到子类对应的画布组件
        canvasGroup = GetComponent<CanvasGroup>();
        //如果没拿到添加组件
        if (canvasGroup == null)
        {
    
    
            canvasGroup = gameObject.AddComponent<CanvasGroup>();
        }
    }

    protected virtual void Start()
    {
    
    
        Init();
    }

    void Update()
    {
    
    
        //淡入
        if (isShow && canvasGroup.alpha < 1)
        {
    
    
            canvasGroup.alpha += alphaSpeed * Time.deltaTime;
            if (canvasGroup.alpha >= 1)
                canvasGroup.alpha = 1;
        }

        //淡出
        else if (!isShow && canvasGroup.alpha > 0)
        {
    
    
            canvasGroup.alpha -= alphaSpeed * Time.deltaTime;
            if (canvasGroup.alpha <= 0)
            {
    
    
                canvasGroup.alpha = 0;
                //让管理器 剔除自己
                hideCallBack?.Invoke();
            }
        }
    }

    //初始化函数声明
    protected abstract void Init();

    //显示自己
    public virtual void ShowMe()
    {
    
    
        //修改显示参数为显示状态
        isShow = true;
        //修改Alpha通道(在update中渐变)
        canvasGroup.alpha = 0;
    }

    //隐藏自己
    public virtual void HideMe( UnityAction callback )
    {
    
    
        //修改显示参数为隐藏状态
        isShow = false;
        //修改Alpha通道(在update中渐变)
        canvasGroup.alpha = 1;
        //开始淡出时将事件注入容器
        hideCallBack = callback;
    }
}

6.9.3 UIManager UI管理器

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

public class UIManager 
{
    
    
    //单例模式
    private static UIManager instance = new UIManager();

    public static UIManager Instance
    {
    
    
        get {
    
     return instance; }
    }

    //存储当前显示的面板的容器
    private Dictionary<string, BasePanel> panelDic = new Dictionary<string, BasePanel>();

    //声明父对象
    private Transform canvasTrans;

    private UIManager()
    {
    
    
        //拿到父对象结点
        canvasTrans = GameObject.Find("Canvas").transform;
        //过场景时不删除Canvas对象
        GameObject.DontDestroyOnLoad(canvasTrans.gameObject);
    }

    //显示面板
    public T ShowPanel<T>() where T : BasePanel
    {
    
    
        //保证泛型T的类型和面板名字一致
        string panelName = typeof(T).Name;

        //场景中是否已经存在显示的同类面板,如果有,不用单独创建了
        if (panelDic.ContainsKey(panelName))
        {
    
    
            return panelDic[panelName] as T;
        }

        //显示面板就是动态创建面板预制体,设置父对象即可
        Debug.Log(panelName);
        GameObject panelObj = GameObject.Instantiate(Resources.Load<GameObject>("UI/" + panelName));
        panelObj.transform.SetParent(canvasTrans, false);

        //得到对应的面板脚本,存储起来即可
        T panel = panelObj.GetComponent<T>();
        panelDic.Add(panelName, panel);

        //调用显示自己逻辑
        panel.ShowMe();

        return panel;
    }

    //隐藏面板
    //参数isFade:是否希望淡出
    public void HidePanel<T>(bool isFade) where T : BasePanel
    {
    
    
        //根据泛型类型得到面板名字
        string panelName = typeof(T).Name;
        //如果当前显示面板是否存在希望删除面板
        if (panelDic.ContainsKey(panelName))
        {
    
    
            if (isFade)
            {
    
    
                panelDic[panelName].HideMe(() =>
                {
    
    
                    //面板淡出成功后,删除该面板
                    GameObject.Destroy(panelDic[panelName].gameObject);
                    //删除面板后从字典中移除
                    panelDic.Remove(panelName);
                });
            }
            else
            {
    
    
                //删除该面板
                GameObject.Destroy(panelDic[panelName].gameObject);
                //删除面板后从字典中移除
                panelDic.Remove(panelName);
            }
        }

    }

    //获得面板
    public T GetPanel<T>() where T : BasePanel
    {
    
    
        string panelName = typeof(T).Name;
        if (panelDic.ContainsKey(panelName))
        {
    
    
            return panelDic[panelName] as T;
        }
        return null;
    }
}


6.9.4 LoginData登录数据类

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

//存储登录时玩家提交的数据
public class LoginData
{
    
    
    //用户名
    public string userName;
    //密码
    public string password;

    //是否记住密码
    public bool rememberPwd;
    //是否自动登录
    public bool autoLogin;

    //上次登录的服务器ID
    public int frontServerID = 0;
}


6.9.5 RegisterData注册数据类

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


//注册数据类,存储玩家注册的数据
public class RegisterData 
{
    
    
    //注册数据(使用字典存储)
    public Dictionary<string, string> registerInfo = new Dictionary<string, string>();

}

6.9.6 ServerInfo服务器数据

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

//单个服务器数据
public class ServerInfo 
{
    
    
    public int id;
    public string name;
    public int state;
    public int isNew;
}

6.9.7 BGPanel背景面板

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

public class BGPanel : BasePanel
{
    
    
    protected override void Init()
    {
    
    
        
    }
}

6.9.8 TipPanel提示面板

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

//提示面板类
public class TipPanel : BasePanel
{
    
    
    //绑定确认按钮
    public Button btn_Sure;
    //绑定提示内容
    public Text txt_Tip;

    //初始化给其面板的确认按钮加上确认逻辑
    protected override void Init()
    {
    
    
        btn_Sure.onClick.AddListener(() =>
        {
    
    
            UIManager.Instance.HidePanel<TipPanel>(true);
        });
    }

    //修改提示文字内容
    public void ChangeInfo(string info)
    {
    
    
        txt_Tip.text = info;
    }
}

6.9.9 LoginPanel登录面板

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

public class LoginPanel : BasePanel
{
    
    
    //登录注册按钮组件
    public Button btn_Register;
    public Button btn_Login;

    //输入框组件
    public InputField input_UserName;
    public InputField input_Password;

    //单选框组件
    public Toggle toggle_RememberPwd;
    public Toggle toggle_AutoLogin;


    protected override void Init()
    {
    
    
        //点击注册逻辑
        btn_Register.onClick.AddListener(() =>
        {
    
    
            //显示注册面板
            UIManager.Instance.ShowPanel<RegisterPanel>();

            //隐藏当前面板
            UIManager.Instance.HidePanel<LoginPanel>(true);
        });

        //点击登录逻辑
        btn_Login.onClick.AddListener(() =>
        {
    
    
            //验证用户名和密码是否正确
            if (LoginManager.Instance.CheckLength(input_UserName.text, input_Password.text))
            {
    
    
                //位数合法
                if (LoginManager.Instance.CheckInfo(input_UserName.text, input_Password.text))
                {
    
    
                    //登录成功
                    //记录数据
                    LoginData login = LoginManager.Instance.LoginData;
                    login.userName = input_UserName.text;
                    login.password = input_Password.text;
                    login.rememberPwd = toggle_RememberPwd.isOn;
                    login.autoLogin = toggle_AutoLogin.isOn;
                    

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

                    //判断上次登录是否选择过服务器
                    if (login.frontServerID <= 0)
                    {
    
    
                        //未登录过,打开选择服务器面板
                        UIManager.Instance.ShowPanel<ChooseServerPanel>();
                    }
                    else
                    {
    
    
                        //登录过,打开服务器面板
                        UIManager.Instance.ShowPanel<ServerPanel>();
                    }

                    //隐藏自己
                    UIManager.Instance.HidePanel<LoginPanel>(true);
                }
                else
                {
    
    
                    //登录失败
                    //提供提示信息
                    UIManager.Instance.ShowPanel<TipPanel>().ChangeInfo("用户名或密码不正确");
                }
            }
            else
            {
    
    
                //登录失败
                //提供提示信息
                UIManager.Instance.ShowPanel<TipPanel>().ChangeInfo("用户名密码位数必须大于6");
            }

        });
        //点击记住密码逻辑
        toggle_RememberPwd.onValueChanged.AddListener((isOn) =>
        {
    
    
            //当取消选中记住密码时,如果选择了自动登录,应该自动取消
            if (!isOn)
            {
    
    
                toggle_AutoLogin.isOn = false;
            }
        });
        //自动登录逻辑
        toggle_AutoLogin.onValueChanged.AddListener((isOn) =>
        {
    
    
            //当选中自动登录时,如果记住密码未被选中,应该让它被选中
            if (isOn)
            {
    
    
                toggle_RememberPwd.isOn = true;
            }
        });
    }

    public override void ShowMe()
    {
    
    
        base.ShowMe();
        //拿到存储的登录数据,并初始化
        LoginData loginData = LoginManager.Instance.LoginData;
        //初始化单选框
        toggle_RememberPwd.isOn = loginData.rememberPwd;
        toggle_AutoLogin.isOn = loginData.autoLogin;
        //print(toggle_AutoLogin.isOn);
        //print(toggle_RememberPwd.isOn);

        //初始化账号密码
        input_UserName.text = loginData.userName;
        //密码的初始化需要判断是否记住密码
        if (toggle_RememberPwd.isOn)
        {
    
    
            input_Password.text = loginData.password;
        }

        //如果勾选了自动登录,则自动验证账号密码
        if (toggle_AutoLogin.isOn)
        {
    
    
            if (LoginManager.Instance.CheckInfo(input_UserName.text, input_Password.text))
            {
    
    
                //根据服务器登录类型决定显示哪个面板
                LoginData login = LoginManager.Instance.LoginData;
                //判断上次登录是否选择过服务器
                if (login.frontServerID <= 0)
                {
    
    
                    //未登录过,打开选择服务器面板
                    UIManager.Instance.ShowPanel<ChooseServerPanel>();
                }
                else
                {
    
    
                    //登录过,打开服务器面板
                    UIManager.Instance.ShowPanel<ServerPanel>();
                }

                //隐藏自己
                UIManager.Instance.HidePanel<LoginPanel>(false);
            }
            else
            {
    
    
                UIManager.Instance.ShowPanel<TipPanel>().txt_Tip.text = "用户名或密码错误";
            }
        }
    }

    //提供给外部快捷设置用户名和密码的逻辑
    public void SetInfo(string userName, string password)
    {
    
    
        input_UserName.text = userName;
        input_Password.text = password;
    }
}

6.9.10 RegisterPanel注册面板

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

public class RegisterPanel : BasePanel
{
    
    
    //输入框组件
    public InputField input_UserName;
    public InputField input_Password;

    //按钮组件
    public Button btn_Register;
    public Button btn_Cancel;

    protected override void Init()
    {
    
    
        //点击取消逻辑
        btn_Cancel.onClick.AddListener(() =>
        {
    
    
            //隐藏当前注册面板
            UIManager.Instance.HidePanel<RegisterPanel>(true);
            //显示登录面板
            UIManager.Instance.ShowPanel<LoginPanel>();
        });

        //点击注册逻辑
        btn_Register.onClick.AddListener(() =>
        {
    
    
            //判断长度是否合理
            if (LoginManager.Instance.CheckLength(input_UserName.text, input_Password.text))
            {
    
    
                //合理
                if (LoginManager.Instance.Register(input_UserName.text, input_Password.text))
                {
    
    
                    //注册成功
                    //清理之前登录数据
                    LoginManager.Instance.ClearLoginData();
                    //显示登录面板
                    LoginPanel loginPanel = UIManager.Instance.ShowPanel<LoginPanel>();
                    loginPanel.SetInfo(input_UserName.text, input_Password.text);
                    UIManager.Instance.HidePanel<RegisterPanel>(true);                  
                }
                else
                {
    
    
                    //未注册成功,提示面板
                    UIManager.Instance.ShowPanel<TipPanel>().ChangeInfo("用户名已存在");
                    //将输入框清空
                    input_UserName.text = "";
                    input_Password.text = "";
                }
            }
            else
            {
    
    
                //不合理,显示提示面板
                UIManager.Instance.ShowPanel<TipPanel>().ChangeInfo("用户名密码长度必须大于6位");
            }
        });
    }

    
}

6.9.11 ServerPanel服务器面板

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

public class ServerPanel : BasePanel
{
    
    
    //按钮组件
    public Button btn_Back;
    public Button btn_clickServer;
    public Button btn_Enter;

    //服务器文本
    public Text txt_ServerId;

    protected override void Init()
    {
    
    
        //给各个组件加功能
        btn_Back.onClick.AddListener(() =>
       {
    
    
           //隐藏当前面板
           UIManager.Instance.HidePanel<ServerPanel>(true);
           //取消自动登录按钮
           if (LoginManager.Instance.LoginData.autoLogin)
               LoginManager.Instance.LoginData.autoLogin = false;
           
           //显示登录面板
           UIManager.Instance.ShowPanel<LoginPanel>();
       });

        btn_clickServer.onClick.AddListener(() =>
        {
    
    
            //隐藏选服务器面板
            UIManager.Instance.HidePanel<ServerPanel>(true);
            //弹出服务器面板
            UIManager.Instance.ShowPanel<ChooseServerPanel>();
        });

        btn_Enter.onClick.AddListener(() =>
        {
    
    
            //隐藏当前面板
            UIManager.Instance.HidePanel<ServerPanel>(true);
            //隐藏背景面板
            UIManager.Instance.HidePanel<BGPanel>(true);
            //保存登录数据
            LoginManager.Instance.SaveLoginData();
            //切场景逻辑
        });
    }

    public override void ShowMe()
    {
    
    
        base.ShowMe();

        //得到当前服务器信息
        int id = LoginManager.Instance.LoginData.frontServerID;
        if (id <= 0)
        {
    
    
            txt_ServerId.text = "无";
        }
        else
        {
    
    
            ServerInfo serverInfo = LoginManager.Instance.ServerInfos[id - 1];
            //修改名字
            txt_ServerId.text = serverInfo.id + "区  " + serverInfo.name;
        }
        
    }
}

6.9.12 ServerLeftItem选服面板左边

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

public class ServerLeftItem : MonoBehaviour
{
    
    
    //按钮本身
    public Button self;
    //显示文本
    public Text text;

    //开始索引
    private int startIndex;
    //区间范围
    private int endIndex;

    //监听各组件的功能
    private void Start()
    {
    
    
        self.onClick.AddListener(() =>
       {
    
    
           //点击后改变右边显示的服务器列表
           ChooseServerPanel panel = UIManager.Instance.GetPanel<ChooseServerPanel>();
           panel.UpdatePanel(startIndex, endIndex);
       });
    }

    //对外提供初始化自身的逻辑
    public void InitInfo(int startIndex,int endIndex)
    {
    
    
        this.startIndex = startIndex;
        this.endIndex = endIndex;

        //修改显示的值
        text.text = startIndex + " - " + endIndex + "区";
    }
}

6.9.13 ServerRightItem选服面板右边

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.U2D;
using UnityEngine.UI;

public class ServerRightItem : MonoBehaviour
{
    
    
    //按钮对象
    public Button self;
    //是否是新服务器
    public Image isNew;
    //当前状态
    public Image state;
    //文本内容
    public Text text;

    //当前按钮代表哪个服务器
    private ServerInfo currentServer;

    // Start is called before the first frame update
    void Start()
    {
    
    
        self.onClick.AddListener(() =>
       {
    
    
           //记录登录信息中的选服信息
           LoginManager.Instance.LoginData.frontServerID = currentServer.id;
           //隐藏选服面板
           UIManager.Instance.HidePanel<ChooseServerPanel>(true);
           //显示服务器面板
           UIManager.Instance.ShowPanel<ServerPanel>();
           
       });
    }

    //初始化服务器方法
    public void InitServer(ServerInfo serverInfo)
    {
    
    
        currentServer = serverInfo;

        //更新按钮上的信息
        text.text = serverInfo.id + "区  " + serverInfo.name;
        //是否是新服务器
        isNew.gameObject.SetActive(serverInfo.isNew == 1 ? true : false);
        //更新状态
        //加载图集
        SpriteAtlas sa = Resources.Load<SpriteAtlas>("login");
        switch (serverInfo.state)
        {
    
    
            case 0://火爆
                state.sprite = sa.GetSprite("ui_DL_huobao_01");
                break;

            case 1://繁忙
                state.sprite = sa.GetSprite("ui_DL_fanhua_01");
                break;

            case 2://流畅
                state.sprite = sa.GetSprite("ui_DL_liuchang_01");
                break;

            case 3://维护
                state.sprite = sa.GetSprite("ui_DL_weihu_01");
                break;
        }
    }



}

猜你喜欢

转载自blog.csdn.net/qq_55071342/article/details/127133030