【Unity基础详解】(9)Unity核心:UI系统

目录

[1 GUI](#1 GUI)

[1.1 GUI简介](#1.1 GUI简介)

[1.2 核心特点](#1.2 核心特点)

[1.3 主要用途](#1.3 主要用途)

[1.4 文本和按钮控件](#1.4 文本和按钮控件)

[1.5 GUI Layout](#1.5 GUI Layout)

[1.6 在编辑器窗口中使用GUI](#1.6 在编辑器窗口中使用GUI)

[2 UGUI](#2 UGUI)

[2.1 UGUI简介](#2.1 UGUI简介)

[2.2 UGUI组成](#2.2 UGUI组成)

[2.2.1 Canvas](#2.2.1 Canvas)

[2.2.1.1 Canvas 组件](#2.2.1.1 Canvas 组件)

[2.1.2.2 Canvas Scaler 组件](#2.1.2.2 Canvas Scaler 组件)

[2.1.2.3 Graphic Raycaster 组件](#2.1.2.3 Graphic Raycaster 组件)

[2.2.2 EventSystem](#2.2.2 EventSystem)

[2.2.2.1 EventSystem 组件](#2.2.2.1 EventSystem 组件)

[2.2.2.2 Standalone Input Module 组件](#2.2.2.2 Standalone Input Module 组件)

[2.2.3 Rect Transform](#2.2.3 Rect Transform)

[2.2.3.1 位置与尺寸属性](#2.2.3.1 位置与尺寸属性)

[2.2.3.2 Anchors 锚点](#2.2.3.2 Anchors 锚点)

[2.2.3.3 Pivot 轴心点](#2.2.3.3 Pivot 轴心点)

[2.3 基础控件](#2.3 基础控件)

[2.3.1 Text 控件](#2.3.1 Text 控件)

[2.3.1.1 属性介绍](#2.3.1.1 属性介绍)

[2.3.1.2 案例:打字机效果](#2.3.1.2 案例:打字机效果)

[2.3.1.3 TextMeshPro](#2.3.1.3 TextMeshPro)

[2.3.2 Image 控件](#2.3.2 Image 控件)

[2.3.3 Raw Image 控件](#2.3.3 Raw Image 控件)

[2.3.3.1 属性介绍](#2.3.3.1 属性介绍)

[2.3.3.2 案例:小地图制作](#2.3.3.2 案例:小地图制作)

[2.4 组合控件](#2.4 组合控件)

[2.4.1 Button 控件](#2.4.1 Button 控件)

[2.4.1.1 属性介绍](#2.4.1.1 属性介绍)

[2.4.1.2 交互性](#2.4.1.2 交互性)

[2.4.1.3 使用方式](#2.4.1.3 使用方式)

[2.4.2 Toggle 控件](#2.4.2 Toggle 控件)

[2.4.2.1 属性介绍](#2.4.2.1 属性介绍)

[2.4.2.2 使用方式](#2.4.2.2 使用方式)

[2.4.3 InputField 控件](#2.4.3 InputField 控件)

[2.4.3.1 属性介绍](#2.4.3.1 属性介绍)

[2.4.3.2 使用方式](#2.4.3.2 使用方式)

[2.4.3.3 案例:注册登陆界面实现](#2.4.3.3 案例:注册登陆界面实现)

[2.4.3.4 案例:DeepSeek AI对话](#2.4.3.4 案例:DeepSeek AI对话)

[2.4.4 Slider 控件](#2.4.4 Slider 控件)

[2.4.4.1 属性介绍](#2.4.4.1 属性介绍)

[2.4.4.2 使用方式](#2.4.4.2 使用方式)

[2.4.4.3 案例:音量控制](#2.4.4.3 案例:音量控制)

[2.4.4.4 案例:进度条](#2.4.4.4 案例:进度条)

[2.4.4.3 案例:血条](#2.4.4.3 案例:血条)

[2.4.5 ScrollBar 控件](#2.4.5 ScrollBar 控件)

[2.4.6 ScrollView 控件](#2.4.6 ScrollView 控件)

[2.4.6.1 属性介绍](#2.4.6.1 属性介绍)

[2.4.6.2 案例:背包功能制作](#2.4.6.2 案例:背包功能制作)

[2.4.7 DropDown 控件](#2.4.7 DropDown 控件)

[2.4.7.1 属性介绍](#2.4.7.1 属性介绍)

[2.4.7.2 使用方式](#2.4.7.2 使用方式)

[3 UI Toolkit](#3 UI Toolkit)

[3.1 简介](#3.1 简介)

[3.2 UI Toolkit 与 UGUI 的比较](#3.2 UI Toolkit 与 UGUI 的比较)

[3.3 UI Toolkit 核心概念与工作流](#3.3 UI Toolkit 核心概念与工作流)


1 GUI

1.1 GUI简介

IMGUI(Immediate Mode GUI)是一种基于代码的即时模式 GUI 系统,与 Unity 基于游戏对象的 UI 系统不同。这套系统专为程序员设计,采用代码驱动的工作方式。开发者需在 OnGUI() 方法中实时编写界面绘制和交互逻辑代码,每帧都需要重新声明 UI 元素。由于系统缺少内置的布局和样式管理功能,开发者需要自行维护所有 UI 元素的状态。

1.2 核心特点

无状态:UI 元素没有持久化的对象表示,每一帧都会根据当前状态重新绘制。

代码驱动:所有 UI 都通过代码动态创建,例如使用GUI.Button(new Rect(10, 10, 50, 20), "Click"); 这类调用。

执行顺序:OnGUI() 方法每帧可能被多次调用,用于处理不同的布局和事件。

1.3 主要用途

**编辑器扩展开发:**创建自定义的 Inspector、EditorWindow 和工具窗口是 IMGUI 最常用且最擅长的应用场景。

**游戏调试工具:**可用于快速绘制游戏中的调试信息,构建测试按钮和控制面板。

**原型开发:**特别适合在项目初期快速搭建简单 UI 界面进行功能验证。

注意事项:

  1. OnGUI 每帧执行,是专门用于 GUI 界面绘制的函数;

  2. 建议仅在其中执行 GUI 相关的界面绘制和操作逻辑;

  3. 执行顺序位于 OnDisable 之前,LateUpdate 之后;

  4. 所有继承自 MonoBehaviour 的脚本都可以通过 OnGUI 方法绘制 GUI 界面。

1.4 文本和按钮控件

cs 复制代码
private int clickCount = 0;
private string textField = "Hello IMGUI";
private void OnGUI()
{
    // 1. 创建一个标签 (Label)
    GUI.Label(new Rect(10, 10, 200, 20), "This is a basic lable");
    // 2. 创建一个按钮 (Button)
    // GUI.Button 方法会返回一个布尔值,当该按钮在本帧被点击时为 true
    if (GUI.Button(new Rect(10, 40, 150, 30), "Click Count:" + clickCount))
    {
        // 当按钮被点击时,增加计数
        clickCount++;
        Debug.Log("Button Click! Count:" + clickCount);
    }
    // 3. 创建一个文本框 (TextField)
    // 将用户在文本框输入的内容返回并存储回 textField 变量
    textField = GUI.TextField(new Rect(10, 80, 1500, 30), textField);
}

代码说明:

  • new Rect(x, y, width, height)定义了 UI 控件在屏幕上的位置和大小(以像素为单位)。(0, 0)是屏幕左上角。
  • GUI.Button()返回bool,只有在点击发生的这一帧才会返回true。
  • GUI.TextField()返回string,即用户输入的内容。你必须将返回值赋回给原始变量(如textField)才能更新它,这正是"无状态"的体现。

1.5 GUI Layout

cs 复制代码
private float sliderValue = 50f;
private bool toggleState = false;
private int toolbarIndex = 0;
private string[] toolbarLabels = { "Tab 1", "Tab 2", "Tab 3" };
private void OnGUI()
{
    // 开始一个自动垂直排列的区域
    GUILayout.BeginVertical(GUILayout.Width(200));
    // 1. 工具栏 (Toolbar)
    toolbarIndex = GUILayout.Toolbar(toolbarIndex, toolbarLabels);
    // 2. 根据选中的工具栏标签显示不同的内容
    switch (toolbarIndex)
    {
        case 0:
            GUILayout.Label("You are on Tab 1");
            break;
        case 1:
            GUILayout.Label("Welcome to Tab 2");
            break;
        case 2:
            GUILayout.Label("This is Tab 3");
            break;
   }
    // 3. 滑动条 (Slider)
    // 我们需要一个标签来显示当前值
    GUILayout.Label("Slider Value:" + sliderValue.ToString("F0"));
    sliderValue = GUILayout.HorizontalSlider(sliderValue, 0f, 100f);
    // 4. 开关 (Toggle)
    toggleState = GUILayout.Toggle(toggleState, "This is a Toggle");
    if (toggleState)
    {
        GUILayout.Label("The Toggle is ON");
    }
    // 5. 一个大的按钮
    if(GUILayout.Button("A Large Layout Butoon", GUILayout.Height(50)))
    {
        Debug.Log("Layout Button Pressed! Slider is :" + sliderValue);
    }
    // 结束垂直区域
    GUILayout.EndVertical();
}

代码说明:

  • GUILayout.BeginVertical()/GUILayout.EndVertical()定义了一个区域,其中的控件会自动垂直排列。类似的还有BeginHorizontal/EndHorizontal。
  • GUILayout是 IMGUI 中更常用的方式,因为它能自动处理布局,非常适合制作工具窗口。
  • GUILayout.Toolbar返回一个int,代表当前选中的标签索引。

1.6 在编辑器窗口中使用GUI

IMGUI 的核心优势在此处得以充分体现,这也是其最典型的应用场景。需要注意的是,以下脚本不能直接附加到游戏对象上,而是需要专门编写编辑器脚本。

具体操作步骤如下:

  1. 在项目中新建名为"Editor"的文件夹(名称必须严格保持一致)
  2. 在该文件夹内创建以下 C# 脚本:CustomToolWindow
cs 复制代码
// 注意:继承自 EditorWindow,不是 MonoBehaviour
public class CustomToolWindow : EditorWindow
{
    private string creatorName = "Your Name";
    private GameObject targetObject;
    // 添加菜单项
    [MenuItem("Tool/My Custom Tool")]
    public static void ShowWindow()
    {
        // 获取一个自定义窗口的实例
        GetWindow<CustomToolWindow>("My Tool");
    }
    // 这是编辑器窗口的 IMGUI 绘制代码
    private void OnGUI()
    {
        GUILayout.Label("Object Creator Tool", EditorStyles.boldLabel);
        // 使用 EditorGUILayout 获取更符合编辑器风格的控件
        creatorName = EditorGUILayout.TextField("Creator Name", creatorName);
        targetObject = (GameObject)EditorGUILayout.ObjectField("Target Object", targetObject, typeof(GameObject), true);
        EditorGUILayout.Space();// 添加一些空行
        if (GUILayout.Button("Creat Cube"))
        {
            CreatePrimitive(PrimitiveType.Cube);
        }
        if (GUILayout.Button("Creat Sphere") && targetObject != null)// 设置控件是否可交互
        {
            CreatePrimitive(PrimitiveType.Sphere);
        }
        GUI.enabled = true;// 恢复可用状态
    }
    void CreatePrimitive(PrimitiveType type)
    {
        GameObject go = GameObject.CreatePrimitive(type);
        go.name = creatorName + "s+" + type.ToString();
        // 将此操作注册到撤销系统中
        Undo.RegisterCreatedObjectUndo(go, "Create" + type.ToString());
        // 在编辑器中选中新创建的对象
        Selection.activeObject = go;
    }
}

代码说明:

  • MenuItem("Tools/My Custom Tool")\]:在 Unity 编辑器顶部菜单栏的Tools下创建一个名为My Custom Tool的菜单项。

  • EditorGUILayout:提供了与 Unity 编辑器风格一致的控件,如ObjectField用于拖拽选择场景中的对象,TextField带有一个标签等。
  • Undo.RegisterCreatedObjectUndo:将创建对象的操作注册到撤销历史中,用户可以按Ctrl+Z撤销。
  • Selection.activeObject:在 Hierarchy 或 Project 窗口中选择指定的对象。
  • 运行后,点击Tools > My Custom Tool即可打开自定义的工具窗口。

2 UGUI

2.1 UGUI简介

UGUI(Unity Graphical User Interface)是 Unity 内置的官方 UI 系统,自 Unity 4.6 版本推出后逐步替代了第三方的 NGUI,成为 Unity 项目中最主流的 UI 解决方案。它深度集成于 Unity 编辑器,支持 2D/3D 场景适配,具备灵活的布局、交互和渲染能力,适用于游戏菜单、HUD、对话框、移动应用界面等各类 UI 开发场景。

2.2 UGUI组成

UGUI 的核心是「Canvas(画布)+ UI 控件 + EventSystem(事件系统) 」的三层结构,所有 UI 逻辑都围绕这三者展开。

2.2.1 Canvas

Canvas(画布)是UI 的容器,所有 UI 元素必须作为 Canvas 的子物体才能显示,Canvas 是 UI 渲染的 "载体",负责管理 UI 的渲染顺序、相机适配等。当你通过菜单GameObject > Create UI首次创建 UI 元素时,如果场景中还没有画布,Unity 会自动创建一个。

2.2.1.1 Canvas 组件

Canvas 定义了 UI 元素被绘制的虚拟空间,其行为主要由 渲染模式(Render Mode) 控制。可以根据游戏的需要,在三种不同的渲染模式中选择,它们决定了 UI 与游戏场景的交互方式。

Canvas 的三种渲染模式(Render Mode):

渲染模式 工作原理 适用场景 注意事项
Screen Space - Overlay (屏幕空间-覆盖) UI直接绘制在屏幕上,无需摄像机,始终位于其他图形之上。 传统的、始终位于顶层的2D UI,如手游的虚拟按键、设置菜单。 此模式的画布必须位于层级视图(Hierarchy)的顶级,否则UI可能消失。
Screen Space - Camera (屏幕空间-摄像机) UI被绘制在指定摄像机前方一定距离的平面上,受摄像机参数(如视野)影响。 需要与场景有简单透视关系的UI,如VR游戏中的界面、游戏中的头盔显示器效果。 UI的屏幕大小不随距离变化,但会被摄像机与UI平面之间的3D对象遮挡。
World Space (世界空间) UI作为场景中的一个普通3D对象渲染,可以任意旋转和放置。 需要与游戏世界交互的"叙事界面",如游戏中的显示屏、漂浮在角色头上的血条、世界中的告示牌。 画布在屏幕上的大小取决于摄像机的视角和距离,需要手动调整Rect Transform来确定大小。

**Pixel Perfect:**仅Screen Space模式,启用后平滑边缘,减少锯齿,使UI显示更清晰。

注意:

  • 在同一个 Canvas 下,UI 元素的绘制顺序(即谁覆盖谁)遵循一个简单规则:按照它们在 Hierarchy 视图中的排列顺序,从上到下依次绘制。排在下面的元素会覆盖在上面的元素之上。
  • 你可以通过直接拖拽调整元素在 Hierarchy 中的顺序,或者使用脚本中的 SetAsFirstSibling()、SetAsLastSibling() 和 SetSiblingIndex()方法来动态控制顺序。
2.1.2.2 Canvas Scaler 组件

Canvas Scaler组件确保你的UI在不同分辨率和屏幕尺寸下都能有合适的显示效果。它的核心是UI Scale Mode 属性:

  • Constant Pixel Size(恒定像素大小):UI元素保持固定的像素尺寸。你可以通过Scale Factor 整体缩放画布内的所有元素。

  • Scale With Screen Size(随屏幕尺寸缩放) :这是最常用的模式,可根据预设的参考分辨率(Reference Resolution)进行缩放。当屏幕分辨率大于参考分辨率时UI会放大,小于则会缩小。通过Screen Match Mode(如Expend、Shrink、Match Width or Height)可以调整宽高比不适配时的缩放策略。

  • Constant Physical Size(恒定物理尺寸):使UI元素在不同设备上保持相同的物理大小(如英寸、毫米)。此模式需要设备能正确报告其DPI。

2.1.2.3 Graphic Raycaster 组件

Graphic Raycaster是挂在Canvas上负责处理UI交互(如点击、悬停)的组件。

Ignore Reversed Graphics :通常建议启用。启用后,只有当图形正面朝向你时才能被射线击中,背对你的UI元素不会被误触发。

Blocking Objects & Blocking Mask :这两个属性用于设置哪些类型的非UI对象 (如3D模型或2D碰撞体)可以阻挡UI射线。例如,你可以设置让一个3D角色模型走到UI前面时,遮挡住后面的UI按钮,使其无法被点击。

2.2.2 EventSystem

EventSystem是UI 交互的核心,用于处理 UI 的输入事件(鼠标点击、触摸、键盘输入等),是按钮、输入框等交互 UI 生效的前提。

新建 UI 元素时,Unity 会自动创建EventSystem物体(包含 EventSystem 和Standalone Input Module / Touch Input Module组件),无需手动创建。

下面这个流程图概括了其核心工作机制:

EventSystem 是整个事件系统的**大脑和协调中心,**它的主要职责包括:

管理输入模块:EventSystem 会在每帧更新时,查看所有可用的输入模块,并决定使用哪一个来处理当前活动,一个场景中通常只需要一个 EventSystem 对象

管理选中对象 :它负责跟踪当前被选中的GameObject,这对于UI导航(例如通过键盘或手柄切换焦点)至关重要。

协调射线投射:它协助输入模块,利用配置在场景中的射线投射器来确定指针指向的位置。

2.2.2.1 EventSystem 组件

属性如下:

  • First Selected:指定游戏启动时默认选中的GameObject,这对于手柄或键盘操作确定初始焦点非常有用。

  • Send Navigation Events:控制事件系统是否允许发送导航事件(移动、提交、取消)。

  • Drag Threshold:拖拽操作的容限区域(以像素为单位),用于判断一个指针移动是否构成拖拽。

2.2.2.2 Standalone Input Module 组件

Standalone Input Module 是专门为处理鼠标、键盘和控制器 输入而设计的模块。它的工作严重依赖于Unity的 Input Manager

  • Horizontal/Vertical Axis:指定输入管理器中用于水平/垂直导航轴的名称。

  • Submit/Cancel Button:指定输入管理器中用于提交和取消操作的按钮名称。

  • Input Actions Per Second:每秒允许的键盘/控制器输入事件的最大数量,用于限制事件触发频率。

  • Repeat Delay:在每秒输入操作重复率生效前,系统等待的延迟时间(以秒为单位)。

  • Force Module Active:即使模块本身认为自己不应被激活,也强制让其处于活动状态。

事件处理流程:

1.新的按压发生时,模块会按顺序发送:

  • PointerEnter事件(给所有可处理该事件的层级中的对象)

  • PointerPress事件

  • 缓存拖动处理程序(层级中第一个能处理拖动的元素)

  • 向缓存的拖动处理程序发送BeginDrag事件

  • 在事件系统中将 "Pressed" 对象设置为Seleted(选中状态)

2.持续按压时,模块会处理移动,并向缓存的拖动处理程序发送Drag事件。如果触摸在对象之间移动,还会处理 PointerEnter和 PointerExit事件。

3.释放操作时,模块会:

  • 向收到 PointerPress的对象发送 PointerUp事件。

  • 如果当前悬停的对象与之前按下的对象相同,则发送 PointerClick事件。

  • 如果有缓存的拖动处理程序,则发送Drop事件,最后发送 EndDrag事件。

2.2.3 Rect Transform

Rect Transform 是 Unity UGUI 系统中所有 UI 元素的基础变换组件,它继承自常规的 Transform,但专门为 2D 用户界面进行了优化和扩展。

Rect Transform 与常规 Transform 的区别

特性 Transform Rect Transform
坐标系 3D 世界坐标系 2D 矩形坐标系
定位方式 位置、旋转、缩放 锚点、轴心点、尺寸
适用对象 3D 物体、2D 精灵 专为 UI 元素设计
父子关系 基于世界/本地坐标 基于矩形相对定位
2.2.3.1 位置与尺寸属性

根据锚点设置的不同,Inspector 中显示的属性会发生变化:

当锚点为点(非拉伸)时:

  • Pos X, Pos Y, Pos Z:相对于轴心点的位置

  • Width, Height:元素的固定宽度和高度

当锚点为线或面(拉伸)时:

  • Left, Right, Top, Bottom:元素各边与父容器对应边的距离

  • Pos Z:Z 轴位置(用于层级排序)

2.2.3.2 Anchors 锚点

锚点是 Rect Transform 最重要的概念,它定义了 UI 元素与其父元素的相对定位关系。

锚点预设模式:

  • 左上/右上/左下/右下角:元素固定在父容器的某个角落

  • 顶部/底部/左/右拉伸:元素紧贴父容器的某一边

  • 中心/水平中心/垂直中心:元素相对于父容器中心定位

  • 全面拉伸:元素填充整个父容器

自定义锚点:

  • Min:左下角锚点 (X, Y)

  • Max:右上角锚点 (X, Y)

  • 数值范围:0 到 1(相对父容器的标准化坐标)

2.2.3.3 Pivot 轴心点

轴心点决定了元素的旋转中心、缩放中心和定位基准点

  • Pivot X, Y:取值范围 0-1

  • 例如:(0, 0) = 左下角,(0.5, 0.5) = 中心,(1, 1) = 右上角

  • 轴心点会影响元素的位置计算和变换效果


2.3 基础控件

2.3.1 Text 控件

2.3.1.1 属性介绍

Text: 实际显示的文本字符串。支持多行文本,使用换行符(\n)进行换行。

Font: 文本所使用的字体。可以是Unity内置字体,也可以是自定义字体。

Font Style: 字体样式

  • Normal(正常)
  • Bold(粗体)
  • Italic(斜体)
  • BoldAndItalic(粗斜体)

Font Size: 字体大小。注意,如果"Auto Size"启用,则字体大小将自动调整,此属性将变为只读。

Line Spacing: 行间距,表示多行文本的行与行之间的间距。

Rich Text: 是否支持富文本。启用后,可以使用HTML风格的标签来设置文本中部分内容的样式(如颜色、大小、粗体等)。

Alignment: 文本的对齐方式

  • 水平对齐:左、中、右
  • 垂直对齐:上、中、下

Align By Geometry: 使用几何体对齐,当启用时,文本将根据字体的几何信息进行对齐,而不是字体矩阵。通常用于使字体看起来更紧凑。

Horizontal Overflow: 水平溢出模式。有两种模式:

  • Wrap:当文本宽度超过RectTransform的宽度时自动换行。
  • Overflow:文本超出RectTransform宽度时继续显示,不会被裁剪。

Vertical Overflow: 垂直溢出模式。有两种模式:

  • Truncate:当文本高度超过RectTransform的高度时,超出部分被裁剪。
  • Overflow:文本超出RectTransform高度时继续显示,不会被裁剪。

Best Fit: 自动调整字体大小以适应RectTransform的尺寸。启用后,可以设置最小和最大字体大小。

Color: 文本的颜色。

Material: 文本的材质,默认使用字体材质。

Raycast Target: 是否作为射线投射目标(即是否响应鼠标事件)。如果不需要文本被点击,可以禁用此属性以提高性能。

2.3.1.2 案例:打字机效果

将本脚本赋给Text游戏对象即可,可以通过调整charsPerSecond控制打印频率。

cs 复制代码
using UnityEngine.UI;

public class DaZiJi : MonoBehaviour
{
    private Text textComponent;
    private float charsPerSecond = 10f;//打印频率

    void Start()
    {
        textComponent = GetComponent<Text>();

        string printText = "沁园春·雪\n北国风光,千里冰封,万里雪飘。\n" +
            "望长城内外,惟余莽莽;大河上下,顿失滔滔。山舞银蛇,原驰蜡象,欲与天公试比高。\n" +
            "须晴日,看红装素裹,分外妖娆。江山如此多娇,引无数英雄竞折腰。\n" +
            "惜秦皇汉武,略输文采;唐宗宋祖,稍逊风骚。一代天骄,成吉思汗,只识弯弓射大雕。\n" +
            "俱往矣,数风流人物,还看今朝。";

        StartCoroutine(TypeText(printText));
    }

    public IEnumerator TypeText(string fullText)
    {
        textComponent.text = "";

        for (int i = 0; i < fullText.Length; i++)
        {
            textComponent.text += fullText[i];
            yield return new WaitForSeconds(1f / charsPerSecond);
        }
    }
}
2.3.1.3 TextMeshPro

虽然 UGUI Text 组件功能完善,但对于高质量文本渲染,建议考虑使用 TextMeshPro

特性 UGUI Text TextMeshPro
文本质量 一般 极佳(Signed Distance Field)
性能 中等 优化更好
功能丰富度 基础 非常丰富
学习曲线 简单 稍复杂

TextMeshPro 基本用法:

cs 复制代码
public class TMPExample : MonoBehaviour
{
    public TextMeshProUGUI tmpText;
    
    void Start()
    {
        tmpText.text = "这是 TextMeshPro 文本";
        tmpText.fontSize = 24;
        tmpText.color = Color.red;
    }
}

2.3.2 Image 控件

Image组件是UGUI系统中用于显示图像的基本组件,它可以显示精灵(Sprite)、简单的颜色块或者通过材质(Material)实现特效。

属性 功能说明 默认值
Source Image 源图像精灵(Sprite) None
Color 图像颜色(与源图像相乘) 白色
Material 渲染材质 None
Raycast Target 是否接收射线检测 开启
Image Type 图像显示类型 Simple
Preserve Aspect 保持宽高比 关闭
Set Native Size 设置为原始尺寸按钮 -
Fill Method 填充方法(仅填充类型) Radial 360
Fill Origin 填充起点 Top
Fill Amount 填充量 1

1. Source Image(源图像)

  • 描述:指定要显示的精灵(Sprite)。如果没有指定,Image将显示为纯色块。

  • 注意:只能指定为Sprite类型的资源。

2. Color(颜色)

  • 描述:用于与源图像颜色相乘的颜色值。默认值为白色(RGB(255,255,255)),表示不改变原图颜色。如果设置为其他颜色,则会与图像颜色进行混合。

3. Material(材质)

  • 描述:用于渲染图像的材质。默认使用UI默认材质。可以指定自定义材质来实现特殊效果(如描边、阴影、发光等)。

4. Raycast Target(射线检测目标)

  • 描述:如果启用,该图像可以作为射线检测的目标,即可以响应鼠标/触摸事件。如果不需要响应事件,可以禁用以提高性能。

5. Image Type(图像类型)

  • 描述:定义图像的显示方式。有以下几种类型:

    • Simple(简单):拉伸整个图像以填充整个矩形区域。

    • Sliced(切片):使用9宫格切片(9-slicing)来拉伸图像,保持角落不变形,适用于按钮背景等。

    • Tiled(平铺):平铺图像,类似于Simple,但如果图像尺寸小于矩形区域,则会平铺。注意:如果图像有边框(Border),则平铺中间部分。

    • Filled(填充):以某种填充方式显示图像的一部分,常用于技能冷却、血条等。

6. Preserve Aspect(保持宽高比)

  • 描述:仅在Image Type为Simple时可用。如果启用,将保持图像的原始宽高比,防止图像变形。

7. Set Native Size(设置为原始大小)

  • 描述:点击此按钮将Image的RectTransform尺寸设置为源图像的原始尺寸。

2.3.3 Raw Image 控件

2.3.3.1 属性介绍

Raw Image 组件是 Unity UGUI 系统中用于直接显示纹理(Texture) 的组件,与 Image 组件使用 Sprite 不同,Raw Image 直接操作纹理资源,提供了更灵活的纹理显示能力。

Raw Image 与 Image 的核心区别

特性 Image 组件 Raw Image 组件
资源类型 使用 Sprite 直接使用 Texture
9-slice 缩放 支持(Sliced 模式) 不支持
图集支持 完整支持 不支持
性能开销 相对较高 相对较低
使用场景 UI 图标、按钮、精灵 视频、动态纹理、渲染纹理

Raw Image 属性

属性 功能说明 默认值
Texture 源纹理资源 None
Color 颜色叠加(与纹理相乘) 白色
Material 渲染材质 None
Raycast Target 是否接收射线检测 开启
UV Rect 纹理 UV 坐标调整 (0,0,1,1)
2.3.3.2 案例:小地图制作

核心思路是让一个专门的摄像机拍摄游戏场景,将实时画面显示在UI的Raw Image上。

  1. 创建小地图摄像机

    在场景中创建一个新的摄像机,重命名为"MiniMapCamera"。调整它的位置和旋转角度(通常放在场景上空,旋转X轴90度俯视 ),在摄像机组件中,将Projection设置为Orthographic(正交投影,无透视变形),并根据需要调整Size参数。

  2. 创建 Render Texture

    在Project视图右键 -> Create -> Render Texture ,命名为"MiniMapRenderTexture"。选中刚创建的Render Texture,在Inspector中可以根据需要调整尺寸、抗锯齿等参数。然后将此Render Texture拖拽到MiniMapCamera摄像机的Target Texture字段中。

  3. 创建小地图UI

    在Hierarchy视图右键 -> UI -> Raw Image ,这将自动创建Canvas并将Raw Image加入其中。选中Raw Image,在Inspector里将其Texture设置为前面创建的"MiniMapRenderTexture"。通过Rect Tool调整Raw Image在屏幕上的位置和大小(通常放在右上角)。

  4. 创建脚本MiniMapCameraFollow,赋给MiniMapCamera,将Player游戏对象拖在playerTarget位置。

MiniMapCameraFollow脚本:

cs 复制代码
public class MiniMapCameraFollow : MonoBehaviour
{
    public Transform playerTarget; // 拖拽玩家对象到此
    private Vector3 offset;

    void Start()
    {
        // 计算初始偏移,通常是小地图摄像机与玩家的高度差
        offset = transform.position - playerTarget.position;
        // 确保小地图摄像机只在X和Z轴上跟随,保持Y轴(高度)不变
        offset.y = transform.position.y; 
    }

    void LateUpdate()
    {
        // 更新摄像机位置,只同步玩家的x和z坐标
        transform.position = new Vector3(playerTarget.position.x, transform.position.y, playerTarget.position.z);
        // 或者使用初始偏移:transform.position = playerTarget.position + offset;
    }
}

注意:

  • 性能:Render Texture的分辨率、抗锯齿等级等会影响性能,移动端需注意
  • Audio Listener冲突 :确保小地图摄像机上没有Audio Listener组件,通常主摄像机上有且只有一个即可。

2.4 组合控件

2.4.1 Button 控件

2.4.1.1 属性介绍

Button(按钮)是Unity UGUI系统中最常用的交互控件之一,它允许用户通过点击、触摸或键盘/手柄事件来触发操作。Button 组件继承自Selectable类,因此它拥有所有可选中 UI 元素的通用属性,并添加了特定的点击事件功能。

1.基本属性

  • Interactable(交互性): 布尔值,决定按钮是否可交互。如果取消勾选,按钮将进入禁用状态,不会响应输入。

  • Transition(过渡): 定义按钮在不同状态(普通、高亮、按下、禁用)下的外观变化方式。有四种模式:

    • None: 无过渡。

    • Color Tint: 颜色渐变(默认)。通过修改颜色来表现状态变化。

    • Sprite Swap: 精灵切换。为每个状态指定不同的精灵。

    • Animation: 动画过渡。使用动画控制器来定义状态变化。

  • Navigation(导航): 定义如何使用键盘、手柄或方向键在UI元素之间导航。选项包括:

    • None: 无导航。

    • Horizontal: 水平导航。

    • Vertical: 垂直导航。

    • Automatic: 自动导航。

    • Explicit: 明确指定上下左右导航的目标。

2. 颜色过渡(Color Tint)模式下的属性

当Transition设置为Color Tint时,会出现以下属性:

  • Target Graphic: 应用颜色过渡的目标图形(通常是一个Image或Text)。

  • Normal Color: 正常状态的颜色。

  • Highlighted Color: 高亮状态的颜色(当鼠标悬停时)。

  • Pressed Color: 按下状态的颜色(当按钮被按下时)。

  • Disabled Color: 禁用状态的颜色。

  • Color Multiplier: 颜色倍增器,与颜色值相乘,可用于增强颜色效果。

  • Fade Duration: 颜色过渡的持续时间(以秒为单位)。

3. 精灵切换(Sprite Swap)模式下的属性

当Transition设置为Sprite Swap时,会出现以下属性:

  • Target Graphic: 应用精灵切换的目标图形(通常是一个Image)。

  • Highlighted Sprite: 高亮状态的精灵。

  • Pressed Sprite: 按下状态的精灵。

  • Disabled Sprite: 禁用状态的精灵。

4. 动画过渡(Animation)模式下的属性

当Transition设置为Animation时,会出现以下属性:

  • Normal Trigger: 正常状态的动画触发器。

  • Highlighted Trigger: 高亮状态的动画触发器。

  • Pressed Trigger: 按下状态的动画触发器。

  • Disabled Trigger: 禁用状态的动画触发器。

  • Auto Generate Animation: 自动生成动画控制器(如果尚未存在)。

5. 按钮特有属性

  • On Click (): 点击事件列表。当按钮被点击并释放时触发(即完整的点击操作)。你可以通过此事件列表添加回调函数。
2.4.1.2 交互性
cs 复制代码
public Button myButton;

void Start()
{
    // 启用/禁用按钮交互
    myButton.interactable = true;
    
    // 检查按钮是否可交互
    bool canInteract = myButton.IsInteractable();
}
2.4.1.3 使用方式

1.AddListener 添加事件监听

cs 复制代码
public Button myButton;

void Start()
{
    // 通过AddListener添加监听
    myButton.onClick.AddListener(MyButtonClick);
}

void MyButtonClick()
{
    Debug.Log("按钮被点击了!");
}

// 注意:在适当的时候移除监听,以免重复添加或内存泄漏
void OnDestroy()
{
    myButton.onClick.RemoveListener(MyButtonClick);
}

2. 匿名函数 添加事件监听

cs 复制代码
public Button myButton;

void Start()
{
    myButton.onClick.AddListener(() =>
    {
        Debug.Log("按钮被点击,使用Lambda表达式");
        // 这里可以写更多处理逻辑
    });
}

2.4.2 Toggle 控件

2.4.2.1 属性介绍

Toggle(开关/复选框)是 Unity UGUI 系统中用于实现二元选择的交互控件,允许用户在开启/关闭状态之间切换。它在设置菜单、选项选择和功能开关等场景中广泛应用。

Toggle组件继承自Selectable类,拥有与 Button 类似的交互属性,并添加了特定的开关状态功能。

属性 功能说明 默认值
Is On 当前开关状态 false
Toggle Transition 状态切换过渡效果 Fade
Graphic 显示开关状态的图像 None
Group 所属的 Toggle Group None
Interactable 是否可交互 true
On Value Changed 值改变事件回调
  • Is On :表示Toggle当前是否处于开启状态(打勾状态)。默认值为false。

    • Toggle Transition:切换时的过渡效果,有两种选项:
    • None:立即切换,无过渡效果。
    • Fade:使用淡入淡出效果进行切换。
  • Graphic:用于显示Toggle开关状态的图像(例如,打勾的图片)。通常是一个Checkmark图像。

  • Group:Toggle组,可以将多个Toggle放在一个组中,实现单选效果(即同时只能有一个Toggle被选中)。

  • 其他继承自Selectable的属性

    • Interactable:是否可交互。
    • Transition:状态过渡效果(颜色过渡、精灵过渡、动画过渡)。
    • Navigation:导航设置。
2.4.2.2 使用方式
cs 复制代码
public class ToggleController: MonoBehaviour
{

    public Toggle toggle;
    public bool enableLogging = true;

    void Start()
    {
        if (toggle == null)
            toggle = GetComponent<Toggle>();

        if (toggle != null)
            toggle.onValueChanged.AddListener(OnToggleChanged);
    }

    void OnToggleChanged(bool isOn)
    {
        if (enableLogging)
            Debug.Log("Toggle is "+ (isOn ? "ON" : "OFF"));

        if (isOn)
            EnableFeature();
        else
            DisableFeature();
    }

    void EnableFeature()
    {
        // 开启功能的代码       
    }

    void DisableFeature()
    {
        // 关闭功能的代码
    }
    //在销毁时移除事件监听
    void OnDestroy()
    {
        if (toggle != null)
            toggle.onValueChanged.RemoveListener(OnToggleChanged);
    }
}

2.4.3 InputField 控件

2.4.3.1 属性介绍

InputField(输入框)是UGUI中用于处理用户文本输入的重要组件,它允许用户通过键盘或触摸输入文本。InputField 组件提供了丰富的属性来控制文本输入的行为和外观。

  1. Text Component (文本组件)
  • 类型:Text

  • 说明:用于显示输入文本的Text组件。通常这是InputField子对象中的一个Text组件。

  1. Text (文本)
  • 类型:string

  • 说明:输入框中当前显示的文本。可以通过代码获取或设置。

  1. Character Limit (字符限制)
  • 类型:int

  • 说明:允许输入的最大字符数。0表示无限制。

  1. Content Type (内容类型)
  • 类型:ContentType枚举

  • 说明:指定输入内容的类型,用于验证和输入限制。常见选项包括:

    • Standard:任何字符。

    • Autocorrected:自动校正。

    • Integer Number:只允许整数。

    • Decimal Number:允许小数。

    • Alphanumeric:字母和数字。

    • Name:人名,首字母大写。

    • Email Address:电子邮件地址。

    • Password:密码,显示为星号。

    • Pin:PIN码,显示为星号,且通常为数字。

    • Custom:自定义,可以设置行类型、输入类型、键盘类型等。

  1. Line Type (行类型)
  • 类型:LineType枚举

  • 说明:指定文本的换行行为。

    • Single Line:单行,不换行。

    • Multi Line Submit:多行,但按提交键(如Enter)时提交。

    • Multi Line Newline:多行,按提交键时换行。

  1. Placeholder (占位文本)
  • 类型:Graphic

  • 说明:当输入框为空时显示的占位文本(通常为灰色提示文字)。通常是一个Text组件,但也可以是其他Graphic。

  1. Caret Blink Rate (光标闪烁速率)
  • 类型:float

  • 说明:光标闪烁的频率(以秒为单位)。0表示不闪烁。

  1. Caret Width (光标宽度)
  • 类型:int

  • 说明:光标的宽度(像素)。

  1. Custom Caret Color (自定义光标颜色)
  • 类型:bool

  • 说明:是否使用自定义光标颜色

  1. Selection Color (选中颜色)
  • 当选中文本时,文本背景的颜色。
  1. On Value Changed (值改变事件)
  • 当输入框的文本内容发生变化时触发的事件
  1. End Edit (结束编辑事件)
  • 当用户完成编辑(例如按下提交键或点击输入框外部)时触发的事件。
2.4.3.2 使用方式

1.监听值改变事件

cs 复制代码
public class InputFieldController : MonoBehaviour
{
    public InputField myInputField;

    void Start()
    {
        myInputField.onValueChanged.AddListener(OnInputValueChanged);
    }

    void OnInputValueChanged(string newText)
    {
        Debug.Log("输入框内容改变为: " + newText);
    }
}

2.监听结束编辑事件

cs 复制代码
public class InputFieldController : MonoBehaviour
{
    public InputField myInputField;

    void Start()
    {
        myInputField.onEndEdit.AddListener(OnInputEndEdit);
    }

    void OnInputEndEdit(string finalText)
    {
        Debug.Log("用户完成编辑: " + finalText);
    }
}
2.4.3.3 案例:注册登陆界面实现

点击下面链接,查看具体详细应用教程!

Unity注册登陆UI界面功能 PlayerPrefs +UGUI

2.4.3.4 案例:DeepSeek AI对话

点击下面链接,查看具体详细应用教程!

Unity+DeepSeek实现AI对话

2.4.4 Slider 控件

2.4.4.1 属性介绍
  • Interactable:布尔值,决定Slider是否可交互。

  • Transition:定义Slider在不同状态(正常、高亮、按下、禁用)下的视觉过渡效果,选项包括None(无)、Color Tint(颜色 tint)、Sprite Swap(精灵交换)和Animation(动画)。

  • Navigation:定义导航顺序,用于控制器或键盘输入。

  • Fill Rect:用于显示填充区域的RectTransform。

  • Handle Rect:滑块手柄的RectTransform。

  • Direction:滑块的方向,包括从左到右、从右到左、从上到下、从下到上。

  • Min Value:滑块的最小值。

  • Max Value:滑块的最大值。

  • Whole Numbers:布尔值,如果为true,则滑块只能取整数值。

  • Value:滑块的当前值。

  • OnValueChanged:当滑块值改变时调用的UnityEvent,可以绑定自定义函数。

2.4.4.2 使用方式
cs 复制代码
public class SliderController : MonoBehaviour
{

    public Slider mySlider;
    void Start()
    {

        mySlider.onValueChanged.AddListener(OnSliderValueChanged);
    }

    void OnSliderValueChanged(float value)
    {
        Debug.Log("Slider value: " + value);
    }

}
2.4.4.3 案例:音量控制
cs 复制代码
public class VolumeControl : MonoBehaviour
{
    public Slider volumeSlider;
    public Text volumeText;

    void Start()
    {
        // 设置滑块范围
        volumeSlider.minValue = 0f;
        volumeSlider.maxValue = 1f;
        
        // 加载保存的音量设置
        volumeSlider.value = PlayerPrefs.GetFloat("MasterVolume", 0.8f);
        
        // 绑定值改变事件
        volumeSlider.onValueChanged.AddListener(SetVolume);
        
        // 初始化显示
        UpdateVolumeDisplay(volumeSlider.value);
    }

    void SetVolume(float volume)
    {
        // 设置全局音量
        AudioListener.volume = volume;
        
        // 保存设置
        PlayerPrefs.SetFloat("MasterVolume", volume);
        PlayerPrefs.Save();
        
        // 更新显示
        UpdateVolumeDisplay(volume);
    }

    void UpdateVolumeDisplay(float volume)
    {
        if (volumeText != null)
        {
            // 显示为百分比
            volumeText.text = $"音量: {(volume * 100):F0}%";
        }
    }

    void OnDestroy()
    {
        // 清理事件监听
        if (volumeSlider != null)
            volumeSlider.onValueChanged.RemoveListener(SetVolume);
    }
}

使用说明:

  1. 场景设置

    • 在场景中创建一个 Slider(UI -> Slider)

    • 创建一个 Text(UI -> Text)用于显示音量百分比

    • 将这两个组件拖拽到脚本的对应字段中

  2. 功能特点

    • 滑块范围 0-1,对应音量 0%-100%

    • 实时保存音量设置到 PlayerPrefs

    • 启动时自动加载上次的音量设置

    • 显示当前音量百分比

2.4.4.4 案例:进度条

点击下面链接,查看具体详细应用教程!

协程实现异步加载场景

2.4.4.3 案例:血条
cs 复制代码
public class HealthBar : MonoBehaviour
{
    public Slider healthSlider;
    public Text healthText;    

    [Header("血量设置")]
    public float maxHealth = 100f; //最大血量
    public float currentHealth = 100f; //当前血量

    void Start()
    {
        // 初始化血条
        healthSlider.minValue = 0f;
        healthSlider.maxValue = maxHealth;
        healthSlider.value = currentHealth;

        // 更新血量显示
        UpdateHealthDisplay();
    }
    void Update()
    {
        //只用于测试,在实际游戏中可以通过组件的方式调用加血和扣血的方法
        if (Input.GetKeyDown(KeyCode.H))
        {
            //测试  摁下H键,加血10
            Heal(10f);
        }

        if (Input.GetKeyDown(KeyCode.J))
        {
            //测试  摁下H键,减血10
            TakeDamage(10f);
        }
    }
    // 受到伤害
    public void TakeDamage(float damage)
    {
        currentHealth = Mathf.Max(0f, currentHealth - damage);
        healthSlider.value = currentHealth;
        UpdateHealthDisplay();

        if (currentHealth <= 0f)
        {
            OnDeath();
        }
    }

    // 恢复血量
    public void Heal(float healAmount)
    {
        currentHealth = Mathf.Min(maxHealth, currentHealth + healAmount);
        healthSlider.value = currentHealth;
        UpdateHealthDisplay();
    }

    // 更新血量显示
    void UpdateHealthDisplay()
    {
        if (healthText != null)
        {
            healthText.text = $"{currentHealth:F0}/{maxHealth:F0}";
        }
    }

    // 死亡处理
    void OnDeath()
    {
        Debug.Log("角色死亡!");
        // 在这里添加死亡逻辑,比如播放动画、游戏结束等
    }

    // 重置血量
    public void ResetHealth()
    {
        currentHealth = maxHealth;
        healthSlider.value = currentHealth;
        UpdateHealthDisplay();
    }
}

具体步骤:

  • 在 Canvas 下创建 Slider (UI -> Slider)

  • 调整 Slider 外观:

    • 删除 Handle Slide Area(不需要拖动把手)

    • 设置 Fill 为绿色,Background 为红色或灰色

  • 创建 Text (UI -> Text) 显示血量数值

  • 将这两个组件拖拽到脚本的对应字段

  • 测试:可以通过摁下J键加血,摁下K键扣血

2.4.5 ScrollBar 控件

ScrollBar(滚动条)是 Unity UGUI 系统中用于控制内容滚动位置的交互组件。ScrollBar 通常与 ScrollRect 组件配合使用,但也可以独立用于控制自定义的滚动逻辑。

属性 功能说明 默认值
Handle Rect 滑动把手的 RectTransform -
Direction 滚动条方向 Bottom To Top
Value 当前滚动值 (0-1) 0
Size 把手大小 (0-1) 0.2
Number Of Steps 步进数量 0
OnValueChanged 值改变事件 -

2.4.6 ScrollView 控件

2.4.6.1 属性介绍

ScrollView(滚动视图)是一个在应用和游戏开发中常见的UI组件,用于在有限的显示区域内浏览更多内容

  • 内容滚动:当内容(如长文本、图片列表等)超过容器大小时,ScrollView 提供垂直或水平滚动功能。

  • 手势支持:支持拖拽、惯性滚动等手势操作,提升用户体验。

  • 可视化指示:通常与滚动条(ScrollBar)结合,显示当前滚动位置。

ScrollView 的行为和外观可以通过一系列属性进行配置。以下是跨平台常见的属性(以 Unity 的 UGUI ScrollView 为例):

属性 功能说明 常见取值/类型
Content 滚动的内容容器,通常是一个包含所有子元素的父节点。 RectTransform (Unity)
Horizontal 是否允许水平滚动。 bool (默认: false)
Vertical 是否允许垂直滚动。 bool (默认: true)
Movement Type 滚动运动类型,如弹性滚动(Elastic)或受限(Clamped)。 枚举类型
Elasticity 弹性效果强度,当内容滚动到边界后继续拖拽时的回弹效果。 float (默认: 0.1)
Inertia 是否开启惯性滚动,手指离开后内容继续滚动。 bool (默认: true)
Deceleration Rate 惯性滚动时的减速度,值越大停止越快。 float (0~1, 默认: 0.135)
Scroll Sensitivity 滚动灵敏度,对手势滚动的响应速度。 float
Viewport 定义可视区域的遮罩,通常与 Mask 组件配合使用。 RectTransform
OnValueChanged 滚动值变化时的事件回调,可用于监听滚动位置。 UnityEvent
2.4.6.2 案例:背包功能制作

制作步骤:

第1步:创建背包UI基础结构

  1. Hierarchy 面板右键 → UIScroll View,命名为 InventorySystem

  2. 调整 ScrollView 组件设置:

    • 取消勾选 Horizontal(我们只需要垂直滚动)

    • 确保 Vertical 保持勾选

    • Movement Type 设置为 Elastic(弹性效果更自然)

  3. 设置 Viewport 的锚点为 stretch(全屏拉伸),确定可见区域

第2步:配置背包内容容器

  1. 选中 Content 对象,添加以下组件:

    • Grid Layout Group(网格布局):自动排列物品格子

    • Content Size Fitter(内容尺寸适配):Vertical Fit 设置为 Preferred Size

  2. 配置 Grid Layout Group

    • Cell Size: 80, 80 每个格子的尺寸

    • Spacing: 10, 10 格子间距

    • Start Corner: Upper Left 从左上角开始排列

    • Start Axis: Horizontal 水平方向优先排列

    • Constraint: Flexible 灵活布局

第3步:创建物品格子预制体

1.右键 ContentUIImage,命名为 InventorySlot

2.设置格子外观,给InventorySlot添加组件:

  • 添加 Image 组件,选择边框样式精灵图
  • 添加 Button 组件(用于交互)

3.给 InventorySlot 创建子对象:

  • ItemIcon (Image):显示物品图标
  • ItemCount (Text):显示物品数量

4.将脚本InventorySlot.cs 赋给InventorySlot ,并将子物体ItemIconItemCount拖入对应位置

5.将 InventorySlot 拖入 Project 窗口创建为预制体备用

第4步:设置背包管理器

  1. 创建空物体 InventoryManager
  2. 添加 InventoryManager.cs脚本
  3. Content Parent: 拖入 ScrollView 的 Content

第5步:设置游戏管理器

  1. 创建空物体 GameController
  2. 添加 GameController.cs脚本
  3. Inventory : 拖入InventoryManager
  4. 四个Icon需要自行搜图导入Unity的Project视图,并修改Texture Type 为**Sprite(2D and UI)**格式,才能使用

第6步:配置物品容器

InventorySlot 预制体作为子物体拖放在Content下,不然会检测背包没有可存放物品的容器,无法添加物品。

代码如下:

1. ItemData.cs - 物品数据定义

作用:定义物品的基本信息和类型

放置位置:不需要挂载到游戏物体,纯粹的数据类

cs 复制代码
public enum ItemType
{
    Consumable, //消耗品
    Weapon,    //武器
    Material   //材料
}

[System.Serializable]
public class ItemData
{
    public string itemId;
    public string itemName;
    public Sprite icon;
    public int count;
    public ItemType type;

    public ItemData(string id, string name, Sprite icon, int count, ItemType type)
    {
        this.itemId = id;
        this.itemName = name;
        this.icon = icon;
        this.count = count;
        this.type = type;
    }
}

2. InventorySlot.cs - 单个物品格子

作用:控制每个背包格子的显示和点击交互

放置位置:背包格子预制体(每个格子一个)

cs 复制代码
/// <summary>
/// 库存槽位类,管理单个物品槽位的UI显示和交互
/// </summary>
public class InventorySlot : MonoBehaviour, IPointerClickHandler
{
    [Header("UI组件")]
    public Image itemIcon;      // 物品图标显示组件
    public Text countText;      // 物品数量显示文本

    private InventoryManager manager;  // 库存管理器引用
    private int slotIndex;             // 当前槽位在库存中的索引
    private ItemData currentItem;      // 当前槽位存放的物品数据

    /// <summary>
    /// 初始化槽位
    /// </summary>
    /// <param name="mgr">库存管理器实例</param>
    /// <param name="index">槽位索引号</param>
    public void Setup(InventoryManager mgr, int index)
    {
        manager = mgr;          // 设置库存管理器引用
        slotIndex = index;      // 设置槽位索引
        ClearSlot();            // 初始化时清空槽位显示
    }

    /// <summary>
    /// 更新槽位显示信息
    /// </summary>
    /// <param name="item">要显示的物品数据</param>
    public void UpdateSlot(ItemData item)
    {
        currentItem = item;     // 更新当前物品引用

        // 如果物品存在且数量大于0,显示物品信息
        if (item != null && item.count > 0)
        {
            itemIcon.sprite = item.icon;            // 设置物品图标
            itemIcon.color = Color.white;           // 设置图标为完全显示
            countText.text = item.count > 1 ? item.count.ToString() : "";  // 数量大于1时显示数量
        }
        else
        {
            ClearSlot();        // 否则清空槽位显示
        }
    }

    /// <summary>
    /// 清空槽位显示
    /// </summary>
    void ClearSlot()
    {
        itemIcon.sprite = null;                     // 移除图标
        itemIcon.color = new Color(1, 1, 1, 0);     // 设置图标完全透明
        countText.text = "";                        // 清空数量文本
    }

    /// <summary>
    /// 处理鼠标点击事件
    /// </summary>
    /// <param name="eventData">指针事件数据</param>
    public void OnPointerClick(PointerEventData eventData)
    {
        // 如果槽位为空,不处理点击
        if (currentItem == null) return;

        // 左键点击 - 使用物品
        if (eventData.button == PointerEventData.InputButton.Left)
        {
            manager.UseItem(slotIndex);
        }
        // 右键点击 - 移除物品
        else if (eventData.button == PointerEventData.InputButton.Right)
        {
            manager.RemoveItem(slotIndex);
        }
    }
}

3. InventoryManager.cs - 背包管理器

作用:管理整个背包系统,处理物品的添加、移除、使用等逻辑

放置位置:场景中的空物体,比如命名为"InventoryManager"

cs 复制代码
using UnityEngine.UI;

/// <summary>
/// 背包系统核心管理器
/// 负责物品的添加、删除、显示等功能
/// </summary>
public class InventoryManager : MonoBehaviour
{
    [Header("背包设置")]
    public Transform contentParent;     // 包含所有格子预制体的父物体

    private List<ItemData> items = new List<ItemData>();
    private List<InventorySlot> slots = new List<InventorySlot>();

    void Start()
    {
        // 初始化现有的格子
        InitializeExistingSlots();

        // 清空所有格子(可选)
        ClearAllSlots();
    }

    // 初始化已经存在的格子预制体
    void InitializeExistingSlots()
    {
        // 获取Content下所有的InventorySlot组件
        InventorySlot[] existingSlots = contentParent.GetComponentsInChildren<InventorySlot>();

        // 初始化每个格子
        for (int i = 0; i < existingSlots.Length; i++)
        {
            existingSlots[i].Setup(this, i);
            slots.Add(existingSlots[i]);
        }

        Debug.Log($"初始化了 {slots.Count} 个现有格子");
    }

    // 添加物品到背包
    public void AddItem(ItemData newItem)
    {
        // 检查堆叠
        foreach (ItemData item in items)
        {
            if (item.itemId == newItem.itemId)
            {
                item.count += newItem.count;
                UpdateSlots();
                return;
            }
        }

        // 添加新物品
        if (items.Count < slots.Count)
        {
            items.Add(newItem);
            UpdateSlots();
        }
        else
        {
            Debug.Log("背包已满!");
        }
    }

    // 移除物品
    public void RemoveItem(int slotIndex)
    {
        if (slotIndex < items.Count)
        {
            items.RemoveAt(slotIndex);
            UpdateSlots();
        }
    }

    // 使用物品
    public void UseItem(int slotIndex)
    {
        if (slotIndex < items.Count)
        {
            ItemData item = items[slotIndex];
            Debug.Log($"使用了: {item.itemName}");

            item.count--;

            if (item.count <= 0)
            {
                RemoveItem(slotIndex);
            }
            else
            {
                UpdateSlots();
            }
        }
    }

    // 更新所有格子显示
    void UpdateSlots()
    {
        for (int i = 0; i < slots.Count; i++)
        {
            ItemData item = i < items.Count ? items[i] : null;
            slots[i].UpdateSlot(item);
        }
    }

    // 清空所有格子
    public void ClearAllSlots()
    {
        items.Clear();
        UpdateSlots();
    }

    // 获取背包中物品数量
    public int GetItemCount()
    {
        return items.Count;
    }

    // 获取背包容量
    public int GetBackpackCapacity()
    {
        return slots.Count;
    }
}

4.GameController.cs - 外部添加游戏物品

作用:添加指定Icon的游戏物体

放置位置 :场景中的空物体,比如命名为"GameController"

cs 复制代码
public class GameController : MonoBehaviour
{
    public InventoryManager inventory;
    public Sprite HPIcon;
    public Sprite MPIcon;
    public Sprite ArmorIcon;
    public Sprite WeaponIcon;

    
    void Update()
    {
        // 按1键添加生命药水
        if (Input.GetKeyDown(KeyCode.Alpha1))
        {
            ItemData newPotion = new ItemData("potion_1", "生命药水", HPIcon, 1, ItemType.Consumable);
            inventory.AddItem(newPotion);
        }
        // 按2键添加魔法药水
        if (Input.GetKeyDown(KeyCode.Alpha2))
        {
            ItemData newPotion = new ItemData("potion_2", "魔法药水", MPIcon, 1, ItemType.Consumable);
            inventory.AddItem(newPotion);
        }
        // 按3键添加装备
        if (Input.GetKeyDown(KeyCode.Alpha3))
        {
            ItemData newPotion = new ItemData("potion_3", "装备", ArmorIcon, 1, ItemType.Weapon);
            inventory.AddItem(newPotion);
        }
        // 按4键添加武器
        if (Input.GetKeyDown(KeyCode.Alpha4))
        {
            ItemData newPotion = new ItemData("potion_4", "武器", WeaponIcon, 1, ItemType.Weapon);
            inventory.AddItem(newPotion);
        }
    }
}

2.4.7.1 属性介绍

Unity 的 DropDown 控件(也常被称为下拉菜单)是一个能让用户从预设列表中挑选单个选项的UI元素。它通过点击展开选项列表,选择后列表收起,只显示当前选中的选项,非常节省界面空间。

属性 说明
Interactable 控件是否可交互。
Transition 控件在不同状态(如正常、悬停、按下)间的视觉过渡效果。
Navigation 定义使用键盘或手柄导航时的切换顺序。
Template 下拉列表的模板 RectTransform,用于实例化选项列表。
Caption Text 用于显示当前选中选项文本的 Text 组件。
Caption Image 用于显示当前选中选项图像的 Image 组件。
Item Text 用于显示选项列表中每一项文本的 Text 组件。
Item Image 用于显示选项列表中每一项图像的 Image 组件。
Value 当前选中选项的索引(从0开始)。
Options 选项列表,每个选项可包含文本和图像。
2.4.7.2 使用方式
cs 复制代码
using UnityEngine.UI;

public class DropDownControl : MonoBehaviour
{
    public Dropdown myDropdown;
    void Start()
    {
        myDropdown.onValueChanged.AddListener(OnDropdownValueChanged);
    }
    private void OnDropdownValueChanged(int selectedIndex)
    {
        // 根据 selectedIndex 执行不同的逻辑
        Debug.Log("选择了选项索引: " + selectedIndex);
        switch (selectedIndex)
        {
            case 0:
                // 处理选项1
                break;
            case 1:
                // 处理选项2
                break;
            case 2:
                // 处理选项3
                break;
        }

        // 或者通过 dropdown.options[selectedIndex].text 获取选中文本
        string selectedText = myDropdown.options[selectedIndex].text;
    }

}

3 UI Toolkit

3.1 简介

UI Toolkit 是 Unity 推出的新一代跨平台 UI 框架 ,旨在替代传统的 IMGUI(即时模式 GUI)并补充 / 升级 UGUI(Unity GUI),核心定位是「编辑器扩展 + 运行时 UI 通用解决方案」。它基于现代 Web 技术思想(HTML/CSS/JS 分离模式),采用「结构 - 样式 - 逻辑分离」的设计,兼具高性能、跨平台兼容性和灵活的扩展性,是 Unity 官方推荐的未来 UI 开发标准。

1. 核心定位

  • 「编辑器 + 运行时」双场景支持:既能开发 Unity 编辑器扩展(如自定义窗口、Inspector 面板),也能开发游戏内运行时 UI(如菜单、 HUD、弹窗)。

  • 替代 IMGUI:解决 IMGUI 「无状态、绘制依赖代码执行」的局限性,提供更稳定的可视化编辑工作流。

  • 补充 UGUI:优化 UGUI 「RectTransform 层级复杂、样式与逻辑耦合」的问题,提供更高效的布局和样式管理。

2. 设计目标

  • 跨平台一致性:支持 PC、移动、主机、WebGL 等所有 Unity 支持的平台,UI 表现一致。

  • 高性能:采用「Retained Mode(保留模式)」(UI 状态持久化,仅在变更时重绘),配合 GPU 加速、Draw Call 自动合并,性能优于 UGUI(尤其复杂 UI 场景)。

  • 可视化工作流:提供 UI Builder 可视化编辑器,支持拖拽布局、实时预览,无需编写冗余代码。

  • 分离关注点:结构(UXML)、样式(USS)、逻辑(C#)完全分离,便于团队协作和维护。

3.2 UI Toolkit 与 UGUI 的比较

选择合适的UI系统对项目至关重要。UI Toolkit和UGUI有各自的特点和适用场景。

特性/方面 UI Toolkit UGUI (Unity UI)
架构与性能 基于保留模式的视觉内容树 ,适合复杂静态UI,在渲染大量元素时性能可能更优。 基于Canvas的即时模式 ,更适合动态变化频繁的UI。
开发体验 提供UI Builder可视化编辑 ,样式与逻辑分离(USS+UXML+C#),更接近现代Web开发。 主要依赖Scene视图拖拽编辑,样式与结构耦合。
学习曲线 有一定学习曲线,需了解USS/UXML及数据绑定等概念。 学习曲线相对平缓,概念对Unity开发者更熟悉。
主要应用场景 编辑器扩展复杂的游戏UI (如模拟经营类游戏、Moba游戏技能UI)、Web风格应用 动态UI (如血条、得分飘字)、快速原型开发移动端简单UI

3.3 UI Toolkit 核心概念与工作流

了解UI Toolkit的核心概念和工作流程,能更好地构建界面。

  • 核心架构 :UI Toolkit的根基是VisualElement类。你可以将其理解为所有UI元素的基类,它构成了UI的视觉内容树 。通过VisualElement的各种派生类(如Button, Label)以及创建自定义视觉元素,你可以构建出复杂的界面。

  • 样式与布局USS 负责控制UI元素的外观,你可以定义如颜色、字体等样式属性。UXML 文件则用于定义用户界面的结构和层级关系 ,它使用一种类似HTML的标签语法来组织UI元素。响应式布局 机制可以让你创建的UI自动适应不同的屏幕尺寸。

  • 数据处理与事件响应 :UI Toolkit提供了数据绑定 系统,可以将UI元素与游戏数据关联起来,实现数据的自动同步。事件处理 系统则用于响应各类用户交互。

  • 开发工作流程 :使用UI Toolkit创建UI的一般步骤是:首先在UI Builder 中通过拖放方式可视化地搭建 UI结构并设置基本样式,这会产生相应的UXML和USS文件。然后,在C#脚本中引用这些资源处理UI逻辑 (如按钮点击响应),并将UI实例化显示给用户。

相关推荐
梵克之泪2 小时前
【号码分离】从Excel表格、文本、word文档混乱文字中提取分离11位手机号出来,基于WPF的实现方案
开发语言·ui·c#
jtymyxmz4 小时前
《Unity Shader》7.3 渐变纹理
unity·游戏引擎
ThreePointsHeat21 小时前
Unity 关于打包WebGL + jslib录制RenderTexture画面
unity·c#·webgl
胡童嘉1 天前
长沙烈焰鸟网络科技有限公司实习day13日记
功能测试·学习·职场和发展·游戏引擎·cocos2d
y***54881 天前
C++在游戏引擎中的开发
开发语言·c++·游戏引擎
BuHuaX1 天前
Unity_AssetBundle相关
unity·c#·游戏引擎·游戏策划
神码编程1 天前
【Unity】 HTFramework框架(六十八)StringEditor字符串复杂编辑器
unity·编辑器·游戏引擎·htframework
开发游戏的老王1 天前
UE5.6 C++项目升级UE5.7时用Rider加载项目失败的解决办法
ue5·游戏引擎·虚幻·虚幻引擎·rider·ue5.7·target.cs
TO_ZRG1 天前
Unity-iPhone、Unity-Framework target 如何选择、@rpath报错
unity·ios·iphone