实现简单血条预制:
- 分别使用 IMGUI 和 UGUI 实现
- 使用 UGUI,血条是游戏对象的一个子元素,任何时候需要面对主摄像机
- 分析两种实现的优缺点
- 给出预制的使用方法
步骤分析:
首先IMGUI在之前的实验中也有用到,主要是用来设置开始游戏和结束游戏的界面。实现方法是在onGUI函数中添加相应的控件(Label、Button等),也就是说每次都调用onGUI都会刷新一次所有控件。
而UGUI是课上新接触的UI设计工具。主要设计可以通过鼠标拖拽、设置属性等方式,在二维平面上完成UI设计,即时能够看到效果。换句话说可以不通过代码就能实现一定的UI效果。
分析完两者的一些区别之后就开始动手实现了。
由于IMGUI主要是通过代码来实现UI,所以也没有说需要建立模型什么的,调整位置也是靠代码控制xy坐标来实现。所以直接上代码:
public class IMGUIhealth : MonoBehaviour
{
public float value;
private float tmp;
// Start is called before the first frame update
private void OnGUI()
{
// 加号按钮,点击时增加血量,每次增加十分之一
if (GUI.Button(new Rect(450, 50, 40, 40), "+"))
{
tmp += 10;
if (tmp > 100)
tmp = 100;
}
// 减号按钮,点击时减少血量,每次减少十分之一
if (GUI.Button(new Rect(100, 50, 40, 40), "-"))
{
tmp -= 10;
if (tmp < 0)
tmp = 0;
}
// 线性插值,使得变化更平滑
value = Mathf.Lerp(value, tmp, 0.05f);
// 使用HorizontalScrollbar作为血条主体,利用value来控制血量多少
GUI.color = Color.red;
GUI.HorizontalScrollbar(new Rect(200, 50, 200, 20), 0, value, 0, 100);
}
}
代码主要添加了三个控件:两个Button负责加减血量,一个水平滚动条负责显示血量。
Button的用处就不讲了,之前实践过很多次了,对于HorizontalScrollbar
来说,是第一次接触,所以看下官方文档:
大概理解一下各个参数的意思:
Parameter | 意义 |
---|---|
position | 整个滚动条的位置和大小 |
value | 滚动条的那一个滑块的位置 |
size | 滑块大小(长度) |
leftValue | 最小值 |
rightValue | 最大值 |
style | 滚动条的样式 |
翻译了一遍,但是对于某些部分还是有点不理解,就拿现成的例子说明以下:
箭头所指为滑块,可以知道我们滚动移动的时候改变的是滑块的位置。对于不同的网页,滑块的长度会不一样:
基于这个想法,我们可以利用滑块的长度作为血条现有血量的多少,将滑块的位置固定在0端,也就是最左端(最小值处),改变滑块的长度(0~100)来显示血量的变化。
所以有了以下的这一句代码:
GUI.HorizontalScrollbar(new Rect(200, 50, 200, 20), 0, value, 0, 100);
其中Rect后的第一个数字0,表示滑块的当前位置,0就是最左边。value就是当前血量,也就是对应着滑块长度。
最后将脚本挂载到摄像机上!
显示效果(静态):
(注:其实有一个控件是HorizontalSlider
水平滑动条,但是由于没有滑块的大小,所以显示不出血量的变化,相比之下HorizontalScrollbar
更加适合血条的样式)
UGUI是为了让设计师能够直接参与UI设计而产生的,所以UGUI有一个设计界面,有所见即所得的方便之处。所以不同于代码编程,用UGUI设计出来会得到一个模型,也就是我们的游戏对象,所以可以将其变为预制,使用的时候直接拖入场景中进行实例化使用。
参考老师课程网站上的教程进行UGUI血条预制:
首先创建一个Canvas
对象作为UGUI控件的一个载体,并且取名为Health
.然后在这个载体里面添加一个Slider
.对象结构如下:Slider
下的子对象是自动生成的不需要手动添加。
设置 Canvas 组件 Render Mode 为 World Space
设置 Rect Transform 组件 (PosX,PosY,Width, Height) 为 (0,2,160,20)
设置 Rect Transform 组件 Scale (x,y) 为 (0.01,0.01):
由于我们不需要拖动Slider,所以把Handle Slide Area
禁用掉,至于Background
可以禁可以不禁,不禁的话就可以当空血槽,效果也不错,看个人喜欢。然后更改fill的属性值,在Image的部件中找到color一项,改变它的颜色:
然后在Scene界面点击2D的按钮,可以直观看到效果:
一个绿色的长条就制作完成了。
改变Slider的属性:
设置 MaxValue 为 100
设置 Value 为 75 :
可以看到缺了一部分。如果加上background,会看的更明显:
下面给他添加一个脚本。
由于它会随着物体转动而转动,所以需要让其时时刻刻都保持面向摄像头,然后自己给他添加了一点颜色改变的逻辑,当血量少到一定程度就会变黄再变红。还做了一个让血条自己变化的一个函数(因为血条量可以通过Slider的Inspetor的slider部件改变,所以这里就没有做一个加减血量的按钮)。
public class HealthBar : MonoBehaviour {
public Slider slider;
float factor = 0.1f;
public bool active = true;
private int turn = 1;
private void Start()
{
}
void change() {
if (turn == 1)
slider.value -= 1f;
else
slider.value += 1f;
if (slider.value <= 0) {
slider.value = 0;
turn = 2;
}
if (slider.value >= 100) {
slider.value = 100;
turn = 1;
}
}
void Update () {
this.transform.LookAt (Camera.main.transform.position);
if (active)
change();
Color current = slider.fillRect.transform.GetComponent().color;
if (slider.value <= 20) {
slider.fillRect.transform.GetComponent().color = Color.Lerp(current, Color.red, factor);
}
else if (slider.value <= 70) {
slider.fillRect.transform.GetComponent().color = Color.Lerp(current, Color.yellow, factor);
}
else {
slider.fillRect.transform.GetComponent().color = Color.Lerp(current, Color.green, factor);
}
}
}
最后将脚本拖到Heath的画布上面去,将Slider拖入脚本的slider变量中去,完成脚本与Slider的绑定。Active是选择是否让其自动变化。
将其拖到一个物体Cube上,观察效果:
(看到效果,我们可能会发现,血条的左右是反的?就是会从右边开始增加减少,这时候只需要稍微设置一下slider的方向即可,因为实际上我们创建Slider的时候,他的Z轴是朝向正方向的,也就是说他的正方向恰好的背对着摄像头,这时候我们看到的效果才是正常的,但是如果设置了LookatCamera,那么就会出现了相反的效果,这时候我们可以通过设置他的方向来调整,这个可能实现方法不同效果不太一样,根据实际情况进行调整)
拖动Slider的slider部件中的value选项:
就可以看到血条在变化。
IMGUI:
UGUI:
优点:
优点:
缺点:
Health
,将其拖到一个物体上,使其成为该物体的子对象。(当然也可以直接将预制拖到场景中,单独查看血条的效果)本次实验到此完成!
提出一点方案建议,没来得及研究实现。
根据参考资料:Faking World Space for monster health bars in Unity
如果你在生产中使用上述血条,足以证明你是入门级别程序员。为了显示血条,每个图片从 pixel 单位映射到 world space,再投影到摄像机空间,在变成屏幕空间(pixel 单位)这需要多少算力?
因此,能用 Srceen Space 解决的问题绝不用 World Space, 能用 Overlay 解决问题绝不用 Camera!
由于使用World Space会降低性能,这个例子中是用到Canvas 组件 Render Mode 为Screen Space - Overlay来实现的。所以会需要一个从worldSpace到屏幕的映射关系,主要有z轴(摄像机朝向)对应深度信息,xy对应xy
完成一个从三维控件到屏幕平面坐标的映射。
在该例子中也给出了明确的方案:
可以根据这个例子来学习UGUI更多知识!再放一遍链接:
Faking World Space for monster health bars in Unity