• 基于Unity开发的血条(Health Bar)的预制设计


    简易血条预制设计

    作业要求

    血条(Health Bar)的预制设计。具体要求如下

    • 分别使用 IMGUI 和 UGUI 实现
    • 使用 UGUI,血条是游戏对象的一个子元素,任何时候需要面对主摄像机
    • 分析两种实现的优缺点
    • 给出预制的使用方法

    项目文档 - Health Bar

    在这里插入图片描述

    一、IMGUI实现

    1.1 IMGUI血条效果

    在这里插入图片描述

    1.2 IMGUI代码实现

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class HealthBar : MonoBehaviour
    {
    
        public float healthUpperLimit;  // 生命值上限
        private float healthValue;		// 当前的生命值
    
        public bool restart;			// 按R键让血量恢复原状
    
        void Start() {
            healthUpperLimit = 4000.0F;
            healthValue = healthUpperLimit;
            restart = false;
        }
    
        void Update() {
            if(restart){	// 恢复原状
                healthUpperLimit = 4000.0F;
                healthValue = healthUpperLimit;
                restart = false;
            }
        }
    
        public void Hurt(float h) { // 造成 h 点伤害
            healthValue -= h;
            if(healthValue <= 0){
                healthValue = 0;
            }
        }
    
        public void Heal(float h) { // 治疗 h 点
            if(healthValue > 0){
                healthValue += h;
                if(healthValue >= healthUpperLimit) {
                    healthValue = healthUpperLimit;
                }
            }
        }
    
        void OnGUI() {
    
            GUIStyle healthTextStyle = new GUIStyle();
            healthTextStyle.fontSize = 20;
            healthTextStyle.alignment = TextAnchor.MiddleCenter;
            
            if(healthValue < healthUpperLimit * 0.3) {
                GUI.color = Color.red;		// 当血量少于上限的30%时,血条为红色
            }
            else if(healthValue < healthUpperLimit * 0.6) {
                GUI.color = Color.yellow;	// 当血量少于上限的60%时,血条为黄色
            }
            else {
                GUI.color = Color.green;	// “健康状况下”,血条为绿色
            }
            
            // 用横向滚动条实现血条
            GUI.HorizontalScrollbar(new Rect(30, 30, Screen.width - 60, 30), 0.0F, healthValue, 0.0F, healthUpperLimit);
            // 显示当前血量
            GUI.Label(new Rect(30, 50, Screen.width - 60, 20), healthValue.ToString() + " / " + healthUpperLimit.ToString(), healthTextStyle);
            
        }
    }
    
    • 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
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    1.3 IMGUI配置方法

    • 配置方法非常简单,只需将代码脚本挂载到一个空的游戏对象上即可。
      在这里插入图片描述

    二、UGUI实现

    2.1 UGUI血条效果

    在这里插入图片描述

    2.2 UGUI代码实现

    UGUI代码:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class HealthBar2 : MonoBehaviour
    {
        public Slider slider; // 血条UGUI对象
    
        public bool restart;
    
        void Start() {
            slider.maxValue = 4000.0F; 		// 血条对象血量上限
            slider.minValue = 0F;			// 血条对象血量下限
            slider.value = slider.maxValue; // 当前血量
            restart = false;
        }
    
        void Update() {
    
            // 面向摄像机,此时血条会发生抖动
            // slider.direction = Slider.Direction.RightToLeft;
            // slider.transform.LookAt(Camera.main.transform.position);
    
            // 不是面向摄像机,而是面向游戏屏幕
            slider.direction = Slider.Direction.LeftToRight;
            slider.transform.rotation = Camera.main.transform.rotation;
            
    
            if(restart){ // 重启
                slider.maxValue = 4000.0F;
                slider.value = slider.maxValue;
                restart = false;
            }
    
            if(slider.value <= 0.3 * slider.maxValue) // 当血量少于上限的30%时,血条为红色
                slider.fillRect.transform.GetComponent().color = Color.red;
            else if(slider.value <= 0.6 * slider.maxValue) // 当血量少于上限的60%时,血条为黄色
                slider.fillRect.transform.GetComponent().color = Color.yellow;        
            else // “健康情况”下,血条为绿色
                slider.fillRect.transform.GetComponent().color = Color.green;
        }
    
        public void Hurt(float h) { //造成h点伤害
            slider.value -= h;
            if(slider.value <= 0)
                slider.value = 0;
        }
        public void Heal(float h) { // 给予h点治疗
            if(slider.value > 0){
                slider.value += h;
                if(slider.value >= slider.maxValue)
                    slider.value = slider.maxValue;            
            }
        }
    }
    
    • 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
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    其他控制代码

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public interface IUserAction {
        void Restart();
        void Hurt();
        void Heal();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class FirstController : MonoBehaviour, IUserAction
    {
        public HealthBar healthBar;
        public HealthBar2 healthBar2; // UGUI血条对象
    
        public float hurt = 250F;
        public float heal = 1000F;
    
        void Start() {
            gameObject.AddComponent();
            healthBar = Singleton.Instance;
        }
    
        void Update() {
            if(Input.GetKeyDown("f"))
                Hurt();
            if(Input.GetKeyDown("h"))
                Heal();
            if(Input.GetKeyDown("r"))
                Restart();
        }
    
        public void Hurt() {
            healthBar.Hurt(hurt);
            healthBar2.Hurt(hurt);
        }
    
        public void Heal() {
            healthBar.Heal(heal);
            healthBar2.Heal(heal);
        }
    
        public void Restart() {
            healthBar.restart = true;
            healthBar2.restart = true;
        }
    }
    
    
    • 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
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class Singleton : MonoBehaviour where T : MonoBehaviour
    {
    	protected static T instance;
    
    	public static T Instance {  
    		get {  
    			if (instance == null) { 
    				instance = (T)FindObjectOfType (typeof(T));  
    				if (instance == null) {  
    					Debug.LogError ("An instance of " + typeof(T) + " is needed in the scene, but there is none.");  
    				}  
    			}  
    			return instance;  
    		}  
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    2.3 镜头跟随的设计

    在设计中,如果血条对象始终面向摄像机,此时血条会发生抖动,代码如下:

    slider.direction = Slider.Direction.RightToLeft;
    slider.transform.LookAt(Camera.main.transform.position);
    
    • 1
    • 2

    实际上,血条对象不应该面向摄像机,而是面向游戏屏幕,这样才不会发生抖动。在下面代码中,如果下面设置血条 rotaion 与摄像机 rotation 一致,血条回翻转,我们看到的是血条的背面,所以血条变化应该自左向右。

    slider.direction = Slider.Direction.LeftToRight; 
    slider.transform.rotation = Camera.main.transform.rotation;
    
    • 1
    • 2

    不同的效果如下图所示:

    面向摄像头面向屏幕
    在这里插入图片描述

    2.3 UGUI配置方法

    • 创建空对象并挂在脚本 FirstController

    • 创建一个Cube作为Boss(目的是让UGUI血条成为它的子对象),可以为Cube加上一个动画(CubeMove)模拟Boss的移动,同时设置一下摄像头的位置。

      CubeMain Camera

    在这里插入图片描述
    在这里插入图片描述

    • 为Cube对象上添加一个UI对象 - Slider,改名为 HealthBarSlider。

    • 设置 Canvas 的属性:包括Render Mode、Event Camera、Rect Transform(不设置 RenderMode 为 World Space 模式则 Rect Transform 无法修改)

    在这里插入图片描述

    • 修改 HealthBarSlider 的子对象 BackgroundFillArea,这样可以让 Slider 充满整个 Background。而子对象 Handle Slider Area 用不到,取消勾选它。

      BackgroundFillArea

    在这里插入图片描述

    • 将脚本 HearthBar2 挂载到 Canvas,设置Slider对象。同时,去设置空对象的 FirstController 脚本的 Health Bar 属性为 Canvas

    在这里插入图片描述

    • 运行程序。

    三、优缺点分析

    IMGUI

    • 优点:

      • 只需要简短的代码就可以实现简单的血条,容易上手。
    • 缺点:

      • 样式比较单调,不能通过交互界面设计血条,布局比较麻烦。

      • 每一帧都需要重算布局重新渲染UI组件,性能较低。

    UGUI

    • 优点:

      • 有交互界面可以设计血条,可以设计风格各异的组件。
    • 缺点:

      • 上手比较困难,学习成本比较高。
  • 相关阅读:
    TiDB Lightning 并行导入
    pat倒数3天
    python进阶系列 - 13讲 生成器generator
    python---socket套接字,粘包问题
    Aigtek高精度电流源仪器设计规范
    C++面试记录之中望软件
    python+vue+elementui舞蹈教学视频评分系统_o4o1y
    ortp 交叉编译
    智能别墅烟雾和粉尘感应报警系统的设计(任务书+开题+lunwen+翻译及原文+附录程序)
    Codeforces Round 953 (Div. 2) A - C 题解
  • 原文地址:https://blog.csdn.net/newlw/article/details/126783580