【3D游戏编程与设计】九 UI系统 血条
血条(Health Bar)的预制设计:
游戏设计要求
- 分别使用 IMGUI 和 UGUI 实现;
- 使用 UGUI,血条是游戏对象的一个子元素,任何时候需要面对主摄像机;
- 分析两种实现的优缺点;
- 给出预制的使用方法。
项目架构
软件版本
项目使用的开发软件为Unity 3D 2020.1.4f1c1。
文件组织
项目的资源文件夹包括Assets和Packages两个子文件夹。其中,Packages子文件夹存储了系统自带的一些包,在这个项目中并没有特别使用。而Assets文件夹则存储了这次游戏项目使用的资源,场景,脚本等。其中的Scripts文件夹存储了游戏中使用的脚本。而Prefabs文件夹存储了游戏中的预制对象。而Scenes文件夹存储了游戏的场景(这个游戏中只有一个场景)。Standard Assets文件夹则是导入的标准素材库的相关资源,这个游戏中使用到了ThirdPersonCharacter预制资源。
其中,项目编写的脚本包括如下文件:
设计思路与实现过程
IMGUI实现
IMGUI实现的思路是,将血条绘制在屏幕左上角。同时在屏幕上绘制增加血量和减少血量的两个按钮,方便用户操纵血条的值以观察血条的变化,注意要判断和处理血量不能低于0,也不能高于最大值。同时,会根据血量的多少选择使用不同的颜色绘制血条。血量最高时,血条为绿色,随着血量的降低,血条将变为黄色,红色。同时,血条的变化是使用Mathf.Lerp进行插值的,使得血量的降低和增加是渐变而不是突变的。这里同时挂载了Slider对象,也就是对应的UGUI血条,再用户按下增减血量的按钮时,同时触发UGUI血条的变化。代码如下,具体分析详见代码注释:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class IM_HPBar : MonoBehaviour {
public float health;//当前血量
private float res;//变化到的目标血量
public Slider healthSlider; //对应UGUI的血条
private float healthEps;//血条变化精度
void Start(){
health = 1.0f;//当前血量
res = 1.0f;//变化到的目标血量
healthEps = 0.1f;//血条变化精度
}
void OnGUI(){
if (GUI.Button (new Rect(255, 20, 40, 20), "+")) {//点击增加血量
if (res + healthEps > 1.0f) //超出最大值
res = 1.0f;//设置为最大值
else
res = res + healthEps;//否则增加一个量
}
if (GUI.Button (new Rect(310, 20, 40, 20), "-")) {//点击减少血量
if (res - healthEps < 0.0f) //低于最小值
res = 0.0f;//设置为最小值
else
res = res - healthEps;//否则减少一个量
}
health = Mathf.Lerp(health, res, 0.05f);//进行插值
if (health > 0.7f)//根据当前血量的多少决定绘制血条的颜色
GUI.color = Color.green;
else if (health > 0.4f)
GUI.color = Color.yellow;
else
GUI.color = Color.red;
GUI.HorizontalScrollbar(new Rect(20, 20, 200, 20), 0.0f, health, 0.0f, 1.0f);//使用水平滚动条绘制血条 将其宽度作为血条的显示值
if (healthSlider != null) //如果存在对应UGUI的血条
healthSlider.value = health * 100;//修改对应UGUI的血条
}
}
之后建立一个空的游戏对象IMGUI,然后将实现上面IMGUI的IM_HPBar.cs挂载到该空对象IMGUI上,就可以制作一个IMGUI血条的预制,该预制就可以被使用。
这样就实现了使用IMGUI实现血条。
UGUI实现
首先,将Standard Assets中的Characters,PhysicsMaterials,Utility,Editor,CrossPlatformInput等素材导入。
之后在层次视图中添加Plane对象:
将 ThirdPersonController 预制拖放放入场景,改名为 Player 并设置以下属性:
之后选择 Player,用上下文菜单添加画布子对象:
之后选择Player的 Canvas子对象,用上下文菜单添加Slider作为血条子对象:
之后设置Player的Canvas的属性如下图所示:
同时,编写LookAtCamera.cs脚本如下,并将该脚本拖入上面的canvas:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LookAtCamera : MonoBehaviour {
void Update () {
this.transform.LookAt (Camera.main.transform.position);
}
}
该脚本使得作用对象始终面向主摄像机,也就使得血条始终面向主摄像机。
之后设置canvas的Slider子对象的属性如下图所示:
对于Slider的Fill Area子对象的Fill子对象的Image组件,设置颜色为蓝色,也就是该UGUI血条的颜色为蓝色:
之后将进行设置过的Canvas拖到Prefabs子文件夹中成为预制。
这样就完成了UGUI血条的制作。在之前IMGUI的脚本中挂载该Slider,就可以实现IMGUI的血量增加和减少按钮同时可以操纵该UGUI血条的血量。
两种实现的优缺点
IMGUI(Immediate Mode GUI)在早期版本的Unity就出现,其为及时模式图形界面,是代码驱动的 UI 系统,其在Unity编辑器中没有图形化设计界面。IMGUI只能在 OnGUI 阶段用 GUI 系列的类绘制各种 UI 元素,因此 UI元素只能浮在游戏界面之上。IMGUI 的存在符合游戏编程的传统,即使在今天它依然没有被官方宣判为遗留(将要淘汰的)系统(Legacy Systems)。在修改模型,渲染模型这样的经典游戏循环编程模式中,在渲染阶段之后,绘制 UI 界面无可挑剔。这样的编程即避免了 UI 元素保持在屏幕最前端,又有最佳的执行效率,一切控制掌握在程序员手中,这对早期计算和存储资源贫乏的游戏设备来说,更是弥足珍贵。当然,早年 UI 交互手段就是绘制图片和文本,检测输入事件等基本任务。
所以IMGUI的优点:
- 可以为脚本组件创建自定义的 Inspector 面板
- 可以创建新的编辑器窗口和工具来扩展 Unity 环境
- 可以在游戏中创建调试显示工具
- IMGUI 的存在符合循环渲染模型游戏编程的传统
- 这样的编程一切控制掌握在程序员手中,既避免了 UI 元素保持在屏幕最前端,又有最佳的执行效率
IMGUI的缺点:
- 代码驱动的 UI 开发效率比较低下
- 涉及编码,可能会因为错误而需要额外的调试
- 开发周期相对较长
UGUI则是面向对象的 UI 系统。其所有 UI 元素都是游戏对象,有着友好的图形化设计界面,可支持在场景渲染阶段渲染这些 UI 元素。
UGUI的优点:
- 是一种所见即所得(WYSIWYG)的设计工具
- 支持多模式、多摄像机渲染
- 有图形界面来操作,开发效率比较高
- 采用面向对象的思想,可以获得面向对象编程的一些优势
- 几乎不需要太多编码,就可以创建出很好的GUI效果
UGUI的缺点:
- UGUI如果对象过多,需要太多的canvas对象,运行性能较低
- 学习图形编辑界面也需要一定的时间
预制的使用方法
IMGUI血条预制的使用方法:
将制作好的IMGUI预制拖入场景中即可使用。
UGUI血条预制的使用方法:
先创建一个需要展示血条的游戏对象,然后将Canvas预制体拖入到该游戏对象成为其子对象。