Unity UI 从零到精通 (第30天): Canvas、布局与C#交互实战
Langchain系列文章目录
01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南
02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖
03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南
04-玩转 LangChain:从文档加载到高效问答系统构建的全程实战
05-玩转 LangChain:深度评估问答系统的三种高效方法(示例生成、手动评估与LLM辅助评估)
06-从 0 到 1 掌握 LangChain Agents:自定义工具 + LLM 打造智能工作流!
07-【深度解析】从GPT-1到GPT-4:ChatGPT背后的核心原理全揭秘
PyTorch系列文章目录
Python系列文章目录
C#系列文章目录
01-C#与游戏开发的初次见面:从零开始的Unity之旅
02-C#入门:从变量与数据类型开始你的游戏开发之旅
03-C#运算符与表达式:从入门到游戏伤害计算实践
04-从零开始学C#:用if-else和switch打造智能游戏逻辑
05-掌握C#循环:for、while、break与continue详解及游戏案例
06-玩转C#函数:参数、返回值与游戏中的攻击逻辑封装
07-Unity游戏开发入门:用C#控制游戏对象移动
08-C#面向对象编程基础:类的定义、属性与字段详解
09-C#封装与访问修饰符:保护数据安全的利器
10-如何用C#继承提升游戏开发效率?Enemy与Boss案例解析
11-C#多态性入门:从零到游戏开发实战
12-C#接口王者之路:从入门到Unity游戏开发实战 (IAttackable案例详解)
13-C#静态成员揭秘:共享数据与方法的利器
14-Unity 面向对象实战:掌握组件化设计与脚本通信,构建玩家敌人交互
15-C#入门 Day15:彻底搞懂数组!从基础到游戏子弹管理实战
16-C# List 从入门到实战:掌握动态数组,轻松管理游戏敌人列表 (含代码示例)
17-C# 字典 (Dictionary) 完全指南:从入门到游戏属性表实战 (Day 17)
18-C#游戏开发【第18天】 | 深入理解队列(Queue)与栈(Stack):从基础到任务队列实战
19-【C# 进阶】深入理解枚举 Flags 属性:游戏开发中多状态组合的利器
20-C#结构体(Struct)深度解析:轻量数据容器与游戏开发应用 (Day 20)
21-Unity数据持久化进阶:告别硬编码,用ScriptableObject优雅管理游戏配置!(Day 21)
22-Unity C# 健壮性编程:告别崩溃!掌握异常处理与调试的 4 大核心技巧 (Day 22)
23-C#代码解耦利器:委托与事件(Delegate & Event)从入门到实践 (Day 23)
24-Unity脚本通信终极指南:从0到1精通UnityEvent与事件解耦(Day 24)
25-精通C# Lambda与LINQ:Unity数据处理效率提升10倍的秘诀! (Day 25)
26-# Unity C#进阶:掌握泛型编程,告别重复代码,编写优雅复用的通用组件!(Day26)
27-Unity协程从入门到精通:告别卡顿,用Coroutine优雅处理异步与时序任务 (Day 27)
28-搞定玩家控制!Unity输入系统、物理引擎、碰撞检测实战指南 (Day 28)
29-# Unity动画控制核心:Animator状态机与C#脚本实战指南 (Day 29)
30-Unity UI 从零到精通 (第30天): Canvas、布局与C#交互实战 (Day 30)
文章目录
- Langchain系列文章目录
- PyTorch系列文章目录
- Python系列文章目录
- C#系列文章目录
- 前言
- 一、UI 系统的基石:Canvas
- 1.1 Canvas 组件概述
- 1.1.1 Canvas 的作用
- 1.1.2 Render Mode (渲染模式)
- 1.2 Canvas Scaler 组件
- 1.2.1 UI Scale Mode (缩放模式)
- 二、核心 UI 元素详解
- 2.1 Text (文本)
- 2.1.1 常用属性
- 2.1.2 应用场景
- 2.2 Image (图像)
- 2.2.1 常用属性
- 2.2.2 应用场景
- 2.3 Button (按钮)
- 2.3.1 核心构成
- 2.3.2 Button 组件属性
- 2.3.3 应用场景
- 2.4 Slider (滑动条)
- 2.4.1 核心构成
- 2.4.2 Slider 组件属性
- 2.4.3 应用场景
- 2.5 InputField (输入字段)
- 2.5.1 核心构成
- 2.5.2 InputField 组件属性
- 2.5.3 应用场景
- 三、精准布局:RectTransform 系统
- 3.1 RectTransform 核心概念
- 3.1.1 Anchors (锚点)
- 3.1.2 Pivot (轴心)
- 3.2 响应式布局技巧
- 四、响应交互:UI 事件处理
- 4.1 Button 的 OnClick 事件
- 4.1.1 在 Inspector 中设置
- 4.1.2 通过 C# 脚本添加监听
- 4.2 其他 UI 事件
- 五、动态更新:C# 脚本控制 UI
- 5.1 获取 UI 组件引用
- 5.1.1 公共变量与 Inspector 赋值 (推荐)
- 5.1.2 代码查找 (GetComponent/Find)
- 5.2 更新 UI 内容
- 5.2.1 更新文本 (Text / TextMeshPro)
- 5.2.2 更新血条 (Slider / Image Fill)
- 5.2.3 控制按钮交互性
- 六、实践:制作游戏主界面
- 6.1 场景设置
- 6.2 创建 UI 管理脚本
- 6.3 关联脚本与 UI
- 6.4 运行测试
- 七、总结
前言
欢迎来到“C# for Unity 从入门到精通”系列专栏的第 30 天!用户界面(UI)是游戏与玩家沟通的桥梁,无论是显示信息、提供操作选项,还是营造氛围,都离不开精心设计的 UI。今天,我们将深入探讨 Unity 中 UI 开发的核心机制,学习如何构建用户界面元素,并通过 C# 脚本让它们响应玩家的操作,动态地展示游戏状态。本篇将重点介绍 Canvas 系统、核心 UI 控件、强大的 RectTransform 布局系统以及事件处理机制,最后通过一个实战案例,带你亲手打造一个包含血条、得分和暂停按钮的基础游戏主界面。无论你是 UI 新手还是希望巩固基础的开发者,本文都将为你提供清晰、实用的指引。
一、UI 系统的基石:Canvas
在 Unity 中,所有 UI 元素都必须存在于一个 Canvas(画布) 组件之下。可以把 Canvas 理解为绘制所有 UI 元素的“画板”。
1.1 Canvas 组件概述
当你创建一个 UI 元素时(如通过 GameObject -> UI -> Text
),如果场景中没有 Canvas,Unity 会自动为你创建一个。
1.1.1 Canvas 的作用
- 容纳 UI 元素: 它是场景中所有 UI 元素的根对象。
- 渲染控制: 决定 UI 如何绘制到屏幕上(Render Mode)。
- 缩放控制: 通过 Canvas Scaler 组件管理 UI 元素在不同分辨率下的缩放行为。
1.1.2 Render Mode (渲染模式)
Canvas 主要有三种渲染模式:
- Screen Space - Overlay: 这是最常用的模式。UI 会被渲染在屏幕的最顶层,覆盖所有场景摄像机看到的内容。适合大多数游戏 HUD(Heads-Up Display)和菜单。
- Screen Space - Camera: UI 会被渲染在指定的摄像机前方特定距离处。可以实现 UI 被 3D 物体遮挡的效果,常用于需要与 3D 世界融合的 UI。
- World Space: UI 就像场景中的普通 3D 对象一样存在于世界空间中。常用于制作游戏世界中的交互式面板(如 VR 界面、角色头顶血条等)。
对于初学者和大多数 2D/常规 3D 游戏的主界面,Screen Space - Overlay
是最常用的选择。
1.2 Canvas Scaler 组件
附加在 Canvas 上的 Canvas Scaler
组件至关重要,它控制着 UI 元素如何适应不同的屏幕分辨率。
1.2.1 UI Scale Mode (缩放模式)
- Constant Pixel Size: UI 元素保持固定的像素大小,屏幕越大,UI 看起来越小。
- Scale With Screen Size: 这是最常用的模式。你可以设定一个参考分辨率(Reference Resolution),UI 元素会根据当前屏幕分辨率相对于参考分辨率进行缩放。可以设置
Match
滑块来控制是优先匹配宽度还是高度,或者取一个中间值。 - Constant Physical Size: 根据屏幕的物理尺寸(DPI)来缩放,确保 UI 在不同设备上看起来物理大小一致。
对于跨平台游戏,强烈推荐使用 Scale With Screen Size
来保证 UI 在不同设备上的显示一致性。
二、核心 UI 元素详解
Unity 提供了丰富的内置 UI 元素,我们来了解几个最核心的。
2.1 Text (文本)
用于在屏幕上显示文字信息。
2.1.1 常用属性
- Text: 输入要显示的文本内容。
- Font: 设置字体。
- Font Style: 粗体、斜体等。
- Font Size: 字体大小。
- Alignment: 文本对齐方式(水平、垂直)。
- Color: 文本颜色。
- Rich Text: 是否启用富文本标签(如
<b>
加粗,<color=red>
变色)。
2.1.2 应用场景
显示得分、玩家名称、对话内容、提示信息等。
2.2 Image (图像)
用于显示图片、图标或作为背景。
2.2.1 常用属性
- Source Image: 指定要显示的 Sprite(精灵)或 Texture(纹理)。
- Color: 可以给图像叠加一层颜色(Tint),默认为白色(不改变原色)。
- Material: 可以指定用于渲染图像的材质,实现特殊效果。
- Image Type:
- Simple: 简单拉伸或缩放图像。
- Sliced: 九宫格切片模式。非常适合制作背景面板、按钮等需要保持边框不变,中间区域拉伸的 UI。需要在 Sprite Editor 中设置好九宫格边距。
- Tiled: 平铺模式。适合制作重复纹理背景。
- Filled: 填充模式。可以通过
Fill Amount
(0 到 1) 控制图像按特定方式(如水平、垂直、径向)显示多少比例。非常适合制作血条、进度条、技能冷却图标。
2.2.2 应用场景
游戏 Logo、按钮图标、角色头像、血条/魔法条(使用 Filled 模式)、背景图。
2.3 Button (按钮)
最常用的交互元素,用于响应用户的点击操作。
2.3.1 核心构成
一个典型的 Button 由以下部分组成:
- Image 组件: 显示按钮的背景或图标。
- Button 组件: 处理交互逻辑,包含点击事件(OnClick)。
- (可选) Text 组件: 作为 Button 的子对象,显示按钮上的文字。
2.3.2 Button 组件属性
- Interactable: 是否可交互。取消勾选后按钮变灰且无法点击。
- Transition: 按钮在不同状态(正常、高亮、按下、禁用)下的视觉反馈方式(颜色变化、精灵切换、动画)。
- OnClick (): 最重要的部分。这是一个事件列表,你可以将其他脚本中的公共方法拖拽到这里,当按钮被点击时,这些方法就会被调用。
2.3.3 应用场景
暂停游戏、确认选择、攻击、跳跃、打开菜单等。
2.4 Slider (滑动条)
允许用户在一个范围内拖动选择一个数值。
2.4.1 核心构成
- Background Image: 滑动条的背景轨道。
- Fill Area / Fill Image: 显示当前值的填充区域。
- Handle Slide Area / Handle Image: 用户拖动的滑块。
2.4.2 Slider 组件属性
- Interactable: 是否可交互。
- Direction: 滑动方向(从左到右、从右到左等)。
- Min Value / Max Value: 滑动条的最小值和最大值。
- Value: 当前的数值。
- On Value Changed (Single): 当滑动条的值发生改变时触发的事件。可以链接方法来响应数值变化。
2.4.3 应用场景
调节音量、设置灵敏度、显示血量/魔法值(通常是程序控制 Value,禁用 Interactable)。
2.5 InputField (输入字段)
允许用户输入文本。
2.5.1 核心构成
- Image 组件: 输入框的背景。
- Text Component: 显示用户输入的文本。
- Placeholder (Text): 当输入框为空时显示的提示文字。
2.5.2 InputField 组件属性
- Text: 当前输入的文本内容。
- Character Limit: 限制输入的最大字符数。
- Content Type: 限制输入类型(标准、整数、数字、密码等)。
- Placeholder: 关联 Placeholder 的 Text 组件。
- On Value Changed (String): 输入内容每次改变时触发的事件。
- On End Edit (String): 结束编辑(例如按下 Enter 或点击输入框外部)时触发的事件。
2.5.3 应用场景
输入玩家昵称、聊天信息、搜索内容等。
三、精准布局:RectTransform 系统
与场景中的普通 3D 对象使用 Transform 组件不同,UI 元素使用 RectTransform 组件来控制其位置、大小、旋转和缩放,并且提供了强大的锚点(Anchors)和轴心(Pivot)系统来实现灵活的布局。
3.1 RectTransform 核心概念
RectTransform 定义了一个矩形区域,所有 UI 元素的布局都是基于这个矩形。
3.1.1 Anchors (锚点)
锚点决定了 UI 元素相对于其父级 RectTransform 的对齐方式和拉伸行为。
- 是什么: 锚点是 UI 元素上的四个小三角形标记(可以在 Scene 视图中看到),它们定义了一个参考框。
- 作用: 当父容器大小改变时,UI 元素会根据其锚点的位置来调整自己的位置和大小,以保持与锚点定义的参考框之间的相对关系。
- 锚点模式:
- 固定模式 (Anchors Together): 四个锚点合并在一起。UI 元素的位置是相对于这个锚点的位置定义的,大小是固定的像素值。适用于图标、固定大小的按钮等。
- 拉伸模式 (Anchors Separated): 锚点分散开。UI 元素会随着父容器的尺寸变化而拉伸,其边缘与对应锚点之间保持固定的边距。适用于需要填满父容器或随屏幕拉伸的背景、面板等。
- 预设 (Presets): Unity 提供了一个方便的锚点预设窗口(点击 Inspector 中 RectTransform 左上角的方形图标),可以快速设置常用的对齐和拉伸模式(如左上角对齐、水平居中、垂直拉伸、完全拉伸等)。
(上图展示了锚点在父容器尺寸变化时的影响)
3.1.2 Pivot (轴心)
轴心是 UI 元素自身的旋转和定位的参考点。
- 是什么: Pivot 是一个在 UI 元素矩形内的归一化坐标点(X, Y 范围都是 0 到 1)。(0, 0) 代表左下角,(0.5, 0.5) 代表中心,(1, 1) 代表右上角。
- 作用:
- 定位: RectTransform 的
Position (X, Y, Z)
值实际上是其 Pivot 点相对于锚点的位置。 - 旋转/缩放: UI 元素的旋转和缩放都是围绕其 Pivot 点进行的。
- 定位: RectTransform 的
- 默认值: 通常 UI 元素的 Pivot 默认在中心 (0.5, 0.5)。
类比: 想象在一块木板(UI 元素)上钉一颗图钉(Pivot),然后用四根橡皮筋(到锚点的距离)把它固定在一个框架(父容器)里。改变框架大小时,橡皮筋会拉伸,木板会移动,但它始终围绕图钉点旋转和定位。
3.2 响应式布局技巧
结合使用 Anchors 和 Pivot 可以创建适应不同屏幕尺寸的 UI 布局。
- 固定位置和大小: 将锚点合并,设置好 Pivot 和 Position (通常 Pivot 设为对应角或边,如左上角 Pivot 为 (0, 1))。
- 相对父容器边缘: 将锚点吸附到父容器的某个边缘或角落,然后设置相对该锚点的偏移量。
- 百分比布局/拉伸: 分开锚点,让元素占据父容器的一部分区域。
熟练掌握 RectTransform 是实现专业、适配性强的 UI 的关键。
四、响应交互:UI 事件处理
让 UI 动起来的关键在于处理用户的输入事件,最常见的就是按钮点击。
4.1 Button 的 OnClick 事件
这是最常用的 UI 事件。当用户点击一个 Button 时,其 OnClick
事件列表中的所有注册方法都会被触发。
4.1.1 在 Inspector 中设置
- 选中你的 Button GameObject。
- 在 Inspector 中找到 Button 组件。
- 找到
OnClick ()
列表。 - 点击右下角的
+
号添加一个新的事件监听槽。 - 将包含公共方法(必须是
public
)的脚本所在的 GameObject 拖拽到事件槽的None (Object)
区域。 - 点击右侧的下拉菜单 (
No Function
),选择你想要调用的脚本及其公共方法。
优点: 直观、无需编码。
缺点: 耦合度高,不适合动态添加或移除监听。
4.1.2 通过 C# 脚本添加监听
可以在代码中动态地为 Button 添加点击事件监听器。
using UnityEngine;
using UnityEngine.UI; // 必须引入 UI 命名空间public class ButtonHandler : MonoBehaviour
{public Button myButton; // 在 Inspector 中拖拽按钮赋值void Start(){// 检查按钮是否已赋值if (myButton != null){// 添加监听器,使用 Lambda 表达式myButton.onClick.AddListener(() => {Debug.Log("按钮被点击了!");MyButtonClickAction(); // 调用另一个方法});// 或者直接添加一个已存在的方法// myButton.onClick.AddListener(MyButtonClickAction);}else{Debug.LogError("myButton 没有在 Inspector 中赋值!");}}// 必须是 public 方法才能在 Inspector 中直接绑定,但 AddListener 可以绑定 private 方法private void MyButtonClickAction(){Debug.Log("执行按钮点击后的具体逻辑。");// 在这里执行暂停游戏、打开商店等操作}// 如果需要移除监听(例如在对象销毁时)void OnDestroy(){if (myButton != null){// 移除所有监听器// myButton.onClick.RemoveAllListeners();// 或移除特定监听器(如果需要精确控制)myButton.onClick.RemoveListener(MyButtonClickAction); // 注意:如果是用 Lambda 添加的,移除会比较麻烦}}
}
优点: 灵活,解耦,适合在运行时动态管理事件。
缺点: 需要编写代码。
4.2 其他 UI 事件
- Slider:
OnValueChanged
- 滑动条数值改变时触发。 - InputField:
OnValueChanged
- 输入内容改变时触发;OnEndEdit
- 结束编辑时触发。 - Toggle:
OnValueChanged
- 切换开关状态时触发。
这些事件的设置方式与 Button 的 OnClick 类似,都可以在 Inspector 中或通过代码添加监听。
五、动态更新:C# 脚本控制 UI
游戏过程中,UI 常常需要根据游戏状态动态变化,例如更新血条、显示分数、改变按钮可用性等。这需要通过 C# 脚本来实现。
5.1 获取 UI 组件引用
首先,你的 C# 脚本需要获取到要控制的 UI 元素的引用。
5.1.1 公共变量与 Inspector 赋值 (推荐)
在脚本中声明 public
变量,然后在 Unity 编辑器的 Inspector 窗口中将对应的 UI GameObject 拖拽到变量槽中。
using UnityEngine;
using UnityEngine.UI; // 引入 UI 命名空间
using TMPro; // 如果使用 TextMeshPro,需要引入这个public class UIManager : MonoBehaviour
{// 在 Inspector 中拖拽对应的 UI 元素到这里public Slider healthSlider;public Image healthFillImage; // 如果使用 Image 做血条public Text scoreText;// public TextMeshProUGUI scoreText_TMP; // 如果使用 TextMeshPropublic Button pauseButton;// ... 其他代码 ...
}
优点: 直观,易于管理,性能较好(查找只在编辑时或 Start 时进行一次)。
5.1.2 代码查找 (GetComponent/Find)
在 Start
或 Awake
方法中使用 GetComponent
或 FindObjectOfType
等方法查找。
using UnityEngine;
using UnityEngine.UI;public class UIManager : MonoBehaviour
{private Slider healthSlider;private Text scoreText;void Awake(){// 假设 Slider 是当前 GameObject 的子对象healthSlider = GetComponentInChildren<Slider>();// 假设 Score Text 有一个独特的 Tag "ScoreText"GameObject scoreTextObject = GameObject.FindGameObjectWithTag("ScoreText");if (scoreTextObject != null){scoreText = scoreTextObject.GetComponent<Text>();}if (healthSlider == null || scoreText == null){Debug.LogError("未能找到必要的 UI 组件!");}}// ... 其他代码 ...
}
优点: 可以在脚本中动态查找,不依赖 Inspector 设置。
缺点: Find
操作相对耗时,不建议在 Update
中频繁调用;如果场景结构改变,查找可能会失败。
5.2 更新 UI 内容
获取到引用后,就可以通过修改组件的属性来更新 UI 了。
5.2.1 更新文本 (Text / TextMeshPro)
public void UpdateScore(int newScore)
{if (scoreText != null){scoreText.text = "得分: " + newScore.ToString();// 对于 TextMeshPro:// scoreText_TMP.text = $"得分: {newScore}";}
}
5.2.2 更新血条 (Slider / Image Fill)
假设有一个 UpdateHealth
方法,接收当前生命值和最大生命值。
public void UpdateHealth(float currentHealth, float maxHealth)
{// 使用 Sliderif (healthSlider != null){// Slider 的 value 通常是 0 到 1 或根据 Min/Max Value 设定// 如果 Min=0, Max=maxHealth,则直接赋值// healthSlider.value = currentHealth;// 更通用的做法是计算比例,假设 Slider 的 Min=0, Max=1if (maxHealth > 0) // 防止除以零{healthSlider.value = currentHealth / maxHealth;}else{healthSlider.value = 0;}}// 使用 Image 的 Filled 模式if (healthFillImage != null && healthFillImage.type == Image.Type.Filled){if (maxHealth > 0){healthFillImage.fillAmount = currentHealth / maxHealth; // fillAmount 范围是 0 到 1}else{healthFillImage.fillAmount = 0;}}
}
5.2.3 控制按钮交互性
public void SetPauseButtonInteractable(bool interactable)
{if (pauseButton != null){pauseButton.interactable = interactable; // 控制按钮是否可点击}
}
六、实践:制作游戏主界面
现在,我们将运用所学知识,制作一个包含血条、得分显示和暂停按钮的简单游戏主界面。
6.1 场景设置
- 创建一个新的 Unity 场景。
- 在 Hierarchy 窗口右键 ->
UI
->Canvas
,创建一个 Canvas。确保其 Render Mode 为Screen Space - Overlay
,并配置Canvas Scaler
使用Scale With Screen Size
,设置一个参考分辨率(如 1920x1080)。 - 选中 Canvas,在 Hierarchy 窗口右键 ->
UI
->Slider
,创建一个血条 Slider。调整其 RectTransform 的 Anchors 和 Pivot,将其放置在屏幕左上角或合适位置。可以去掉 Handle,只保留 Background 和 Fill。设置 Slider 的 Min Value = 0, Max Value = 1。 - 选中 Canvas,右键 ->
UI
->Text
(或TextMeshPro - Text
),创建一个得分 Text。调整 RectTransform,放置在屏幕右上角。修改 Text 内容为 “得分: 0”。 - 选中 Canvas,右键 ->
UI
->Button
(或TextMeshPro - Button
),创建一个暂停 Button。调整 RectTransform,放置在屏幕右上角得分下方或其他合适位置。修改 Button 子对象的 Text 内容为 “暂停”。
6.2 创建 UI 管理脚本
- 在 Project 窗口创建一个新的 C# 脚本,命名为
GameUIManager
。 - 将以下代码复制到
GameUIManager.cs
中:
using UnityEngine;
using UnityEngine.UI; // 引入 UI 命名空间
using TMPro; // 如果使用 TextMeshPro,取消注释这行并替换 Text 相关代码public class GameUIManager : MonoBehaviour
{[Header("UI References")]public Slider healthSlider; // 血条 Sliderpublic Text scoreText; // 得分 Text// public TextMeshProUGUI scoreText; // 如果使用 TextMeshPropublic Button pauseButton; // 暂停 Button[Header("Game State Sim")]public float maxHealth = 100f; // 模拟最大生命值public float currentHealth = 100f; // 模拟当前生命值public int currentScore = 0; // 模拟当前得分private bool isPaused = false; // 模拟游戏暂停状态void Start(){// 初始化 UIUpdateHealthUI(currentHealth, maxHealth);UpdateScoreUI(currentScore);// 为暂停按钮添加点击事件监听if (pauseButton != null){pauseButton.onClick.AddListener(TogglePause);}else{Debug.LogError("Pause Button not assigned in the Inspector!");}// ---- 模拟游戏状态变化 (仅用于演示) ----InvokeRepeating("SimulateDamage", 2.0f, 1.5f); // 每1.5秒扣血InvokeRepeating("SimulateScoreIncrease", 1.0f, 1.0f); // 每1秒加分// ---- 模拟结束 ----}// 公共方法:更新血条显示public void UpdateHealthUI(float health, float max){currentHealth = health; // 更新内部记录maxHealth = max; // 更新内部记录if (healthSlider != null){if (maxHealth > 0){healthSlider.value = currentHealth / maxHealth;}else{healthSlider.value = 0;}Debug.Log($"Health UI Updated: {currentHealth}/{maxHealth}");}}// 公共方法:更新得分显示public void UpdateScoreUI(int score){currentScore = score; // 更新内部记录if (scoreText != null){scoreText.text = "得分: " + currentScore.ToString();// scoreText.text = $"得分: {currentScore}"; // TextMeshPro 写法Debug.Log($"Score UI Updated: {currentScore}");}}// 暂停按钮点击时调用的方法public void TogglePause(){isPaused = !isPaused;if (isPaused){Time.timeScale = 0f; // 暂停游戏时间Debug.Log("游戏已暂停");// 可以在这里显示暂停菜单等}else{Time.timeScale = 1f; // 恢复游戏时间Debug.Log("游戏已恢复");// 隐藏暂停菜单}// 可以在此更新暂停按钮的文本,如 "恢复" / "暂停"}// ---- 模拟游戏状态变化的方法 (仅用于演示) ----void SimulateDamage(){if (!isPaused){UpdateHealthUI(Mathf.Max(0, currentHealth - 10), maxHealth); // 每次减少10点生命值}}void SimulateScoreIncrease(){if (!isPaused){UpdateScoreUI(currentScore + 5); // 每次增加5分}}// ---- 模拟结束 ----// 确保在脚本销毁时移除监听器(好习惯)void OnDestroy(){if (pauseButton != null){pauseButton.onClick.RemoveListener(TogglePause);}}
}
6.3 关联脚本与 UI
- 在 Hierarchy 窗口创建一个空的 GameObject,命名为
UIManager
。 - 将
GameUIManager.cs
脚本拖拽附加到UIManager
GameObject 上。 - 选中
UIManager
GameObject,在 Inspector 中找到GameUIManager
组件。 - 将场景中创建的
Slider
、Text
和Button
分别拖拽到脚本对应的Health Slider
、Score Text
和Pause Button
公共变量槽中。
6.4 运行测试
点击 Unity 编辑器的 Play 按钮。你应该能看到:
- 血条初始为满。
- 得分初始为 0。
- 血条会随着时间(模拟伤害)减少。
- 得分会随着时间(模拟得分)增加。
- 点击“暂停”按钮,游戏时间停止(血条和得分不再变化),再次点击则恢复。
恭喜你!你已经成功构建了一个基础的游戏主界面,并实现了动态更新和交互响应。
七、总结
今天,我们深入学习了 Unity UI 开发的核心知识与实践:
- Canvas: UI 系统的根基,理解其 Render Mode 和 Canvas Scaler 对于 UI 显示至关重要。
- 核心 UI 元素: 掌握了 Text, Image, Button, Slider, InputField 等常用组件的属性和应用场景,特别是 Image 的 Sliced 和 Filled 模式,以及 Button 的 OnClick 事件。
- RectTransform: 学习了 Anchors 和 Pivot 的概念,它们是实现精准、响应式 UI 布局的关键。
- UI 事件处理: 了解了如何在 Inspector 中或通过 C# 脚本为 Button 等元素添加事件监听,以响应用户交互。
- C# 脚本动态更新: 学会了通过 C# 脚本获取 UI 组件引用,并动态修改其属性来更新界面内容(如血条、分数)。
- 实践应用: 通过构建一个包含血条、得分和暂停按钮的游戏主界面,将理论知识应用于实际开发。
掌握 UI 开发是 Unity 游戏开发中不可或缺的一环。希望通过今天的学习,你能更有信心地构建和控制你的游戏界面。在后续的学习中,我们还会接触到更高级的 UI 技术和优化技巧。继续加油!
相关文章:
Unity UI 从零到精通 (第30天): Canvas、布局与C#交互实战
Langchain系列文章目录 01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南 02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖 03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南 04-玩转 LangChai…...
vue项目打包部署到maven仓库
需要的资源文件,都放在根目录下: 1. versionInfo.js const fs require(fs) const path require(path) const mkdirp require(mkdirp) const spawn require(child_process).spawnconst packageObj require(./package.json) const versionNo packa…...
【力扣】day1
文章目录 27.移除元素26. 删除有序数组的重复项 27.移除元素 26. 删除有序数组的重复项 我们仔细看一下这两道题的最后的返回值,为什么第一题返回slow 而第二题返回slow1 最后的返回值该如何返回绝对不是凭感觉,我们自己分析一下第一个slow,从0位置开始, 遇到val值就开始和fas…...
MySQL:B+树索引
InnoDB索引方案 为了使用二分法快速定位具体的目录项,假设所有目录项都可以在物理存储器上连续存储,有以下问题: InnoDB使用页为管理存储空间的基本单位,最多只能保证16KB的连续存储空间,记录数据量多可能需要非常大…...
如何建立可复用的项目管理模板
建立可复用的项目管理模板能够显著提高项目执行效率、减少重复劳动、确保项目管理标准化。在企业中,项目管理往往涉及多个步骤和多个团队,然而每次开始一个新项目时,如果都从头开始设计流程和文档,势必浪费大量的时间和精力。通过…...
Go:goroutine 和通道
goroutine f() // 等待 f() 返回 go f() // 新建一个调用 f() 的 goroutine,不用等待在 Go 语言里,goroutine 是并发执行的活动单元。与顺序执行程序不同,在有多个 goroutine 的并发程序中,不同函数可同时执行。程序启动时&…...
盛水最多的容器问题详解:双指针法与暴力法的对比与实现
文章目录 问题描述方法探讨方法一:暴力法(Brute Force)思路代码实现复杂度分析 方法二:双指针法(Two Pointers)思路正确性证明代码实现复杂度分析 方法对比总结 摘要 盛水最多的容器(Container …...
VMWare 16 PRO 安装 Rocky8 并部署 MySQL8
VMWare 16 PRO 安装 Rocky8 并部署 MySQL8 一.Rocky OS 下载1.官网 二.配置 Rocky1.创建新的虚拟机2.稍后安装系统3.选择系统模板4.设置名字和位置5.设置大小6.自定义硬件设置核心、运存和系统镜像7.完成 三.启动安装1.上下键直接选择安装2.回车安装3.设置分区(默认…...
日常学习开发记录-slider组件
日常学习开发记录-slider组件 从零开始实现一个优雅的Slider滑块组件前言一、基础实现1. 组件结构设计2. 基础样式实现3. 基础交互实现 二、功能增强1. 添加拖动功能2. 支持范围选择3. 添加垂直模式 三、高级特性1. 键盘操作支持2. 禁用状态 五、使用示例六、总结 从零开始实现…...
AIDL 中如何传递 Parcelable 对象
目录 1. 直接在 AIDL 中定义 Parcelable 对象2. 自定义 Parcelable 对象的传递3. 以 Rect 类为例的 Parcelable 实现4. 注意安全性5. 小结1. 直接在 AIDL 中定义 Parcelable 对象 背景说明 从 Android 10(API 级别 29)开始,AIDL 允许直接在 .aidl 文件中定义 Parcelable 对…...
LVGL实战训练——计算器实现
目录 一、简介 二、部件知识 2.1 按钮矩阵部件(lv_btnmatrix) 2.1.1 按钮矩阵部件的组成 2.1.2 按钮文本设置 2.1.3 按钮索引 2.1.4 按钮宽度 2.1.5 按钮属性 2.1.6 按钮互斥 2.1.7 按钮文本重着色 2.1.8 按钮矩阵部件的事件 2.1.9 按钮矩阵部件的 API 函数 2.2…...
代码随想录算法训练营Day30
力扣452.用最少数量的箭引爆气球【medium】 力扣435.无重叠区间【medium】 力扣763.划分字母区间【medium】 力扣56.合并区间【medium】 一、力扣452.用最少数量的箭引爆气球【medium】 题目链接:力扣452.用最少数量的箭引爆气球 视频链接:代码随想录 题…...
AIDL 语言简介
目录 软件包类型注释导入AIDL 的后端AIDL 语言大致上基于 Java 语言。AIDL 文件不仅定义了接口本身,还会定义这个接口中用到的数据类型和常量。 软件包 每个 AIDL 文件都以一个可选软件包开头,该软件包与各个后端中的软件包名称相对应。软件包声明如下所示: package my.pac…...
经典算法 判断一个图中是否有环
判断一个图中是否有环 问题描述 给一个以0 0结尾的整数对列表,除0 0外的每两个整数表示一条连接了这两个节点的边。假设节点编号不超过100000大于0。你只要判断由这些节点和边构成的图中是否存在环。存在输出YES,不存在输出NO。 输入样例1 6 8 5 3 …...
Transformer-PyTorch实战项目——文本分类
Transformer-PyTorch实战项目——文本分类 ———————————————————————————————————————————— 【前言】 这篇文章将带领大家使用Hugging Face里的模型进行微调,并运用在我们自己的新项目——文本分类中。需要大家提前下…...
Linux-服务器负载评估方法
在 Linux 服务器中,top 命令显示的 load average(平均负载)反映了系统在特定时间段内的负载情况。它通常显示为三个数值,分别代表过去 1 分钟、5 分钟和 15 分钟的平均负载。 1. 什么是 Load Average? Load average …...
Transformer编程题目,结合RTX 3060显卡性能和市场主流技术
以下是10道针对4年经验开发者的Transformer编程题目,结合RTX 3060显卡性能和市场主流技术,每题包含模型选择和实现逻辑描述: 题目1:医疗报告结构化提取 模型选择:BioBERT-base 要求: 开发从PDF医疗报告中提…...
Web三漏洞学习(其二:sql注入)
靶场:NSSCTF 、云曦历年考核题 二、sql注入 NSSCTF 【SWPUCTF 2021 新生赛】easy_sql 这题虽然之前做过,但为了学习sql,整理一下就再写一次 打开以后是杰哥的界面 注意到html网页标题的名称是 “参数是wllm” 那就传参数值试一试 首先判…...
VLAN的知识
1.什么是VLAN? VLAN是虚拟局域网,逻辑隔离广播域和网络区域 是一种通过将局域网内的设备逻辑地划分为一个个网络的技术 2.对比逻辑网络分割和物理网络分割? 逻辑网络分割是VLAN,隔离广播域和网络区域 物理网络分割是路由&…...
RFID 赋能部队智能物联网仓储建设:打造信息化高效解决方案
在当今军事现代化进程的宏大背景下,部队后勤保障工作无疑占据着举足轻重的地位,而仓储管理作为其中的核心环节,更是至关重要。传统的仓储管理模式在面对当下物资种类繁杂、数量庞大的现状时,已显得力不从心,效率低下、…...
结构型屏蔽在高频电子设备中的应用与优化
在当今高度电子化的时代,随着电子产品工作频率不断提高,设备内部温度上升,电磁环境日趋复杂,电磁兼容(EMC)问题成为设计和制造过程中必须重点解决的问题。EMC不仅关系到设备自身的稳定运行,更涉…...
【教程】Ubuntu修改ulimit -l为unlimited
转载请注明出处:小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你,欢迎[点赞、收藏、关注]哦~ 目录 问题描述 解决方法一 解决方法二 解决方法三 (终极) 问题描述 查系统资源限制 ulimit -l如果返回的是 64 或其他较小值,那么RDM…...
【HDFS】BlockPlacementPolicyRackFaultTolerant#getMaxNode方法的功能及具体实例
方法参数说明: numOfChosen:已经选择的节点数numOfReplicas:还需要选择的副本数方法的返回值是一个长度为2的数组:[调整后的要选出多少个节点(不包括已经选择的), 每个机架最大能选择的节点数] @Overrideprotected int[] getMaxNodesPerRack(int numOfChosen, int numOfR…...
水污染治理(生物膜+机器学习)
文章目录 **1. 水质监测与污染预测****2. 植物-微生物群落优化****3. 系统设计与运行调控****4. 维护与风险预警****5. 社区参与与政策模拟****挑战与解决思路****未来趋势** 前言: 将机器学习(ML)等人工智能技术融入植树生物膜系统ÿ…...
数模小白变大神的日记2025.4.15日
分工 1.论文:mathtype (Latex) 2.建模;相应的建模知识与撰写方法,写摘要 3.编程:matlab、SPSs、(Python) 评价模型 1. 层次分析法 ①层次分析法是一种多目标、多准则的决策问题 ②层次分析法是一种主观加权法 ③层次分析法通过以下步骤实现: 1.构…...
STM32提高篇: 以太网通讯
STM32提高篇: 以太网通讯 一.以太网通讯介绍二.W5500芯片介绍1.W5500芯片特点2.W5500应用目标3.接入框图 三.驱动移植四.tcp通讯五.udp通讯六.http_server 一.以太网通讯介绍 以太网(Ethernet)是一种计算机局域网技术。IEEE组织的IEEE 802.3标准制定了以…...
4-15记录(冒泡排序,快速选择排序)
算法稳定 简单选择排序的实质就是最后一个和第一个比较,小,就换位置,然后继续用最后一个数字和第二个比较,以此类推。 但是算法不稳定,本来下划线的2在后面,但是经过算法后去了前面 快速排序 实现过程&am…...
Ubuntu系统18.04更新驱动解决方法
原始是:ubuntu18.04里面的驱动是470,对应cuda11.4 现在需要更新为525,对应cuda为12.0 实现: 1、打开终端 Ctrl Alt T2、使用 lspci 命令(快速查看显卡型号) lspci | grep -i vga3、终端输入 ubuntu-d…...
Rocky Linux 9.x 基于 kubeadm部署k8s
搭建集群使用docker下载K8s,使用一主两从模式 主机名IP地址k8s- master192.168.1.141k8s- node-1192.168.1.142k8s- node-2192.168.1.143 一:准备工作 VMware Workstation Pro新建三台虚拟机Rocky Linux 9(系统推荐最小化安装) …...
MATLAB程序实现了一个物流配送优化系统,主要功能是通过遗传算法结合四种不同的配送策略,优化快递订单的配送方案
%% 主函数部分 % function main()clear; clc; close all;% 生成或加载算例 filename = D:\快递优化\LogisticsInstance.mat; if ~exist(filename, file)instance = generate_instance();save(filename, -struct, instance); elseinstance = load(filename); end% 遗传算法参数配…...
利用宝塔面板搭建RustDesk服务
一、介绍 1.1官网 https://rustdesk.com/ 1.2github仓库 https://github.com/rustdesk/rustdesk 1.3特点 RustDesk 支持多种操作系统,包括 Windows、macOS、Linux、Android 和 iOS。它甚至提供网页版客户端,可以在浏览器中直接使用。 用户可以通过…...
前端与Java后端交互出现跨域问题的14种解决方案
跨域问题是前端与后端分离开发中的常见挑战,以下是14种完整的解决方案: 1 前端解决方案( 开发环境代理) 1.1 Webpack开发服务器代理 // vue.config.js 或 webpack.config.js module.exports {devServer: {proxy: {/api: {target: http://localhost:8…...
PBKDF2全面指南(SpringBoot实现版)
文章目录 第一部分:PBKDF2基础概念1. 什么是PBKDF2?2. 为什么需要PBKDF2?3. PBKDF2的工作原理4. PBKDF2与其他密码散列函数的比较第二部分:在Java和SpringBoot中使用PBKDF21. Java内置的PBKDF2支持2. SpringBoot中集成PBKDF22.1 添加依赖2.2 配置PBKDF2密码编码器2.3 自定义…...
基于RV1126开发板的rknn-toolkit-lite使用方法
1. rknn-toolkit-lite介绍 rknn-toolkit-lite是用于python算法的推理的组件,当前已经在EASY-EAI-Nano完成适配,用户可以用它进行深度学习算法的纯python开发。而且同时支持已经进行了预编译的模型,短短几行代码即可完成算法的推理,…...
一款轻量级的PHP地址发布页面源码
源码介绍 一款轻量级的PHP链接发布页面源码,适合快速搭建个性化的链接导航网站,支持动态链接管理和多种风格模板切换 1:后台登录地址为/admin/login.php,提供便捷的配置入口。 2:默认用户名是admin,密码为…...
分布式计算领域的前沿工具:Ray、Kubeflow与Spark的对比与协同
在当今机器学习和大数据领域,分布式计算已成为解决大规模计算问题的关键技术。本文将深入探讨三种主流分布式计算框架——Ray、Kubeflow和Spark,分析它们各自的特点、应用场景以及如何结合它们的优势创建更强大的计算平台。 Spark批量清洗快,…...
【专题刷题】双指针(一)
📝前言说明: 本专栏主要记录本人的基础算法学习以及LeetCode刷题记录,按专题划分每题主要记录:1,本人解法 本人屎山代码;2,优质解法 优质代码;3,精益求精,…...
火山引擎旗下防御有哪些
首先,我需要确认用户是不是打错了,比如把“引擎”当成了“云”,或者他们真的想了解火山引擎的防御机制。火山引擎是字节跳动旗下的云服务平台,类似于阿里云或腾讯云,所以用户可能想了解的是其安全防护措施。 接下来&am…...
python程序打包——nuitka使用
目前python打包成exe的工具主要有:PyInstaller Briefcase py2exe py2app Nuitka CX_Freeze等。 不同于C代码,可以直接编译成可执行的exe文件,或者js代码在浏览器中就能执行,python代码必须通过python解释器来运行,…...
编写了一个专门供强化学习玩的贪吃蛇小游戏,可以作为后续学习的playgraound
文章目录 **试玩效果****项目背景****核心设计思路****代码亮点解析****与强化学习算法的对接示例****扩展方向****总结****完整代码**把训练一个会玩小游戏的智能体,作为学习强化学习的一个目标,真的是很有乐趣的一件事。我已经不知为此花费了多少日夜了。如今已是着魔了一般…...
chain_type=“stuff 是什么 ? 其他方式有什么?
chain_type="stuff 是什么 ? 其他方式有什么? 目录 chain_type="stuff 是什么 ? 其他方式有什么?1. `chain_type="stuff"`2. `chain_type="map_reduce"`3. `chain_type="refine"`4. `chain_type="map_rerank"`在 LangCh…...
在IDEA里面建立maven项目(便于java web使用)
具体步骤: 第一次有的电脑你再创建项目的时候右下角会提醒你弹窗:让你下载没有的东西 一定要下载!!可能会很慢 运行结果: 因为他是默认的8080端口所以在运行的时候输入的url如下图: 新建了一个controller代…...
MyBatis 详解
1. 什么是 MyBatis? MyBatis 是一款优秀的 持久层框架,它通过 XML 或注解配置,将 Java 对象(POJO)与数据库操作(SQL)进行灵活映射,简化了 JDBC 的复杂操作。 核心思想:S…...
郑州工程技术学院党委书记甘勇一行莅临埃文科技调研交流
为深化产教融合、推动人工智能领域人才培养与产业需求精准对接,2025年4月9日下午,郑州工程技术学院党委书记甘勇、河南省人工智能产业创新发展联盟执行秘书长孟松涛等一行莅临埃文科技调研交流。 一、聚焦技术前沿 共话AI产业变革 座谈会上,…...
AI应用开发之扣子第一课-夸夸机器人
首先,进入官网:点击跳转至扣子。 1.创建智能体 登录进网站后,点击左上角+图标,创建智能体,输入智能体名称、功能介绍 2.输入智能体提示词 在“人设与回复逻辑”输入以下内容: # 角色 你是一…...
Node.js 数据库 CRUD 项目示例
希望使用Nodejs操作数据库做CRUD,用deepseek实战搜索“使用Nodejs对数据库表做CRUD的项目例子”,找到了解决方案,如下图所示: 项目结构 nodejs-crud-example/ ├── config/ │ └── db.js # 数据库连接配置 ├──…...
ESP8266/32作为AVR编程器(ISP programmer)的使用介绍
ESP8266作为AVR编程器( ISP programmer)的使用介绍 🌿ESP8266自带库例程:https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266AVRISP📍支持ESP8266/32的ESP_AVRISP其它开源工程(个人没有再去验证)&…...
union all几个常见问题及其解决方案
UNION ALL 是 SQL 中用于合并两个或多个 SELECT 语句结果集的操作符。与 UNION 不同,UNION ALL 不会去除重复的记录,它简单地将一个查询的结果附加到另一个查询的结果之后。尽管 UNION ALL 相对来说更高效(因为它不需要检查重复项)…...
21.C++11
1.列表初始化 1.1C11中的{} •C11以后想统⼀初始化⽅式,试图实现⼀切对象皆可⽤{}初始化,{}初始化也叫做列表初始化。 • 内置类型⽀持,⾃定义类型也⽀持,⾃定义类型本质是类型转换,中间会产⽣临时对象,最…...
【交叉编译】目标机编译安装对应依赖库总结
1、解压目标机交叉编译工具链 # 创建工具链存放目录(可选) sudo mkdir -p /opt/toolchain# 解压到目标路径(示例路径:/opt/toolchain) sudo tar -xzvf 目标主机编译工具链.tar.gz -C /opt/toolchain# 查看解压后的目录…...