这阵子项目中需要用到一种特殊样式的血条。描述如下:
1. 正常颜色为红色。受到伤害后,即将扣除的血量变暗(暗红色),并有下降动画效果;
2. 加护盾效果后,增加一部分血量值,该额外部分为白色,护盾效果消失后该部分血量瞬间消失;
3. 在护盾效果下受到伤害时,首先扣除白色血量。白色血量不足扣除时,余下部分从红色血量中扣除;
4. 白色血量的扣除效果为变为灰色并有下降动画效果;
4. 当加护盾效果时,若即将添加的白色血量将使总血条“溢出”,从新计算百分比并排满血条;
5. 中毒时,将相应的血量(按照伤害扣血优先级,即先扣除护盾,再扣除正常)变为紫色。该紫色血量有递减动画;
6. 中毒时若受到伤害,不扣除紫色部分血量(实际上该部分已扣除,但有个缓冲时间),而是红色或白色部分;
7. 若中毒时受到护盾效果?
8. 血条会自动隐藏,血量产生变化时会自动显示;
制作普通血条时,我们一般会用UISlider。
但是这里涉及到护盾和中毒的效果,用UISlider显然是不够的。我首先想到的是用多个血条叠加在一起,分辨为正常血条、中毒血条、护盾血条。但是掉血效果要怎么解决?
如果只是有下降动画,那很好解决,可是会先变暗,这显然是一个slider做不到的。
于是我灵机一动想到了:一个血条,多个UISlider!我们可以写一个自定义血条,该血条包含正常血量、中毒值、护盾值,以及相应的状态属性。
经过实践,果然我的想法是对的。先来看下效果图:
1.掉血效果
2.加护盾
2.1 加护盾时掉血
3. 中毒
复杂的叠加效果我们稍后再讨论。第一步,先完成UI上的结构设计:
1. Heathbar为金色的边框(UISprite)
2. Blank为底色(灰)(UISprite)
3. ShieldedDmg为加护盾时的减血底色(深灰色)(UISprite, UISlider)
4. Shielded为护盾颜色(白色)(UISprite, UISlider)
5. Poisoned为中毒颜色(紫色)(UISprite, UISlider)
6. NormalDmg为正常情况下的减血底色(暗红色)(UISprite, UISlider)
7. Normal为正常血条的颜色(红色)(UISprite, UISlider)
8. thumb为血条末端的小刻度(白色)(UISprite),并设置Normal上Slider的Thumb为它
如此,我们就完成了初步的UI设计。数一下,一共有5个Slider。我们再添加一个名为UIHealthbar自定义脚本,用来管理这些UISlider的数值变化,以及处理相关逻辑。
将UIHealthbar绑到Heathbar上。初步脚本如下:
1 using System; 2 using UnityEngine; 3 4 public class UIHealthbar : MonoBehaviour 5 { 6 #region 7 8 private UISlider _normal; 9 private UISlider _normalDmg; 10 private UISlider _shielded; 11 private UISlider _shieldedDmg; 12 private UISlider _poisoned; 13 private UISprite _barSprite; 14 15 #endregion 16 17 18 /// <summary> 19 /// 全局动画时长 20 /// </summary> 21 private const float AnimDuration = 0.2f; 22 23 /// <summary> 24 /// 渐变类型 25 /// </summary> 26 private const iTween.EaseType EaseType = iTween.EaseType.linear; 27 28 /// <summary> 29 /// 是否正在隐藏或显示(但如或淡出) 30 /// </summary> 31 private bool _isFading; 32 33 /// <summary> 34 /// 用来判断自动隐藏的计时器 35 /// </summary> 36 private float _timer; 37 38 /// <summary> 39 /// 是否自动隐藏 40 /// </summary> 41 public bool autoHide = true; 42 43 /// <summary> 44 /// 是否受到正常伤害 45 /// </summary> 46 private bool IsNormalDamaging 47 { 48 get { return _normalDmg.gameObject.activeSelf; } 49 set { _normalDmg.gameObject.SetActive(value); } 50 } 51 52 /// <summary> 53 /// 是否在加护盾的情况下受到伤害 54 /// </summary> 55 private bool IsShieldedDamaging 56 { 57 get { return _shieldedDmg.gameObject.activeSelf; } 58 set { _shieldedDmg.gameObject.SetActive(value); } 59 } 60 61 /// <summary> 62 /// 是否正在掉血 63 /// </summary> 64 public bool IsDamaging 65 { 66 get { return IsShieldedDamaging || IsNormalDamaging; } 67 } 68 69 /// <summary> 70 /// 是否中毒 71 /// </summary> 72 public bool IsPoisoned 73 { 74 get { return _poisoned.gameObject.activeSelf; } 75 private set { _poisoned.gameObject.SetActive(value); } 76 } 77 78 /// <summary> 79 /// 是否受护盾 80 /// </summary> 81 public bool IsShielded 82 { 83 get { return _shielded.gameObject.activeSelf; } 84 private set { _shielded.gameObject.SetActive(value); } 85 } 86 87 /// <summary> 88 /// 是否可见(自动隐藏相关隐藏) 89 /// </summary> 90 private bool IsVisible 91 { 92 get 93 { 94 throw 95 new NotImplementedException(); 96 } 97 set 98 { 99 100 } 101 } 102 103 private void OnEnable() 104 { 105 IsPoisoned = false; 106 IsShielded = false; 107 IsShieldedDamaging = false; 108 IsNormalDamaging = false; 109 } 110 111 private void Awake() 112 { 113 _normal = transform.FindChild("Normal").GetComponent<UISlider>(); 114 _normalDmg = transform.FindChild("NormalDmg").GetComponent<UISlider>(); 115 _shielded = transform.FindChild("Shielded").GetComponent<UISlider>(); 116 _shieldedDmg = transform.FindChild("ShieldedDmg").GetComponent<UISlider>(); 117 _poisoned = transform.FindChild("Poisoned").GetComponent<UISlider>(); 118 _barSprite = transform.GetComponent<UISprite>(); 119 } 120 121 #region 逻辑处理 122 123 /// <summary> 124 /// 加伤害 125 /// </summary> 126 /// <param name="percent">将造成的伤害百分比(小于1)</param> 127 /// <returns>剩余血量百分比</returns> 128 public float AddDamage(float percent) 129 { 130 return 0; 131 } 132 133 /// <summary> 134 /// 加中毒值 135 /// </summary> 136 /// <param name="percent">百分比</param> 137 /// <param name="speed">下降速度(刻度/秒)</param> 138 public void AddPoison(float percent, float speed) 139 { 140 } 141 142 /// <summary> 143 /// 加护盾值 144 /// </summary> 145 /// <param name="percent">百分比</param> 146 /// <param name="time">持续时间(秒)</param> 147 public void AddShield(float percent, float time) 148 { 149 } 150 151 #endregion 152 }