目录
解决:选择图片,按Alt,选择锚点,实现图片的宽度和高度和父物体保持一致
什么是UGUI
unity graphic user interface,简称UI,游戏UI,用户接口
Canvas画布
- Rect Transform 多了一些自身宽度和高度
- 画布就是UI容器
Text文本控件

- 字体资源要导入Unity里
- 富文本就是可以用标签修改文本,比如<b></b>对文本加粗
图片Image控件

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

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

- 宽度,高度以像素为单位
Button控件

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


- 把挂载在游戏对象Main Camera拖到Button组件点击事件中
- 选择该游戏对象上的脚本上的方法,作为鼠标点击触发事件
- 类似c#中的事件,鼠标点击后,触发调用列表的所有方法
Anchor锚点
登录UI功能开发

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

单选和多选按钮

- 创建空游戏物体对象,添加组件Toggle
- Target Graphic目标图形是背景图片,创建图片,并且拖拽赋值
- Is on 是否开启,勾选是默认开启
- Graphic 图片一般是赋值打勾图片,点击后激活该图片
如何实现男女只能选择一个的


- Toggle男,Toggle女创建空父对象
- 父对象添加Toggle Group组件
- 把父对象拖拽到子对象Toggle组件里Group属性
- 相对于给它们分成一个组里
Slider滑动器


- 滑动时,Value值会改变
- 值变化时,会触发列表的方法
- Target Graphic 是进度条圈圈图片
图片的Sliced 已切片
导入缺少的包



- 绿线设置边框,绿色线外部部分就是边框Border
- 左右拉伸,上下拉伸,四个角不会随着拉伸而改变
- 对于上下边框,上下拉伸不会等比例拉伸,左右拉伸会拉长(会变模糊)
- 对于左右边框,左右拉伸不会等比例拉伸,上下拉伸会拉长(会变模糊)
- 在于设计按钮时候,可以设计可以任意缩放的按钮
- Fill Center填充,勾选会挖空除了边框的内容
图片的Tiled 平铺
按照原本的大小平铺在里面,不够会塞到满
图片的Filled 已填充
应用:技能cd

滚动条和下拉列表
案例介绍
![]()
导入资源包

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

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

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

只有高度和父物体保持一致,只有高度会被拉伸,宽度不会被拉伸
图片足够宽,就能填充满整个屏幕

开发开始界面-背景和声音按钮
点击后,阴影效果的图片设置为子物体Image

设置锚点为左上

设置锚点为右上

开发设置、游戏和开始按钮
- 按shift拉伸图片,等比例缩放
- 按shift+Alt拉伸图片,在图片中心点等比例缩放
- 添加Shadow组件,控制文字阴影

开发头像面板

开发血量条


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

开发技能冷却效果

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

- 通过Shadow设置字体阴影
- 通过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;
}
}
}
- 把脚本挂载到游戏物体上,再拖拽到Button组件中
- 当点击图标后,会触发Button事件,调用挂载在Button的全部方法
- transform.Find("ColdMask").GetComponent<Image>();通过transform.Find找到挂载在的对象的子物体ColdMask,再通过GetComponent获取到Image组件
- 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;
}
}
}
-
Input.GetKeyDown(KeyCode.Alpha1)点击数字1返回true
-
可以把KeyCode.Alpha1设置为public的变量,方便在Unity里修改
Panel面板
、
- 面板图片等等有边框的,都需要设置边框,不然拉伸会变模糊
- 画布上,面板,背景图片都需要设置锚点,拉伸之后不会偏移
开发我的背包面板

设计人物的属性

开发背包的选项卡

- 添加Toggle组件,三个选择一个默认开启Is On
- 设置为单选,创建一个父对象,在父对象上添加Toggle Group组件
- 把父对象拖拽给子对象Toggle组件的Group设置为同一组
- 可以通过代码改变选择时候的字体颜色
开发物品面板的切换
实现思路
- 点击不同的选项时候,Is On会取消勾选,会触发函数,另一个选项,Is On会勾选,也调用函数
- 拖拽Panel1游戏物体到Toggle的触发函数里,调用GameObject.SetActive改变状态
- 点击任务选项,触发Item1的函数,把Panel1状态设置为未激活
- 同时,任务选项被点击,触发Item2的函数,改变Panel2的状态为激活


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

设计关卡选择面板

可以把能复用的游戏对象设置为Prefab预制体
设计关卡按钮和锁关按钮

设计关卡的网格列表

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

把Grid的原点设置在左边,这样宽度增加,会向右边延申
如果在中间会向两边延申
一让关卡列表滚动起来
- 创建一个父空对象,宽高设置为要显示的宽高,比如显示8个单元格,根据单元格计算宽高
- 在父对象中,添加Scroll Rect组件,把带有网格组件的Grid子对象拖拽给Content内容
- 超出父对象高宽的可以滚动

问题:只有点击成就图片才能滚动
- 添加图片Image组件解决,Image组件的Raycast Target可以检测点击碰撞
- 图片颜色设置为透明
- ScrollRect 组件禁止垂直滚动


Mesh组件
- 添加Mesh组件,实现当滚动超过高宽时候,不显示
- 问题:添加Mesh组件后,Image透明度设置为零,子问题透明度也为零
- 解决:取消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;
}
}
}
}
通过页面按钮控制滚动列表跳转
- 先在下方设置单选功能的选项
- 点击时候触发挂载在ScrollRect游戏对象上的LevelScrollRect脚本里的方法
- 比如点击第二个选项,就调用方法把页面位置更新为第二页,实现同步
- 同时,也要实现当页面滚动时,选项的改变
- 页面滚动是在脚本里实现的,选项改变是在toggle组件的isOn属性改变的
- 所以,在脚本里实现改变isOn属性
- 在脚本里,定义一个toggle类型的数组,通过数组.isOn改变
- 在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];
}
}
}
开发任务列表背景和任务项

- 背景用预制体Prefab复用
- 其他用图片Image,加上各种组件
- 完成选项有Button组件
使用VerticalLayout进行任务列表布局
垂直网络布局VerticalLayoutGroup

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


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

设计谁易程度单选按钮

- 遇到个问题,文字高宽覆盖其他选项会出错,比如点击中等会显示简单
- 多选变单选就是添加父对象,在父对象上添加Toggle Group组件
- 再把子对象的Toggle组件的Group组都设置为父对象,实现单选
设计自定义开关,添加声音和背景开关

识笔识别颜色

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

重新添加Toggle组件,拖拽脚本,就没问题了
思路
- Toggle组件只能让一张图片显示或隐藏,现在这个包括两文字和两图片
- 把两对图片和文字分别放在两个游戏对象上,通过控制游戏对象的状态(激活与未激活)显示开关
- 添加Toggle组件在两个游戏对象的父对象上,利用Toggle的触发方法,当点击之后,把参数Is On传递给调用列表的方法
- 再通过代码去实现对子对象状态的修改
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);
}
}
设计登录面板

总结
- 终于结束了,好累
- 游戏开发之路开始很艰难,UGUI学起来就一卡一卡的,坚持!!!
- 记得复习!复习!复习!
本文详细介绍了Unity中的UGUI系统,包括Canvas、Text、Image、Button、Anchor、登录UI开发、单选/多选按钮、滑动器、图片布局以及处理不同分辨率下的适配。还涵盖了网格布局、滚动条、列表滚动、事件处理和面板设计等内容。


2415

被折叠的 条评论
为什么被折叠?



