【Unity基础】ugui的案例篇(个人学习)

article/2025/10/6 14:39:40

文章目录

  • 前言
  • 案例1、点击游戏物体改变一次颜色,被UI遮挡的情况下点击无效
    • 1.动态图演示
    • 2.实现方式
      • I.实现方案1 通过射线检测实现
    • 3.源码演示
      • Lua部分代码
      • CSharp部分代码
  • 案例2、圆形图片的制作
    • 1.图演示
    • 2.实现方式
      • I.实现方案1 使用Mask组件实现
      • II.实现方案2 通过重写Graphic类的OnPopulateMesh()方法重新写入顶点数据实现
    • 3.源码演示
      • 实现方案2的Lua部分代码
      • 实现方案2的CSharp部分代码
  • 案例3、基于圆形图片制作的类似技能CD的UI效果
    • 1.动图演示
    • 2.实现方式
    • 3.源码演示
      • Lua代码
      • CSharp部分代码
  • 案例4、点击多边形UI时,判断点击的区域是否有效
    • 1.动态演示
    • 2.实现方式
      • I.实现方案1 通过鼠标点击的屏幕坐标向右作射线,通过与UI轮廓的交点进行判断
      • II.实现方案2 通过多边形2D碰撞器检测实现
    • 3.代码演示
      • 实现方案1的CSharp部分代码
      • 实现方案2的CSharp部分代码
  • 案例5、实现3D图片循环滚动效果UI.
    • 1.动态图演示
    • 2.实现方式
    • 3.代码演示
      • Lua部分代码,主要用来初始化创建
      • CSharp部分代码,动画部分使用了DoTween插件
        • 存放数据的类
  • 案例6、实现自定义多边形可拖拽实时修改形状的UI组件(可以实现属性面板之类的功能)
    • 1.动态图演示
    • 2.实现方式
    • 3.代码演示
      • CSharp部分代码
        • CustomPloyImage类
        • CustonPolyImageHandler类
      • Lua初始化代码
  • 案例7、滚动视图的制作(案例无需代码)
    • 动态图演示
    • 实现步骤
      • 1.插件Scroll View游戏物体
      • 2.在Scroll View的子物体Viewport里面的Content物体添加Content-Size-Filter组件用来管理内容的布局,并且将Content-Size-Filter的Horizontal-fit 修改成perferred size 这样就可以让Content的高度跟着内容的高度改变而改变
      • 3.将内容排版进Content即可
  • 案例8、简单血条制作
    • 1.动图展示
    • 2.代码演示

前言

主要是为了进一步熟悉ugui,结合lua和C#做一些ugui的实践案例。(个人学习总结)
ugui基础案例工程为UGUIBasic文件夹
案例1、点击游戏物体改变一次颜色,被UI遮挡的情况下点击无效
案例2、圆形图片的制作
案例3、基于圆形图片制作的类似技能CD的UI效果
案例4、点击多边形UI时,判断点击的区域是否有效
案例5、实现3D图片循环滚动效果UI.
案例6、实现自定义多边形可拖拽实时修改形状的UI组件(可以实现属性面板之类的功能)
案例7、滚动视图的制作(案例无需代码)
案例8、简单血条制作

案例1、点击游戏物体改变一次颜色,被UI遮挡的情况下点击无效

1.动态图演示

请添加图片描述

2.实现方式

I.实现方案1 通过射线检测实现

进行两边检查。
检查一,点击鼠标的时候,通过GraphicRaycaster发射射线,检查是否击中UI层,如果有直接结束。
检查二,点击鼠标的时候,通过摄像机的PhysicsCaster发射射线,检查是否击中物体,通过击中修改颜色。

3.源码演示

Lua部分代码

--案例1、点击游戏物体改变一次颜色,被UI遮挡的情况下点击无效
local case1 = {}--相当于引用命名空间
local UnityEngine = CS.UnityEngine
local Vector3 = CS.UnityEngine.Vector3;
local PrimitiveType = CS.UnityEngine.PrimitiveType;
local UI = CS.UnityEngine.UI;
local Color = CS.UnityEngine.Color;
local Input = CS.UnityEngine.Input; 
local EventSystems = CS.UnityEngine.EventSystems; -- 被脚本的全局变量
local cubeObject = nil;  --成本创建的盒子物体
local clickNum = 0;     --鼠标点击次数case1.init = function ()-- 创建一个盒子 并且初始化角度cubeObject = UnityEngine.GameObject.CreatePrimitive(PrimitiveType.Cube);local initPosOffset = Vector3(0,0,10);cubeObject.transform.position = Vector3.zero + initPosOffset;cubeObject.transform.localScale = Vector3(2,2,2);cubeObject.transform.eulerAngles = Vector3(16,21,0);-- 创建UI 一个imagelocal imageObject = UnityEngine.GameObject("Image");local rectTransform = imageObject:AddComponent(typeof(UnityEngine.RectTransform)); local canvas = UnityEngine.GameObject.Find("Canvas");local canvasRectTransform = canvas:GetComponent(typeof(UnityEngine.RectTransform));imageObject.transform:SetParent(canvasRectTransform);rectTransform.anchoredPosition = Vector3(0,0,0);imageObject:AddComponent(typeof(UnityEngine.CanvasRenderer));local image = imageObject:AddComponent(typeof(UnityEngine.UI.Image));image.color = Color.red;
end-- 检查有没有点击到UI
local function checkClickUI()checkUtil = CS.CheckIsClickUI.Instance;res = checkUtil:isClickUI();return res;
end--检查是否点击到物体
local function checkClickObject() checkUtil = CS.CheckIsClickUI.Instance;res = checkUtil:isClickObject();return res;
end-- update生命周期
case1.update = function() if Input:GetMouseButtonDown(0) and cubeObject thenif checkClickUI() thenreturn;endif checkClickObject()==false thenreturn;endmaterial = cubeObject:GetComponent(typeof(UnityEngine.MeshRenderer)).material;if clickNum % 2 == 0 thenmaterial:SetColor("_Color",UnityEngine.Color.blue);elsematerial:SetColor("_Color",UnityEngine.Color.green);endclickNum = clickNum + 1;end
end return case1;

CSharp部分代码

public class CheckIsClickUI : UnitySingleton<CheckIsClickUI> { /// <summary>/// 判断是否点击到UI/// </summary>public bool isClickUI() {GraphicRaycaster graphicRaycaster = FindObjectOfType<GraphicRaycaster>();PointerEventData eventData = new PointerEventData(EventSystem.current);eventData.pressPosition = Input.mousePosition;eventData.position = Input.mousePosition;List<RaycastResult> results = new List<RaycastResult>();graphicRaycaster.Raycast(eventData, results);return results.Count > 0;}/// <summary>/// 判断是否点击到物品/// </summary>public bool isClickObject(){PhysicsRaycaster physicsRaycaster = FindObjectOfType<PhysicsRaycaster>();PointerEventData eventData = new PointerEventData(EventSystem.current);eventData.pressPosition = Input.mousePosition;eventData.position = Input.mousePosition;List<RaycastResult> results = new List<RaycastResult>();physicsRaycaster.Raycast(eventData, results);return results.Count > 0;}
}

案例2、圆形图片的制作

1.图演示

在这里插入图片描述

2.实现方式

I.实现方案1 使用Mask组件实现

其实可以直接使用Unity自带的Mask组件来实现,创建两个Image,然后再把一个Image变成另外一个Image的子物体,在父物体的Source texture上挂上带有alpha通道的png图片,alpha为0的地方对其进行遮罩就可以实现效果了,如下截图所示
在这里插入图片描述

II.实现方案2 通过重写Graphic类的OnPopulateMesh()方法重新写入顶点数据实现

虽然方案1可以实现,并且方案简单,但是性能上会很差,所有推荐使用方案2。
解读1:其实实现方式很简单,我们知道UI中的Image也是通过顶点数据显示出来的。

解读2:顶点是通过VertexHepler然后被CanvasRenderer渲染出来的。由因为所有可视化组件都会继承MaskabeGraphic类,而这个类右继承Graphic类,这个类会在自己的OnPopulateMesh()方法里面对VertexHepler进行顶点数据填充,

解读3:那么我们只需要自定义生成圆形Image的顶点数据。首先重新继承Image类,然后重写OnPopulateMesh()方法,修改里面的VertexHepler字段的数据就可以实现了。

3.源码演示

实现方案2的Lua部分代码

-- 案例2 圆形图片的制作
local case2 = {}--命名控件
local UnityEngine = CS.UnityEngine;
local Vector3 =  CS.UnityEngine.Vector3;
local Color = CS.UnityEngine.Colorcase2.init = function ()-- 创建UI 一个imagelocal imageObject = UnityEngine.GameObject("Image");local rectTransform = imageObject:AddComponent(typeof(UnityEngine.RectTransform)); local canvas = UnityEngine.GameObject.Find("Canvas");local canvasRectTransform = canvas:GetComponent(typeof(UnityEngine.RectTransform));imageObject.transform:SetParent(canvasRectTransform);rectTransform.anchoredPosition = Vector3(0,0,0);imageObject:AddComponent(typeof(UnityEngine.CanvasRenderer));local image = imageObject:AddComponent(typeof(CS.CircleImage));image.color = Color.white;
endreturn case2;

实现方案2的CSharp部分代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Sprites;/// <summary>
/// 实现圆形头像,基于Image所以直接继承Image类
/// </summary>
public class CircleImage : Image
{/// <summary>/// 创建使用,先对顶点加工运行/// </summary>/// <param name="toFill"></param>protected override void OnPopulateMesh(VertexHelper toFill){//清掉原来的顶点数据toFill.Clear();//获取UV数据。xy分量为min坐标,zw为max坐标Vector4 uv = Vector4.zero;if (overrideSprite != null) {uv = DataUtility.GetOuterUV(overrideSprite);} //获得uv的长度和宽度float uvWid = uv.z - uv.x;float uvHei = uv.w - uv.y;//获取当前UI的长度和宽度float wid = rectTransform.rect.width;float hei = rectTransform.rect.height;//转换向量比例计算Vector2 convertVect = new Vector2(uvWid/wid, uvHei/hei);//uv的中心点,必须要从uv的min坐标开始算Vector2 uvCenter = new Vector2((uvWid + uv.x) / 2, (uvHei + uv.y) /2);//圆心UIVertex cirleCenter = new UIVertex();cirleCenter.color = color;cirleCenter.position = Vector3.zero;  //顶点坐标。因为是一模型坐标来生成的顶点信息,所以直接认为中心点为0cirleCenter.uv0 = new Vector2(cirleCenter.position.x * convertVect.x + uvCenter.x, cirleCenter.position.y * convertVect.y + uvCenter.y);toFill.AddVert(cirleCenter);//把圆分成的份数int bran = 50;float radian = (2 * Mathf.PI) / bran;//弧度float radius = wid / 2;  //半径float curRadian = 0;//填充顶点for (int i = 0;i<bran + 1;i++) {float x = Mathf.Cos(curRadian) * radius;float y = Mathf.Sin(curRadian) * radius;curRadian += radian;UIVertex vertex = new UIVertex();vertex.position = new Vector2(x, y);vertex.color = color;//因为顶点带有负数,所以要变成正数vertex.uv0 = new Vector2(x * convertVect.x, y * convertVect.y) + uvCenter;toFill.AddVert(vertex);}//输入顶点顺序int index = 1;for (int i = 0;i < bran;i++) {toFill.AddTriangle(index, 0, index + 1);index++;}}
}

案例3、基于圆形图片制作的类似技能CD的UI效果

1.动图演示

请添加图片描述

2.实现方式

其实就是在案例2的基础上添加一个百分比字段,这个字段为浮点类型,取值从0到1,把这个百分比乘上形成这个圆的三角形个数就可以得到一部分的扇形,把这部分扇形的颜色加深且在时间的推移下修改这个字段的值即可实现。

3.源码演示

Lua代码

-- 案例3 技能CD
local case2 = {}--命名控件
local UnityEngine = CS.UnityEngine;
local Vector3 =  CS.UnityEngine.Vector3;
local Color = CS.UnityEngine.Color;
local Time = CS.UnityEngine.Time;
local UI = CS.UnityEngine.UI;--引用的变量
local image;
local updateNum = 0;
case2.init = function ()-- 创建UI 一个imagelocal imageObject = UnityEngine.GameObject("Image");local rectTransform = imageObject:AddComponent(typeof(UnityEngine.RectTransform)); local canvas = UnityEngine.GameObject.Find("Canvas");local canvasRectTransform = canvas:GetComponent(typeof(UnityEngine.RectTransform));imageObject.transform:SetParent(canvasRectTransform);rectTransform.anchoredPosition = Vector3(0,0,0);imageObject:AddComponent(typeof(UnityEngine.CanvasRenderer));image = imageObject:AddComponent(typeof(CS.CircleImage));image.color = Color.white;image.sprite=CS.TexManger.Instance:getSpriteByAssetName("minmap"); 
end--声明update函数
case2.update = function()if image.percent >=1 thenimage.percent = 0;end image.percent = image.percent + Time.deltaTime / 5;--修改渲染相关,需要调用ICavasElement的ReBuild()方法才会重新生效--需要让其重新刷新以下顶点数据image:SetVerticesDirty();
endreturn case2;

CSharp部分代码

using UnityEditor;
using UnityEngine;
using UnityEngine.Sprites;
using UnityEngine.UI;/// <summary>
/// 实现圆形头像,基于Image所以直接继承Image类
/// </summary>
public class CircleImage : Image
{/// <summary>/// 百分比/// </summary>[SerializeField]public float percent = 1;/// <summary>/// 创建使用,先对顶点加工运行/// </summary>/// <param name="toFill"></param>protected override void OnPopulateMesh(VertexHelper toFill){//清掉原来的顶点数据toFill.Clear();//uv的中心点,必须要从uv的min坐标开始算Vector2 uvCenter = getUvCenter();//转换向量比例计算Vector2 convertVect = getConvertVect();//计算并且添加顶点addVertex(toFill, uvCenter,convertVect);}private void addVertex(VertexHelper toFill,Vector2 uvCenter,Vector2 convertVect) {//圆心UIVertex cirleCenter = new UIVertex();cirleCenter.color = color;if (percent < 1){cirleCenter.color = new Color(90 / 255f, 90 / 255f, 90 / 255f);}//顶点坐标。因为是一模型坐标来生成的顶点信息,所以直接认为中心点为0cirleCenter.position = new Vector2(0.5f, 0.5f) - rectTransform.pivot;cirleCenter.uv0 = uvCenter;toFill.AddVert(cirleCenter);rectTransform.localScale = new Vector3(1, 1, 1);//把圆分成的份数int bran = 100;int inParceBran = (int)(bran * Mathf.Min(percent, 1));float radian = (2 * Mathf.PI) / bran;//弧度float radius = rectTransform.rect.width / 2;  //半径float curRadian = 0;//填充顶点for (int i = 0; i < bran + 1; i++){float x = Mathf.Cos(curRadian) * radius;float realX = x + cirleCenter.position.x;float y = Mathf.Sin(curRadian) * radius + cirleCenter.position.y;float realY = y + cirleCenter.position.y;Vector2 readPos = new Vector2(realX + cirleCenter.position.x, realY + cirleCenter.position.y);curRadian += radian;UIVertex vertex = new UIVertex();vertex.position = new Vector2(realX, realY);if (i >= inParceBran){vertex.color = color;}else{//不在访问的都设定为灰色vertex.color = new Color(90 / 255f, 90 / 255f, 90 / 255f);}//因为顶点带有负数,所以要变成正数vertex.uv0 = new Vector2(x, y) * convertVect + uvCenter;toFill.AddVert(vertex);}//输入顶点顺序int index = 1;for (int i = 0; i < bran; i++){toFill.AddTriangle(index, 0, index + 1);index++;}}/// <summary>/// 获取Uv的宽度和高度/// </summary>/// <returns></returns>private Vector2 getUvWidAndHei() {//获取UV数据。xy分量为min坐标,zw为max坐标Vector4 uv = Vector4.zero;if (overrideSprite != null){uv = DataUtility.GetOuterUV(overrideSprite);}//获得uv的长度和宽度float uvWid = uv.z - uv.x;float uvHei = uv.w - uv.y;return new Vector2 (uvWid, uvHei);}/// <summary>/// 得到UV坐标中心/// </summary>/// <returns></returns>private Vector2 getUvCenter(){Vector2 uvWH = getUvWidAndHei();//获取当前UI的长度和宽度float wid = rectTransform.rect.width;float hei = rectTransform.rect.height;return new Vector2(uvWH.x  / 2, uvWH.y / 2);}/// <summary>/// 获取转换用的坐标向量/// </summary>/// <returns></returns>private Vector2 getConvertVect() {Vector2 uvWH = getUvWidAndHei();//获取当前UI的长度和宽度float wid = rectTransform.rect.width;float hei = rectTransform.rect.height;return new Vector2(uvWH.x / wid, uvWH.y / hei);}
}

案例4、点击多边形UI时,判断点击的区域是否有效

1.动态演示

修改前,点击UI空白部分仍然会判断为有效区域。
请添加图片描述
修改后,点击UI空白部分判断为无效区域。
请添加图片描述

2.实现方式

I.实现方案1 通过鼠标点击的屏幕坐标向右作射线,通过与UI轮廓的交点进行判断

获取到点击屏幕的坐标,然后让这个点往右边发射一条射线,与多边形的UI进行形状进行相交,如果焦点数与2的余数为基数,那么直接认定点击的区域为有效区域。如下图所示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

II.实现方案2 通过多边形2D碰撞器检测实现

给UI添加PolygonCllider2D组件,如下图所示:
在这里插入图片描述
然后通过PolygonCllider2D组件自己提供的overlayPointer(Vertor2 point)来进行判断

3.代码演示

实现方案1的CSharp部分代码

 /// <summary>/// 判断操作是否有效/// </summary>/// <param name="localPoint"></param>/// <returns></returns>private bool IsValid(Vector2 localPoint) {int num = GetCrossPointNum(localPoint, vertexCache); return num % 2 == 1;}/// <summary>/// 用点击的点沿着屏幕x轴发射一条线与UI轮廓获取次数/// </summary>/// <param name="localPoint"></param>/// <returns></returns>private int GetCrossPointNum(Vector2 localPoint,List<Vector2> vertexList) {int crossPointNum = 0;int vertextNum = vertexList.Count; for (int i = 0;i< vertextNum; i++) {Vector2 vect1 = vertexList[i];Vector2 vect2 = vertexList[(i+1)% vertextNum];//做一些过滤,以屏幕的y坐标为参考,y坐标不在线段范围内直接过滤掉if (vect1.y > vect2.y){if (localPoint.y > vect1.y){continue;}if (localPoint.y < vect2.y){continue;}}else if (vect2.y > vect1.y) {if (localPoint.y > vect2.y){continue;}if (localPoint.y < vect1.y) {continue;}}//用方程 y = localPosition.y 与 y = kx + b(满足vect2.x,vect2.y与vect1.x,vect1.y的方程相交再判断交点x的范围)float k = (vect1.y - vect2.y)/(vect1.x-vect2.x);float b = vect2.y - vect2.x * k;float localPosX = localPoint.y/k - b/k;//不往右边延长if (localPosX < localPoint.x) continue;if (vect1.x > vect2.x){  if (localPosX > vect1.x){continue;}if (localPosX < vect2.x){continue;}}else if (vect1.x < vect2.x  ){if (localPosX > vect2.x) {continue;}if (localPosX < vect1.x) {continue;}}//运行到这里符合焦点crossPointNum ++;}return crossPointNum;}

实现方案2的CSharp部分代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class CustomImage : Image{private PolygonCollider2D polygonCollider2D;protected override void Awake(){polygonCollider2D = GetComponent<PolygonCollider2D>();}public override bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera){Vector2 localPos;RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform,screenPoint, eventCamera,out localPos);if (localPos == null) {return false;}return polygonCollider2D.OverlapPoint(localPos);}
}

案例5、实现3D图片循环滚动效果UI.

1.动态图演示

请添加图片描述

2.实现方式

解读1:使用了伪3D的方式来实现这一效果,按照UI物体的Scaler的X轴大小来进行排序,然后按照排序后的结构使用setsiblingIndex来改变物体的父物体下的顺序,进而改变显示的顺序。

解读2:在z轴方向,套用了圆。每张图片按照圆的运动轨迹上的各个点来修改图片的缩放和坐标,来达到视觉效果
在这里插入图片描述

3.代码演示

Lua部分代码,主要用来初始化创建

-- 3d滚动图实现
local case5 = {}local UnityEngine = CS.UnityEngine;
local Color = CS.UnityEngine.Color;case5.init = function ()--找到画布local canvas = UnityEngine.GameObject.Find("Canvas");scroll3DImage = UnityEngine.GameObject("scroll3DImage");rect = scroll3DImage:AddComponent(typeof(UnityEngine.RectTransform));rect:SetParent(canvas.transform);scroll3DImage:AddComponent(typeof(CS.Scroll3DImage));
endreturn case5

CSharp部分代码,动画部分使用了DoTween插件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using DG.Tweening;/// <summary>
/// 滚动3D图片组件
/// </summary>
public class Scroll3DImage : MonoBehaviour, IDragHandler, IEndDragHandler
{//默认4张图片public int itemNum = 4;//原来的4张private int itemNumCache = 4;//播放动画时间private int animalTime = 1;public Vector3 minScaler = new Vector3(0.5f, 0.5f, 1);public Vector3 maxScaler = Vector3.one;//拿到当前物体的RectTransform组件RectTransform rectTransform;//做图片位置用public List<ScrollImage> imageObjects;public List<ScrollImage> cahceList;void Start() {imageObjects = new List<ScrollImage>();cahceList = new List<ScrollImage> ();itemNumCache = itemNum;rectTransform = GetComponent<RectTransform>();rectTransform.sizeDelta = new Vector2(800, 600);rectTransform.anchoredPosition = Vector2.zero;InitSpriteRes();}void Update() {fresh();}/// <summary>/// 监听并且修改元素,一般情况下不会动这个函数/// </summary>void fresh() {if (itemNum == itemNumCache) {return;}//发现和原来不相等重新刷新并且生成滚动的子物体itemNumCache = itemNum;InitSpriteRes();}/// <summary>/// 初始化资源/// </summary>void InitSpriteRes() {//把原来的东西销毁掉//刚刚初始化的时候物体必定为空的东西for (int i = 0; i < imageObjects.Count; i++) {Destroy(imageObjects[i].transform.gameObject);}imageObjects.Clear(); cahceList.Clear();//获取对象模板GameObject temple = CreateItemTemp();//先做颜色缓存float offsetColor = 1 / (float)itemNum;for (int i = itemNum -1; i >=0; i--) {GameObject item = Instantiate(temple);ScrollImage scrollImage = item.AddComponent<ScrollImage>(); scrollImage.SetParent(transform);//为了区分不同的item稍微改改颜色item.GetComponent<Image>().color = new Color(offsetColor * i, offsetColor * i, offsetColor * i);imageObjects.Add(scrollImage);scrollImage.Order = i;//初始化坐标float x = GetX(scrollImage.Order);scrollImage.GetRectTransform().sizeDelta = new Vector2(200, 200); scrollImage.GetRectTransform().anchoredPosition = new Vector3(x, 0, 0);scrollImage.GetRectTransform().localScale = GetScale(i);cahceList.Add(scrollImage);//scrollImage.transform.SetSiblingIndex(scrollImage.Order);}cahceList.Sort(cacheListSort);for (int i = 0;i < cahceList.Count;i++ ) {cahceList[i].transform.SetSiblingIndex(i);}//模板用完丢掉Destroy(temple);}public int cacheListSort(ScrollImage x, ScrollImage y) {if (x.GetRectTransform().localScale.x > y.GetRectTransform().localScale.x)return 1;elsereturn -1;}/// <summary>/// 获取这个元素的x/// </summary>/// <param name="index">元素的索引</param> public float GetX(int index) {float gradient = GetGradient(index);return 2 * rectTransform.rect.width * gradient;}/// <summary>/// 获取变化梯度/// </summary>/// <returns></returns>public float GetGradient(int index) {float gradient = 1 / (float)itemNum * (float)index;if (gradient >= 0 && gradient <= 0.25){return gradient;}else if (gradient > 0.25 && gradient <= 0.5){return (0.5f - gradient);}else if (gradient > 0.5 && gradient <= 0.75){return 0.5f - gradient;}else{return -(1f - gradient);}return gradient;}/// <summary>/// 获取缩放/// </summary> public Vector3 GetScale(int index) { Vector3 offsetScale = (maxScaler - minScaler) / 0.5f;float offsetX = GetX(index);float gradient = 1 / (float)itemNum * (float)index; ;//返回最大和最小的情况if (gradient == 0 || gradient == 1) {return maxScaler;}if (gradient == 0.5) {return minScaler ;}if (gradient > 0f && gradient < 0.5f) {return maxScaler - (gradient  * offsetScale);}return maxScaler - ((1f- gradient) * offsetScale);}/// <summary>/// 创建模板对象/// </summary>GameObject CreateItemTemp() {GameObject gameObject = new GameObject("Item");Image image = gameObject.AddComponent<Image>();Sprite sprite = TexManger.Instance.getSpriteByAssetName("minmap");image.sprite = sprite;return gameObject;}public void OnDrag(PointerEventData eventData){Vector2 vector = eventData.delta;}public void OnEndDrag(PointerEventData eventData){Vector2 vector = eventData.delta;//Debug.Log(vector);ChangeOrder(vector.x);}/// <summary>/// 修改层级/// </summary>public void ChangeOrder(float offsetX) {int moveX = offsetX > 0 ? 1 : -1;for (int i = 0; i < imageObjects.Count; i++) {int lastIndex = imageObjects[i].Order + moveX;if (lastIndex < 0){lastIndex = imageObjects.Count - 1;}else if (lastIndex > imageObjects.Count - 1) {lastIndex = 0;}imageObjects[i].Order = lastIndex;imageObjects[i].SetScrollImageData(lastIndex); }cahceList.Clear();for (int i = 0; i < imageObjects.Count; i++) { updateData(imageObjects[i]);cahceList.Add(imageObjects[i]);}cahceList.Sort(cacheListSort);for (int i = 0; i < cahceList.Count; i++){cahceList[i].transform.SetSiblingIndex(i);}}/// <summary>/// 等一般的动画时间过后才能往下执行换元素顺序/// </summary>/// <returns></returns>IEnumerator Wait(){yield return new WaitForSeconds(animalTime/2);for (int i = 0; i < cahceList.Count; i++){cahceList[i].transform.SetSiblingIndex(i);}}/// <summary>/// 更新数据/// </summary>/// <param name="scrollImage"></param>public void updateData(ScrollImage scrollImage){float newX = GetX(scrollImage.Order);Vector3 newScaler =  GetScale(scrollImage.Order);scrollImage.GetRectTransform().localScale = newScaler; scrollImage.GetRectTransform().DOAnchorPos(new Vector2(newX, 0), animalTime);scrollImage.GetRectTransform().DOScale(newScaler, animalTime);} 
}

存放数据的类

using System.Collections;
using System.Collections.Generic;
using UnityEngine;[RequireComponent(typeof(RectTransform))]
public class ScrollImage : MonoBehaviour
{  public int Order = 0;         //UI元素的排列方式 /// <summary>/// 这个物体的UI布局组件/// </summary>RectTransform rectTransform;private void Awake(){rectTransform = GetComponent<RectTransform>();}/// <summary>/// 设置父物体/// </summary> public void SetParent(Transform transform) {rectTransform.SetParent(transform);}/// <summary>/// 获取物体的Rect/// </summary> public RectTransform GetRectTransform() { return rectTransform;}/// <summary>/// 修改层级显示/// </summary>public void SetScrollImageData(int order) {this.Order = order;}
}

案例6、实现自定义多边形可拖拽实时修改形状的UI组件(可以实现属性面板之类的功能)

1.动态图演示

请添加图片描述
请添加图片描述

2.实现方式

实现原理和案例2一样,只是多加了一个功能需要,可以修改对应拖拽的点来修改多边形形状

3.代码演示

CSharp部分代码

CustomPloyImage类

/// <summary>
/// 自定义多边形UI组件
/// </summary>
public class CustomPolyImage : Image
{//构成的点集合List<CustomPloyImageHandler> pointList = null;/// <summary>/// 构成多边形的点数/// </summary>[SerializeField]public int pointNum = 5;protected override void Awake(){base.Awake();fresh();SetVerticesDirty();}/// <summary>/// 重新编写顶点数据/// </summary>/// <param name="toFill"></param>protected override void OnPopulateMesh(VertexHelper toFill){toFill.Clear();AddVerts(toFill);AddTriangles(toFill);}/// <summary>/// 添加顶点/// </summary>void AddVerts(VertexHelper toFill) {for(int index = 0;index < pointList.Count;index++ ) {CustomPloyImageHandler handler = pointList[index];UIVertex v = new UIVertex();if (index != 0) {v.color = Color.red; ;}v.position = handler.rectTransform.anchoredPosition;toFill.AddVert(v);}}/// <summary>/// 添加三角形索引/// </summary>void AddTriangles(VertexHelper toFill) {int id = 1;for (int i = 0;i<pointNum;i++){int nextId = id + 1;if (nextId > pointNum) {nextId = 1;}toFill.AddTriangle(id, 0, nextId);id++;}  }/// <summary>/// 初始化点/// </summary>void InitPoint() {  for (int index = 0; index < pointNum + 1;index++) {GameObject go = new GameObject ("Point"+index); CustomPloyImageHandler handler = go.AddComponent<CustomPloyImageHandler>();handler.SetParent(transform.transform);handler.color = Color.blue;InitPointRect(index, handler);pointList.Add (handler);}}/// <summary>/// 初始化点的位置/// </summary>void InitPointRect(int index, CustomPloyImageHandler handler){handler.rectTransform.sizeDelta = new Vector2(10,10);//第一个为中心点,必定是0,0处if (index == 0) {handler.rectTransform.anchoredPosition = Vector2.zero;return;}//弧度float radius = 2 * Mathf.PI /(float)pointNum * (index - 1);//半径,直接认为是宽度float width = rectTransform.rect.width / 2;float x = Mathf.Cos(radius) * width;float y = Mathf.Sin(radius) * width;handler.rectTransform.anchoredPosition = new Vector2(x, y);}void ClearPoint() {foreach (CustomPloyImageHandler handler in pointList) {DestroyImmediate (handler);  //立即销毁}pointList.Clear ();}/// <summary>/// 刷新函数/// </summary>void fresh() {pointList = new List<CustomPloyImageHandler>();rectTransform.sizeDelta = new Vector2(500,500);ClearPoint();InitPoint();}
}

CustonPolyImageHandler类

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;[RequireComponent(typeof(RectTransform))]
public class CustomPloyImageHandler : Image,IDragHandler
{public void OnDrag(PointerEventData eventData){rectTransform.anchoredPosition += eventData.delta / rectTransform.lossyScale.x;//通知父物体进行脏标记rectTransform.parent.gameObject.GetComponent<CustomPolyImage>().SetVerticesDirty();}/// <summary>/// 修改父物物体/// </summary>/// <param name="transform"></param>public void SetParent(Transform transform){  rectTransform.SetParent(transform);}
}

Lua初始化代码

-- 3d滚动图实现
local case6 = {}local UnityEngine = CS.UnityEngine;
local Color = CS.UnityEngine.Color;
local Vector2 = CS.UnityEngine.Vector2;case6.init = function ()--找到画布local canvas = UnityEngine.GameObject.Find("Canvas");PloyImage = UnityEngine.GameObject("PloyImage");rect = PloyImage:AddComponent(typeof(UnityEngine.RectTransform)); rect:SetParent(canvas.transform);PloyImage:AddComponent(typeof(CS.CustomPolyImage));rect.anchoredPosition = Vector2(0,0);
endreturn case6

案例7、滚动视图的制作(案例无需代码)

动态图演示

请添加图片描述

实现步骤

1.插件Scroll View游戏物体

2.在Scroll View的子物体Viewport里面的Content物体添加Content-Size-Filter组件用来管理内容的布局,并且将Content-Size-Filter的Horizontal-fit 修改成perferred size 这样就可以让Content的高度跟着内容的高度改变而改变

3.将内容排版进Content即可

案例8、简单血条制作

1.动图展示

血量越少,血条的进度就跟着减少。
50%以上血量为翡翠绿色
20% - 50 % 的血量为橘色
20%以下血量为红色
请添加图片描述

2.代码演示

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;/// <summary>
/// 挂上这个组件自动申请别的组件
/// </summary>
[RequireComponent(typeof(RectTransform))]
public class CustomLifeBarComponet : MonoBehaviour 
{RectTransform rectTransform;RectTransform liftBarRect;/// <summary>/// 健康血量颜色/// </summary>Color color1 = new Color(83/255f,137/255f,64/255f);/// <summary>/// 风险血量颜色/// </summary>Color color2 = new Color(243 / 255f, 124 / 255f, 54 / 255f);/// <summary>/// 风险血量颜色/// </summary>Color color3 = new Color(243 / 255f, 65 / 255f, 74 / 255f);public  float curHitPoint = 1f; void Update() {if (Input.GetKey(KeyCode.D)) {curHitPoint +=  1/10f * Time.deltaTime * 2;if (curHitPoint >= 1) {curHitPoint = 1;}}if (Input.GetKey(KeyCode.A)){curHitPoint -= 1 / 10f*Time.deltaTime * 2;if (curHitPoint <= 0){curHitPoint = 0;}} liftBarRect.offsetMax = new Vector2((curHitPoint - 1) * rectTransform.rect.width, liftBarRect.offsetMax.y);if (curHitPoint > 0.5) {liftBarRect.GetComponent<Image>().color = color1;}if (curHitPoint>0.2 && curHitPoint <= 0.5 ) {liftBarRect.GetComponent<Image>().color = color2;}if (curHitPoint< 0.2) {liftBarRect.GetComponent<Image>().color = color3;}}//当前血量private void Awake(){rectTransform = GetComponent<RectTransform>();rectTransform.anchoredPosition = Vector2.zero;liftBarRect = gameObject.transform.GetChild(1).GetComponent<RectTransform>();  }}

http://chatgpt.dhexx.cn/article/0ZN93J18.shtml

相关文章

Unity UGUI源码解析

前言 这篇文章想写的目的也是因为我面试遇到了面试官问我关于UGUI原理性的问题&#xff0c;虽然我看过&#xff0c;但是并没有整理出完整的知识框架&#xff0c;导致描述的时候可能自己都是不清不楚的。自己说不清楚的东西&#xff0c;别人就等于你不会。每当学完一个东西的时…

UGUI基础学习

目录 TEXT IMAGE ROWIMAGE TEXT fontsize:字体 color&#xff1a;字体颜色 ;inespacing:字行间隔 代码展示&#xff1a; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI;public class TEXTtest : MonoBehaviour {p…

UGUI源码解析——总览

一&#xff1a;图像相关 ——UIBehaviour&#xff1a;UI组件的基类&#xff0c;继承MonoBehaviourUGUI源码解析——UIBehaviour——CanvasUpdateRegistry&#xff1a;图像、布局重建注册器UGUI源码解析——CanvasUpdateRegistry——ICanvasElement&#xff1a;图像、布局重建接…

UGUI 全方位了解

随着 unity3d 4.6 ~ 5.x 新 UI 系统终于与大家见面了。这篇文章将不会介绍如何使用按钮、滚动条之类的UI控件&#xff0c;这些内容可以参考 Unity Manual&#xff1b;这篇文章的重点是&#xff0c;如何理解 UI 系统的设计&#xff0c;以便更好的在实际中使用它。 RectTransfor…

UI框架(UGUI)

整个游戏的工程源码下载链接&#xff1a;点击打开链接 可以参考的写的Demo和本文章来学习 毕竟有些细节问题在文章中不能一一说到 工具&#xff1a;VS2010、Unity5.2.3f 先介绍整个Demo的主面板 其中任务、技能、符文等等都是按钮&#xff0c;点击按钮会生成相应面板 【Pro…

UGUI相关使用

UGUI 文章目录 UGUI1.六大基础组件概述1.1 Canvas组件1.2 CanvasScaler组件1.3 Graphic Raycaster组件1.4 Event System组件1.5 Standalone Input Module组件1.6 RectTransform组件 2.三大基础控件概述2.1 图像控件Image2.2 文本控件Text2.3 RawImage原始图像组件 3.七大组合控…

Unity UGUI系统

UI系统对比 对 UI 系统的选择取决于是为 Unity 编辑器开发 UI&#xff0c;还是为游戏或应用程序开发运行时 UI。 UI 的类型UI 工具包Unity UI(uGUI)IMGUI注意事项运行时&#xff08;调试&#xff09;✔ *✔✔这指用于调试用途的临时运行时 UI。运行时&#xff08;游戏内&…

UGUI 详解

1.RectTransform RectTransform组件 继承自Transform组件&#xff0c;是2D界面中元素的Transform。 对比Transform增加了新的属性分别是&#xff1a;Anchor&#xff08;锚点&#xff09;和 Pivot&#xff08;轴心点&#xff09;。 属性&#xff1a; localPosition&#xff1a;图…

UGUI学习笔记(八)UGUI不规则响应区域

一、Unity自带的点击策略 在上一篇文章中我们了解到&#xff0c;UI的默认响应区域是UI元素所在的矩形框线内的区域。这也就意味着&#xff0c;当UI的图形为不规则形状时&#xff0c;点击图形的外部也可能会触发事件。 但其实Unity自带了一种不规则区域点击策略。要想使用它&…

[Unity UGUI图集系统]浅谈UGUI图集使用

**写在前面&#xff0c;下面是自己做Demo的时候一些记录吧&#xff0c;参考了很多网上分享的资源 一、打图集 1.准备好素材&#xff08;建议最好是根据图集名称按文件夹分开&#xff09; 2、创建一个SpriteAtlas 3、将素材添加到图集中 4、生成图集 到此&#xff0c;我们的图…

Ngui和Ugui的区别

NGUI的元素更新&#xff1a; UIPanel.LateUpdate采用轮询的方式&#xff0c;每帧都会执行&#xff0c;并且每帧都会有UIPanel.UpdateWidgets这个函数的调用&#xff0c;做的事情就是对这些UI元素的位置、缩放等信息的获取&#xff0c;也就是即使没有变化的UI元素&#xff0c;也…

Unity—UGUI

每日一句&#xff1a;读数、学习 去更远的地方&#xff0c;才能摆脱那些你不屑一顾的圈子 目录 InputFiled输入框 例&#xff1a;用户名和密码 Toggle组件 案例&#xff1a;冷却效果 InputFiled输入框 Text Component 输入文本组件 Text输入内容 Character Limit 输入字符…

【Unity3D】UGUI概述

1 UGUI 与 GUI 区别 GUI控件 在编译时不能可视化&#xff0c;并且界面不太美观&#xff0c;在实际应用中使用的较少。UGUI 在编译时可视化&#xff0c;界面美观&#xff0c;实际应用较广泛。 2 Canvas 渲染模式&#xff08;Render Mode&#xff09; Screen Space - Overlay&a…

怎样使用UGUI

什么是 UGUI UGUI 是 Unity 自带的一套 GUI 系统&#xff0c;含有基本的一些 UI 控件。 UGUI 控件有哪些&#xff1f; 我们常用的有 Canvas&#xff0c;Text&#xff0c;Image&#xff0c;Button&#xff0c;Toggle&#xff0c;Slider&#xff0c;Scroll Bar&#xff0c;Scroll…

Unity3D UGUI系列之合批

目录 1. 什么是UGUI的合批1.1 准备工作1.2 批处理1.3 批处理的意义1.4 UGUI的合批 2 分析工具的使用2.1 Frame Debugger的使用2.2 Profiler-UI的使用 3 UGUI合批规则3.1 UGUI合批初体验3.2 UGUI合批被打断初体验3.3 UGUI合批规则详解3.3.1 合批规则3.3.2 合批规则示例13.3.3 合…

unity中NGUI与UGUI的区别?

什么是UI? UI即User Interface&#xff08;用户界面&#xff09;的简称。泛指用户的操作界面&#xff0c;UI设计主要指界面的样式&#xff0c;美观程度。而使用上&#xff0c;对软件的人机交互、操作逻辑、界面美观的整体设计则是同样重要的另一个门道。好的UI不仅是让软件变得…

【UGUI】UGUI入门,系统介绍

Unity 2017.1.0f3 常用的UI控件 添加UI控件 创建UI控件时&#xff0c;如果没有Canvas和EventSystem系统会自动创建。 Canvas是画布&#xff0c;是所有UI控件的根类&#xff0c;所有UI控件都必须在Canvas上绘制。如果UI控件不在Canvas下&#xff0c;将无法正常渲染显示。 Eve…

UGUI框架

记录最新学习的UGUI框架。 UIType类保存面板基本信息&#xff08;名称、路径&#xff09;&#xff0c;该面板会在具体的面板类里面&#xff08;StartPanel&#xff09;进行实例化。 public class UIType {private string name;public string Name { get > name; }private …

UGUI的简单理解

1.Canvas(画布) UGUI中几乎所有的组件都要在Canvas下搭建 2.EventSysteam(事件系统) 如果进行UI搭建的时候,缺少或删除了EventSysteam的话会导致UGUI中的组件无法交互,无法发生事件. 3.Panel 平时我们进行UI工程搭建的时候,我们都会先创建Panel面板,创建Panel面板的…

UGUI底层

关于UGUI底层的小知识---上 (转雨松momo) 1 | UGUI原理简述 1.1 原理 首先得生成显示UI用的Mesh&#xff0c;如图1-1所示&#xff0c;一个矩形的Mesh&#xff0c;由4个顶点&#xff0c;2个三角形组成&#xff0c;每个顶点都包含UV坐标&#xff0c;如果需要调整颜色&#xf…