uGUI备忘

本文深入探讨Unity的用户界面系统UGUI,包括ContentSizeFitter组件的使用、RectTransform的调整技巧、文本显示特性、粒子系统与UI的交互,以及小地图优化等高级主题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

UGUI 源代码

地址

之前以为Unity 收了NGUI后,重新开发UI,提供的UGUI是引擎层的(C++实现),其实不是。

ContentSizeFitter:

该组件可以帮我们在空间内容发生变化导致空间尺寸改变时,重新计算RectTransform。

但在复杂的UI应用中,可能我们给文本赋值后,没有正确地计算RectTransform,那么我们需要手动触发计算:

RectTransform rt;
UnityEngine.UI.LayoutRebuilder.ForceRebuildLayoutImmediate(rt);

RectTransform

改变RectTransform的top

GetComponent<RectTransform>().offsetMax = new Vector2(GetComponent<RectTransform>().offsetMax.x, top);

改变RectTransform的bottom

GetComponent().offsetMin = new Vector2(GetComponent().offsetMin.x, bottom);

改变RectTransform的width,height

GetComponent<RectTransform>().sizeDelta = new Vector2(width, height);

改变RectTransform的pos

GetComponent<RectTransform>().anchoredPosition3D = new Vector3(posx,posy,posz);
GetComponent<RectTransform>().anchoredPosition = new Vector2(posx,posy);

更新子元素前后关系

RectTransform.SetSiblingIndex,越小,会在Hierarchy的上面,会先渲染。

Text

获取文本显示的宽高

Text txtObject;
String str;
TextGenerationSetting settings = txtObject.GetGenerationSettings(Vector2.zero);
Vector2 sz = Vector2.zero;
sz.x = txtObject.cachedTextGeneratorForLayout.GetPreferedWidth(str, settings);
sz.y = txtObject.cachedTextGeneratorForLayout.GetPreferedHeight(str, settings);

获取文本mesh构造信息

Text txtObject;
String str;
TextGenerationSetting settings = txtObject.GetGenerationSettings(Vector2.zero);
UICharInfo[] arrCh = txtObject.cachedGeneratorForLayout.Populate(str, settings);

UICharInfo存储了构造Mesh需要的数据

获取文本在RectTransform内显示的行数(宽度固定)

遍历UICharInfo,累计UICharInfo.charWidth,如果宽度超过RectTransform.sizeDelta.x,则换行。

字库文件过大

可以用FontCreator来精简,合并字库。合并后还能能带来额外的提升合批效率的好处

描边和阴影

描边会增加4次绘制(上下左右),阴影一次

静态字体

对于在UI上显示的文本,要显示的不同文字的个数是确定的(不像聊天,用户可以输入),所以可以用SDF来降低字库大小,可以使用TextMeshPro插件。

字体花屏

对于动态字体,UGUI会创建字体渲染缓冲贴图,将要显示的字体绘制在上面,再通过该贴图绘制到UI上。该贴图最大是4096x4096(根据平台支持最大贴图尺寸)。当贴图到达最大尺寸,且有新文字不再缓冲贴图上,则会刷新该贴图,将最近不用的文字删除,这时会造成字体花屏,尤其是帧速率慢时(比如加载时)。

解决办法:

监听字体刷新事件:Font.textureRebuilt

发现刷新时,将UI中所有Text的刷新一遍:Text.FontTextureChanged()

public class CheckFontTextureRebuilt : MonoBehaviour
{
    private Font _changedFont;
    void Start()
    {
        Font.textureRebuilt += (Font font)=>{_changedFont = font};
    }
    
    void Update()
    {
    	if(_changedFont != null)
    	{
    		Text[] allText = GameObject.FindObjectsOfType<Text>();
    		if(allText != null)
    		{
    			foreach(Text text in allText)
    			{
    				if(text.font == _changedFont)
    					text.FontTextureChanged();
    			}
            }
            _changedFont = null;
    	}
    }
}

基础控件事件

Button

  • 事件监听:Button.onClick.AddListener

Toggle

  • 事件监听:Toggle.onValueChanged.AddListener
  • 设置选中状态:Toggle.isOn

Slider

  • 事件监听:Slider.onValueChanged.AddListener
  • 设置位置:Slider.value

InputField

  • 验证输入字符:onValidateInput,发生在onValueChanged之前,可以进行验证修改。
  • 监听输入字符:onValueChanged,输入框内容发生改变。

Sprite 及图集

打包设置

  1. 在Project窗口内,右键鼠标->Create->Sprite Atlast,创建Atlas
  2. 选中创建的Atlas,在Objects For Packing列表,点+号,添加,并将图标目录拖上来
  3. 在Project Settings->Editor的Sprite Packer的Mode,选择always enabled

加载图集

SpriteAtlas spriteAtlas = Resources.Load<SpriteAtlas>("SpriteAtlas");
transform.Find("icon").GetComponent<Image>().sprite = spriteAtlas.GetSprite("ToolTip_Bg_0");
//sprite 
Sprite[] spriteArray = new Sprite[spriteAtlas.spriteCount];
//spriteArray得到数组
spriteAtlas.GetSprites(spriteArray);

ScrollRect

如果控件没有Image组件,则Mask不起作用

重新打开时,滚动到顶端:scrollRect.content.localPosition = Vector2.zero;

更详细的解析

Vertical/Horizental Layout Group

Control Child Size 自动计算尺寸

官方文档解释是控制子元素尺寸,实际应用中,当子元素尺寸发生变化,需要选中这个,该Group尺寸才会自动更新,否则只能SetActive(false) ->SetActive(true)才正确。

要加入Content Size Fitter组件来计算尺寸

UI粒子

UI与粒子的遮挡关系

可以把不同的UI及粒子,放到不同的Canvas里,并设定Canvas和粒子的参数,来实现UI与UI之间,UI与粒子之间的渲染排序:

canvas.overrideSorting = true;

canvas.sortingOrder = 1;

particle.sortingOrder = 1;

粒子裁剪

如果我们希望粒子旨在我们的RectTransform内显示,超出部分裁掉,可以修改粒子的shader,将RectTransform的4个角传递给shader,对超出的像素,不进行渲染。

粒子缩放

如果屏幕分辨率发生变化,UGUI会自动对UI元素进行缩放,但是粒子需要我们自己处理。

根据设计分辨率宽高比,和当前分辨率宽高比,计算缩放

// 设计宽高比
float designAspectRatio = designWidth / designHeight;
// 屏幕宽高比
float screenAspectRatio = screen.width/screen.height;
// 如果屏幕宽高比,小于设计宽高比(屏幕在变高了)
if(screenAspectRatio < designAspectRatio)
{
	float scale = screenAspectRatio / designAspectRatio;
    particle.transform.localScale = scale * particle.firstLocalScale;
}
else
{
	particle.transform.localScale = particle.firstLocalScale;
}

UI挂粒子

粒子的资源引用关系比较复杂,所有不要直接将特效挂在UI对象上,而是保存预制名字,运行时加载。

小地图优化

小地图一般时美术把整张地图画在一张大图上,之渲染一部分。但是如果用裁切,虽然被裁切的地方没有渲染出来,但它还是执行渲染了,这其实拉高了填充率。其实我们可以创建一个小的Image,移动时修改UV 坐标,能达到相同的效果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值