Unity的UGUI学习

本文详细介绍了Unity中的UGUI系统,包括Canvas、Text、Image、Button、Anchor、登录UI开发、单选/多选按钮、滑动器、图片布局以及处理不同分辨率下的适配。还涵盖了网格布局、滚动条、列表滚动、事件处理和面板设计等内容。

目录

什么是UGUI

Canvas画布

Text文本控件

图片Image控件

Button控件

Button的点击事件

Anchor锚点

登录UI功能开发

单选和多选按钮

如何实现男女只能选择一个的

Slider滑动器

图片的Sliced 已切片

图片的Tiled 平铺

图片的Filled 已填充

滚动条和下拉列表

案例介绍

问题:不同的分辨率,会导致图片没办法填满画布(屏幕)

解决:选择图片,按Alt,选择锚点,实现图片的宽度和高度和父物体保持一致

开发开始界面-背景和声音按钮

开发设置、游戏和开始按钮

开发头像面板

开发血量条

开发技能冷却效果

开发技能冷却效果

按键触发技能冷却

Panel面板

开发我的背包面板

设计人物的属性

开发背包的选项卡

开发物品面板的切换

实现思路

使用网格布局设计物品格子

设计关卡选择面板

设计关卡按钮和锁关按钮

设计关卡的网格列表

一让关卡列表滚动起来

问题:只有点击成就图片才能滚动

Mesh组件

控制滑动列表到最近的页面

控制列表滑动到目标页面

通过页面按钮控制滚动列表跳转

开发任务列表背景和任务项

使用VerticalLayout进行任务列表布局

问题:遮盖平面以外的成就,可以滚动

设计设置面板添加声音大小滑动器

设计谁易程度单选按钮

设计自定义开关,添加声音和背景开关

思路

设计登录面板

总结


什么是UGUI

unity graphic user interface,简称UI,游戏UI,用户接口

Canvas画布

  1. Rect Transform 多了一些自身宽度和高度
  2. 画布就是UI容器

Text文本控件

  1. 字体资源要导入Unity里
  2. 富文本就是可以用标签修改文本,比如<b></b>对文本加粗

图片Image控件

导入图片后要设置纹理类型,应用

  1. Raycast Target 是否监听鼠标点击的事件,可以通过碰撞检测,检测到控件
  2. 按Shift拉大图片会等比例缩放
  3. Set Native Size 设置原生大小,把图片更改为原本大小

  1. 宽度,高度以像素为单位

Button控件

  1. interactable表示是否可以交互,取消勾选,就是禁用状态,没法点击
  2. Selected Color设置按下后改变的颜色
  3. On click()点击事件,当鼠标点击后,会触发什么方法
  4. 按钮就是图片Image加上Button组件
  5. Target Graphic目标图形,修改图片的对象是哪一个,默认是自身的Image

Button的点击事件

  1. 把挂载在游戏对象Main Camera拖到Button组件点击事件中
  2. 选择该游戏对象上的脚本上的方法,作为鼠标点击触发事件
  3. 类似c#中的事件,鼠标点击后,触发调用列表的所有方法

Anchor锚点

登录UI功能开发

图片和画布保持一致,当不同设备分辨率不同时候,也能让图片占满屏幕

单选和多选按钮

  1. 创建空游戏物体对象,添加组件Toggle
  2. Target Graphic目标图形是背景图片,创建图片,并且拖拽赋值
  3. Is on 是否开启,勾选是默认开启
  4. Graphic 图片一般是赋值打勾图片,点击后激活该图片

如何实现男女只能选择一个的

  1. Toggle男,Toggle女创建空父对象
  2. 父对象添加Toggle Group组件
  3. 把父对象拖拽到子对象Toggle组件里Group属性
  4. 相对于给它们分成一个组里

Slider滑动器

  1. 滑动时,Value值会改变
  2. 值变化时,会触发列表的方法
  3. Target Graphic 是进度条圈圈图片

图片的Sliced 已切片

导入缺少的包

  1. 绿线设置边框,绿色线外部部分就是边框Border
  2. 左右拉伸,上下拉伸,四个角不会随着拉伸而改变
  3. 对于上下边框,上下拉伸不会等比例拉伸,左右拉伸会拉长(会变模糊)
  4. 对于左右边框,左右拉伸不会等比例拉伸,上下拉伸会拉长(会变模糊)
  5. 在于设计按钮时候,可以设计可以任意缩放的按钮
  6. Fill Center填充,勾选会挖空除了边框的内容

图片的Tiled 平铺

按照原本的大小平铺在里面,不够会塞到满

图片的Filled 已填充

应用:技能cd

滚动条和下拉列表

案例介绍

导入资源包

全选图片,因为要做UI,都设置为2DandUI

拖拽满画布

问题:不同的分辨率,会导致图片没办法填满画布(屏幕)

解决:选择图片,按Alt,选择锚点,实现图片的宽度和高度和父物体保持一致

只有高度和父物体保持一致,只有高度会被拉伸,宽度不会被拉伸

图片足够宽,就能填充满整个屏幕

开发开始界面-背景和声音按钮

点击后,阴影效果的图片设置为子物体Image

设置锚点为左上

设置锚点为右上

开发设置、游戏和开始按钮

  1. 按shift拉伸图片,等比例缩放
  2. 按shift+Alt拉伸图片,在图片中心点等比例缩放
  3. 添加Shadow组件,控制文字阴影

开发头像面板

开发血量条

  1. 设置图像的类型为已填充,填充方法为水平
  2. 把图片赋值给Slider组件的填充矩形

开发技能冷却效果

  1. 在刀图片上再加一层刀的图片,把上面一层的图片调暗
  2. 设置图片类型为填充,360,通过控制填充总数就可以控制填充比例

  1. 通过Shadow设置字体阴影
  2. 通过Outline组件设置字体边框

开发技能冷却效果

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

public class SkillItem : MonoBehaviour
{
    public float coldTime = 2;
    private float timer = 0;

    private bool isColding = false;

    private Image coldMask;

    // Start is called before the first frame update
    void Start()
    {
        
        //获取子对象,再获取该对象的组件Image
        coldMask = transform.Find("ColdMask").GetComponent<Image>();
        coldMask.fillAmount = 0;
    }

    // Update is called once per frame
    void Update()
    {
        if (isColding)
        {
            //按下技能后,isColding==true,开始记录时间timer, 冷却时间为coldTime
            timer += Time.deltaTime;
            //计算比例赋值给fillAmount
            coldMask.fillAmount = (coldTime - timer) / coldTime;

            if(timer > coldTime)
            {
                isColding = false;
                coldMask.fillAmount = 0;
                timer = 0;
            }

        }
    }

    public void OnSkillClick()
    {
        if (isColding == false)
        {
            isColding = true;
            timer = 0;
            coldMask.fillAmount = 1;
        }
    }
}

  1. 把脚本挂载到游戏物体上,再拖拽到Button组件中
  2. 当点击图标后,会触发Button事件,调用挂载在Button的全部方法
  3. transform.Find("ColdMask").GetComponent<Image>();通过transform.Find找到挂载在的对象的子物体ColdMask,再通过GetComponent获取到Image组件
  4. fillAmount是Image组件的填充总数,0技能亮,1技能暗

按键触发技能冷却

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

public class SkillItem : MonoBehaviour
{
    public float coldTime = 2;
    private float timer = 0;

    private bool isColding = false;

    public KeyCode KeyCode = KeyCode.Alpha1;

    private Image coldMask;

    // Start is called before the first frame update
    void Start()
    {
        
        //获取子对象,再获取该对象的组件Image
        coldMask = transform.Find("ColdMask").GetComponent<Image>();
        coldMask.fillAmount = 0;
    }

    // Update is called once per frame
    void Update()
    {
        if (isColding)
        {
            //按下技能后,isColding==true,开始记录时间timer, 冷却时间为coldTime
            timer += Time.deltaTime;
            //计算比例赋值给fillAmount
            coldMask.fillAmount = (coldTime - timer) / coldTime;

            if(timer > coldTime)
            {
                isColding = false;
                coldMask.fillAmount = 0;
                timer = 0;
            }

        }
        //点击1为true
        if(Input.GetKeyDown(KeyCode))
        {
            ReleaseSkill();
        }
    }

    public void OnSkillClick()
    {
       ReleaseSkill();
    }

    private void ReleaseSkill()
    {
        if (isColding == false)
        {
            isColding = true;
            timer = 0;
            coldMask.fillAmount = 1;
        }
    }
}
  1. Input.GetKeyDown(KeyCode.Alpha1)点击数字1返回true

  2. 可以把KeyCode.Alpha1设置为public的变量,方便在Unity里修改

Panel面板

  1. 面板图片等等有边框的,都需要设置边框,不然拉伸会变模糊
  2. 画布上,面板,背景图片都需要设置锚点,拉伸之后不会偏移

开发我的背包面板

设计人物的属性

开发背包的选项卡

  1. 添加Toggle组件,三个选择一个默认开启Is On
  2. 设置为单选,创建一个父对象,在父对象上添加Toggle Group组件
  3. 把父对象拖拽给子对象Toggle组件的Group设置为同一组
  4. 可以通过代码改变选择时候的字体颜色

开发物品面板的切换

实现思路

  1. 点击不同的选项时候,Is On会取消勾选,会触发函数,另一个选项,Is On会勾选,也调用函数
  2. 拖拽Panel1游戏物体到Toggle的触发函数里,调用GameObject.SetActive改变状态
  3. 点击任务选项,触发Item1的函数,把Panel1状态设置为未激活
  4. 同时,任务选项被点击,触发Item2的函数,改变Panel2的状态为激活

使用网格布局设计物品格子

网格布局组件Grid Layout Group,可以把子物体按照网络排列,设置单元格的高宽

设计关卡选择面板

可以把能复用的游戏对象设置为Prefab预制体

设计关卡按钮和锁关按钮

设计关卡的网格列表

要让网格Grid Layout Group的单元格宽度*一行个数==Grid的宽度,高度同理

把Grid的原点设置在左边,这样宽度增加,会向右边延申

如果在中间会向两边延申

一让关卡列表滚动起来

  1. 创建一个父空对象,宽高设置为要显示的宽高,比如显示8个单元格,根据单元格计算宽高
  2. 在父对象中,添加Scroll Rect组件,把带有网格组件的Grid子对象拖拽给Content内容
  3. 超出父对象高宽的可以滚动

问题:只有点击成就图片才能滚动

  1. 添加图片Image组件解决,Image组件的Raycast Target可以检测点击碰撞
  2. 图片颜色设置为透明
  3. ScrollRect 组件禁止垂直滚动

Mesh组件

  1. 添加Mesh组件,实现当滚动超过高宽时候,不显示
  2. 问题:添加Mesh组件后,Image透明度设置为零,子问题透明度也为零
  3. 解决:取消Mash组件的图片遮罩

控制滑动列表到最近的页面

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

public class LevelScrollRect : MonoBehaviour,IBeginDragHandler, IEndDragHandler
{
    private ScrollRect scroll;
    //第一页位置为0,第四页位置为1
    private float[] pagePositon = new float[4] { 0, 0.333f, 0.6666f, 1 };
    //脚本要放在Scroll Rect组件的对象下
    //监听开始拖拽事件
    public void OnBeginDrag(PointerEventData eventData)
    {
        
    }

    //监听结束拖拽事件
    public void OnEndDrag(PointerEventData eventData)
    {
        //normalizedPosition获取位置比例
        //scroll.normalizedPosition
        //currentPosition保持拖拽结束后位置
        float currentPosition = scroll.horizontalNormalizedPosition;
        //假设第一页最近
        int index = 0;
        float offset = currentPosition - pagePositon[index];
        for (int i = 0; i < pagePositon.Length; i++)
        {
            //通过偏移判断哪一个页面更接近
            if (Mathf.Abs(currentPosition - pagePositon[i]) < offset){
                index = i;
                offset = Mathf.Abs(currentPosition - pagePositon[i]);
            }
        }
        //设置最近的页面位置
        scroll.horizontalNormalizedPosition = pagePositon[index];
    }

    // Start is called before the first frame update
    void Start()
    {
        scroll = GetComponent<ScrollRect>();
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    
}

控制列表滑动到目标页面

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

public class LevelScrollRect : MonoBehaviour,IBeginDragHandler, IEndDragHandler
{
    private ScrollRect scroll;
    //第一页位置为0,第四页位置为1
    private float[] pagePositon = new float[4] { 0, 0.333f, 0.6666f, 1 };

    private float targetPosition = 0;
    private bool isMoving = false;

    public float speed = 4;
    //脚本要放在Scroll Rect组件的对象下
    //监听开始拖拽事件
    public void OnBeginDrag(PointerEventData eventData)
    {
        
    }

    //监听结束拖拽事件
    public void OnEndDrag(PointerEventData eventData)
    {
        //normalizedPosition获取位置比例
        //scroll.normalizedPosition
        //currentPosition保持拖拽结束后位置
        float currentPosition = scroll.horizontalNormalizedPosition;
        //假设第一页最近
        int index = 0;
        float offset = currentPosition - pagePositon[index];
        for (int i = 0; i < pagePositon.Length; i++)
        {
            //通过偏移判断哪一个页面更接近
            if (Mathf.Abs(currentPosition - pagePositon[i]) < offset){
                index = i;
                offset = Mathf.Abs(currentPosition - pagePositon[i]);
            }
        }
        //设置最近的页面位置
        //scroll.horizontalNormalizedPosition = pagePositon[index];
        targetPosition = pagePositon[index];
        isMoving = true;
    }

    // Start is called before the first frame update
    void Start()
    {
        scroll = GetComponent<ScrollRect>();
    }

    // Update is called once per frame
    void Update()
    {
        //Mathf.Lerp 函数来平滑地将 scroll.horizontalNormalizedPosition 的值从当前值向 targetPosition 进行插值。
        //Time.deltaTime 用于控制插值的速度,确保在每一帧中移动的距离是恰当的,以保持动画的平滑性。

        if (isMoving == true)
        {
            scroll.horizontalNormalizedPosition = Mathf.Lerp(scroll.horizontalNormalizedPosition, targetPosition, Time.deltaTime*speed);
            if(Mathf.Abs(scroll.horizontalNormalizedPosition - targetPosition) < 0.001f)
            {
                isMoving = false;
                scroll.horizontalNormalizedPosition = targetPosition;
            }
        }
    }

    
}

通过页面按钮控制滚动列表跳转

  1. 先在下方设置单选功能的选项
  2. 点击时候触发挂载在ScrollRect游戏对象上的LevelScrollRect脚本里的方法
  3. 比如点击第二个选项,就调用方法把页面位置更新为第二页,实现同步
  4. 同时,也要实现当页面滚动时,选项的改变
  5. 页面滚动是在脚本里实现的,选项改变是在toggle组件的isOn属性改变的
  6. 所以,在脚本里实现改变isOn属性
  7. 在脚本里,定义一个toggle类型的数组,通过数组.isOn改变
  8. 在Unity里,把四个选项按顺序赋值toggle类型数组

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

public class LevelScrollRect : MonoBehaviour,IBeginDragHandler, IEndDragHandler
{
    private ScrollRect scroll;
    //第一页位置为0,第四页位置为1
    private float[] pagePositon = new float[4] { 0, 0.333f, 0.6666f, 1 };

    private float targetPosition = 0;
    private bool isMoving = false;

    //解决页面滑动,下面选项也有跟着改变
    public Toggle[] toggleArray;

    public float speed = 4;
    //脚本要放在Scroll Rect组件的对象下
    //监听开始拖拽事件
    public void OnBeginDrag(PointerEventData eventData)
    {
        
    }

    //监听结束拖拽事件
    public void OnEndDrag(PointerEventData eventData)
    {
        //normalizedPosition获取位置比例
        //scroll.normalizedPosition
        //currentPosition保持拖拽结束后位置
        float currentPosition = scroll.horizontalNormalizedPosition;
        //假设第一页最近
        int index = 0;
        float offset = currentPosition - pagePositon[index];
        for (int i = 0; i < pagePositon.Length; i++)
        {
            //通过偏移判断哪一个页面更接近
            if (Mathf.Abs(currentPosition - pagePositon[i]) < offset){
                index = i;
                offset = Mathf.Abs(currentPosition - pagePositon[i]);
            }
        }
        //设置最近的页面位置
        //scroll.horizontalNormalizedPosition = pagePositon[index];
        targetPosition = pagePositon[index];
        isMoving = true;
        //当滑动到第二页面,就把第二页面isOn设置为true,勾选
        toggleArray[index].isOn = true;
    }

    // Start is called before the first frame update
    void Start()
    {
        scroll = GetComponent<ScrollRect>();
    }

    // Update is called once per frame
    void Update()
    {
        //Mathf.Lerp 函数来平滑地将 scroll.horizontalNormalizedPosition 的值从当前值向 targetPosition 进行插值。
        //Time.deltaTime 用于控制插值的速度,确保在每一帧中移动的距离是恰当的,以保持动画的平滑性。

        if (isMoving == true)
        {
            scroll.horizontalNormalizedPosition = Mathf.Lerp(scroll.horizontalNormalizedPosition, targetPosition, Time.deltaTime*speed);
            if(Mathf.Abs(scroll.horizontalNormalizedPosition - targetPosition) < 0.001f)
            {
                isMoving = false;
                scroll.horizontalNormalizedPosition = targetPosition;
            }
        }
    }

    public void MoveToPage1(bool isOn)
    {
        if (isOn)
        {
            isMoving = true;
            targetPosition = pagePositon[0];
        }
    }
    public void MoveToPage2(bool isOn)
    {
        if (isOn)
        {
            isMoving = true;
            targetPosition = pagePositon[1];
        }
    }
    public void MoveTopage3(bool isOn)
    {
        if (isOn)
        {
            isMoving = true;
            targetPosition = pagePositon[2];
        }
    }
    public void MoveTopage4(bool isOn)
    {
        if (isOn)
        {
            isMoving = true;
            targetPosition = pagePositon[3];
        }
    }

}

开发任务列表背景和任务项

  1. 背景用预制体Prefab复用
  2. 其他用图片Image,加上各种组件
  3. 完成选项有Button组件

使用VerticalLayout进行任务列表布局

垂直网络布局VerticalLayoutGroup

问题:遮盖平面以外的成就,可以滚动

  1. 创建图片Image,把Image缩放到显示3条成就的窗口大小
  2. Image作为父对象,VericalList对象作为子对象,
  3. 在Image父对象上,添加Mask组件,这样实现了遮盖了图片以外的成就
  4. 取消显示遮盖图形,去掉了白底
  5. Mask组件将子元素限制为父元素的形状。因此,如果子项大于父项,则只有子项中在父项的部分才可见。

设计设置面板添加声音大小滑动器

设计谁易程度单选按钮

  1. 遇到个问题,文字高宽覆盖其他选项会出错,比如点击中等会显示简单
  2. 多选变单选就是添加父对象,在父对象上添加Toggle Group组件
  3. 再把子对象的Toggle组件的Group组都设置为父对象,实现单选

设计自定义开关,添加声音和背景开关

识笔识别颜色

问题:点击后,传入的Is On一直等于false,不懂

重新添加Toggle组件,拖拽脚本,就没问题了

思路

  1. Toggle组件只能让一张图片显示或隐藏,现在这个包括两文字和两图片
  2. 把两对图片和文字分别放在两个游戏对象上,通过控制游戏对象的状态(激活与未激活)显示开关
  3. 添加Toggle组件在两个游戏对象的父对象上,利用Toggle的触发方法,当点击之后,把参数Is On传递给调用列表的方法
  4. 再通过代码去实现对子对象状态的修改
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Mytoggle : MonoBehaviour
{
    public GameObject onGameObject;
    public GameObject offGameObject;

    private Toggle toggle;
    // Start is called before the first frame update
    void Start()
    {
        //初始化,一开始只能有一个激活
        toggle = GetComponent<Toggle>();
        OnvalueChange(toggle.isOn);
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    public void OnvalueChange(bool isOn)
    {
        
        onGameObject.SetActive(isOn);
        offGameObject.SetActive(!isOn);
    }
}

设计登录面板

总结

  1. 终于结束了,好累
  2. 游戏开发之路开始很艰难,UGUI学起来就一卡一卡的,坚持!!!
  3. 记得复习!复习!复习!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值