基础元素

UI提供了Rect Transform组件,用来设置锚点以及对齐方式,每一个基础元素都要设置Rect规则

Text

文本需要使用TTF字体,汉子字库一般非常庞大,有大多数无用的字符,可以使用Font Creator等软件来精简一下字库。

有些文本文字数字和中文需要两种不同的字体,可以将两种字体合并,这样使用一个Text组件就可以同时显示中文加数字了。

UGUI的Text有很多缺点,推荐使用TextMeshPro组件可以省去很多麻烦

在“第三章——拓展Hierarchy视图——重写菜单”中,有取消新建的UI的Raycast Target方法

UGUI的事件系统会遍历所有Raycast Target组件。不需要交互的元素需要关闭Raycast Target以节省性能

UGUI默认的材质是无法修改的,但是可以重写,只需要将新的材质拖入Material处即可

描边和阴影

在Text游戏对象上添加Outline和Shadow,即表示支持文本的描边和阴影。

描边是在原有文字组件的基础上上下左右各画了一遍。效率是很低的

阴影比描边好很多,只画一遍。

动态字体

动态字体是根据传入的字体以及字体的大小生成到一张纹理上。最终将纹理上的字体显示出来。这是Unity动态字体的原理。

除了聊天和起名等必须用户自己主动输入的文字外,游戏中大量的的文字实际上并不需要使用动态字体。此时可以使用SDF字体,它的原理是用位图来保存矢量信息,记录到边的最短距离,最后再用shader还原回来,TextMeshPro就是用了这个原理。

关于动态字体的详细信息,可以参阅官方文档

字体 - Unity 手册 (unity3d.com)

字体花屏

UGUI的动态字体会动态生成材质,这种做法也是为了提高游戏的性能,材质贴图从256X256,随着字体的增多变成4096X4096,字体再增多就会触发重建贴图命令。这个时候有可能会触发字体花屏,要解决这个问题,需要监听内部重建的事件,重建时刷新当前场景中的所有字体。

监听Font.textureRebuilt事件,调用FontTextureChanged方法

新建RefreshTextFont脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
using UnityEngine;
using UnityEngine.UI;

public class RefreshTextFont : MonoBehaviour
{
private Font m_NeedRebuildFont;//标记某个字体发生了重建
void Start()
{
//监听字体贴图重建事件
Font.textureRebuilt += (Font font) =>
{
m_NeedRebuildFont = font;
};
}

void Update()
{
if (m_NeedRebuildFont)
{
//找到场景中的所有text,重新刷新一下
Text[] texts = GameObject.FindObjectsOfType<Text>();
if(texts != null)
{
foreach (Text text in texts)
{
if (text.font == m_NeedRebuildFont)
{
text.FontTextureChanged();
}
}
}
m_NeedRebuildFont = null;
}
}
}

Image组件

Image组件需要格式标记为“Sprite(2D and UI)”的图片

图片有如下四种格式

  • Simple:直接显示图片。
  • Sliced: 九宫格切割法图片,图片本身使用SpriteEditor编辑(需要先安装2Dpackage)
  • Tiled:平铺图片
  • Filed:可以裁切图片,多用于技能CD

Perserve Aspect表示是否强制等比例显示图片。单击Set Native Size按钮,可以重新设置图片大小和比例

Raw Image组件

Image组件只能显示Sprite,Raw Image组件既可以显示任意Texture,也可以使用Sprite,不过它还是以Texture方式显示的。

Image组件使用Sprite时,可以使用Atlas来合并批次,但是RawImage就不能,每个Raw Image就占一次DrawCall。

当使用Render Texture时,必须使用Raw Image组件。render texture即摄像机渲染纹理,可以用来制作小地图或者假镜子等。

因为性能问题,正式的UI系统不建议使用。

Button组件

Button组件依赖Image组件,按钮有Normal、Pressed、Selected、Highlighted、Disable几种状态,有Color Tint、Sprite、Animation三种transition。

首先是通过脚本引用按钮来实现点击的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using UnityEngine;
using UnityEngine.UI;

public class ButtonReferenceByScript : MonoBehaviour
{
public Button button;
void Start()
{
button.onClick.AddListener(()=>
{
Debug.Log("Button");
});
}
}

脚本点击

当然,也可以在按钮组件中的OnClock里面添加点击事件。前提是该方法需要为public属性。

开发中,在代码最后那个对按钮进行监听更灵活。不建议在面板中添加点击方法。

Toggle组件

Unity单个GameObject只能挂载单个Selectable组件,也就是说不能在一个GameObject上面添加两个toggle。我们可以复制几个toggle,作为一个toggle group父对象的子级。然后都关联到一个group中。

toggles

toggle group

然后演示脚本引用toggle的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using UnityEngine;
using UnityEngine.UI;

public class ToggleReferenceByScript : MonoBehaviour
{
public Toggle[] toggles;
void Start()
{
foreach (var toggle in toggles)
{
toggle.onValueChanged.AddListener((bool enable) =>
{
Debug.LogFormat("toggle={0} selected={1}", toggle.name, enable);
});
}
}
}

监听toggle

Slider组件

制作血条、状态条的组件

演示脚本引用Slider的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using UnityEngine;
using UnityEngine.UI;

public class SliderReferenceByScript : MonoBehaviour
{
public Slider slider;
void Start()
{
slider.minValue = 0;
slider.maxValue = 100;
slider.onValueChanged.AddListener((float value) =>
{
Debug.LogFormat("value = {0}", value);

});
}
}

滑动Slider

如果运行时需要更改,使用slider.value来设置新的值。另外,Slider和Toggle都是使用onValueChanged来监听事件的,但是传递的UnityEvent是不同的,一个是bool、一个是float

Scrollbar和ScrollView组件

Scroll Rect | Unity UI | 1.0.0 (unity3d.com)

ScrollView组件重点是其中的Scroll Rect,它能够设置一个滑动区域,然后挂上Scrollbar组件监听滑动的事件

image-20220125123658274

属性 功能
Content 这是对要滚动的 UI 元素的 Rect Transform 的引用,例如大图片大段文字。
Horizontal 是否水平滑动
Vertical 是否垂直滑动
Movement Type 使用 Elastic 或 Clamped 强制内容保持在 Scroll Rect 的范围内。Elastic在内容到达 Scroll Rect 的边缘时反弹内容。使用Unrestricted随便滑动
Elasticity 这是Elastic中使用的反弹量。
Inertia 设置Inertia后,拖动后释放指针时内容将继续移动。当没有设置惯性时,内容只会在拖动时移动。
Deceleration Rate 当设置Inertia时,Deceleration Rate决定了内容物停止移动的速度。速率为 0 将立即停止运动。值为 1 表示运动永远不会减速。
Scroll Sensitivity 对滚轮和触控板滚动事件的敏感度。
Viewport 对作为content Rect Transform的父级的viewport Rect Transform的引用。
Horizontal Scrollbar 对水平滚动条元素的可选引用。
Visibility 滚动条是否在不需要时自动隐藏,也可以选择expand viewport。
Spacing 滚动条和视口之间的空间。

使用ScrollRect组件制作游戏摇杆

  1. 首先新建一个scrollView,删除它所有的子对象,删除ScrollView内的ScrollRect组件,将ScrollView命名为GameStick
  2. 新建GameStickScript脚本,并挂载在gamestick上面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class GameStickScript : ScrollRect
{
protected float mRadius = 0f;
protected override void Start()
{
base.Start();
//计算摇杆半径
mRadius = (transform as RectTransform).sizeDelta.x * 0.5f;
//如果anchor是四个聚在一起的,sizeDelta指的就是当前GameObject的size(vector2),如果anchor是分开的,sizedelta是相对于父级的Rect区域的大小比例
}
public override void OnDrag(UnityEngine.EventSystems.PointerEventData eventData)
{
base.OnDrag(eventData);
var contentPosition = this.content.anchoredPosition;
//anchoredPosition指的是pivot相对于Anchors的位置(vector2),如果anchors不在一起,Unity 会使用pivot位置作为参考来估计四个anchor位置
if (contentPosition.magnitude > mRadius)
{
contentPosition = contentPosition.normalized * mRadius;
SetContentAnchoredPosition(contentPosition);
}
}
}
  1. 将导入的图片设置为sprite,将摇杆的背景图放在GameStick的Image组件内
  2. 将摇杆的图片作为GameStick的子级,并命名为point,在GameStick的GameStickScript脚本中,将point放在content里面。

游戏摇杆