之前写回血之类的状态,用协程来做发现会有性能问题,虽然用起来很爽
干脆改成了一下,也可以用,再改改也可以用作技能之类的东西,希望对你有帮助
效果图
直接上代码
恢复基类
/// <summary>
/// 恢复基类
/// </summary>
public abstract class RecoverBase
{
[SerializeField]
private bool active = false;
[SerializeField]
private float rateMultiplier;
[SerializeField]
private float regenRate;
[SerializeField]
private bool isDone;
[SerializeField]
private bool regenerated;
[SerializeField]
private float regenWaitTime;
[SerializeField]
private float regenMaxValue;
/// <summary> 停止自动恢复 </summary>
public virtual bool Active { get => active; set => active = value; } /// <summary> 当前的恢复的值 </summary>
public Action<float> OnRegenValue { get; set; }
/// <summary> 当前恢复的百分比 </summary>
public Action<float> OnRegenValueNormalize { get; set; }
/// <summary> 是否恢复完成 </summary>
public Action<bool> OnIsDone { get; set; }
/// <summary> 当恢复值为空[假]/满[真]</summary>
public Action<bool> OnEmptyOrFull { get; set; }
public bool Regenerated { get => regenerated; set => regenerated = value; }//是否自动恢复
public float RegenRate { get => regenRate + (regenRate * rateMultiplier); set => regenRate = value; }//恢复率
public float RateMultiplier { get => rateMultiplier; set { rateMultiplier = Mathf.Clamp(value, 0, float.MaxValue); } }//恢复当前恢复速率的倍数
/// <summary> 当前恢复的值 </summary>
public float RegenMaxValue { get => regenMaxValue; set => regenMaxValue = value; }//恢复的最大值
public float RegenWaitTime { get => regenWaitTime; set => regenWaitTime = value; }//恢复等待时间
public virtual bool IsDone { get => isDone; set { isDone = value; OnIsDone?.Invoke(value); } } //是否恢复完成
/// <summary> 真:增加 假:扣减 </summary>
public abstract bool RegenType { get; set; }
public abstract float RegenValue { get; set; }//这里是抽象的原因不知道是扣减还是增加
/// <summary>
/// 恢复
/// </summary>
/// <param name="tick">delta time</param>
public abstract void UpdateRegenValue(float tick);//恢复的实现
}
实现
public static class Tools {//工具类
//判断有无到底持续时间
public static bool ElapsedTime(float StartTime, float intervalTime) => (Time.time - StartTime) >= intervalTime;
}
public enum StateType
{
Health = 1,//生命
Stamina = 2,//精力
Hungry = 3,//饥饿
}
[System.Serializable]
public class Status : RecoverBase
{
public StateType stateType;
[SerializeField]
private float regenValue;
[SerializeField]
private bool regenType;
public override bool IsDone
{
get => base.IsDone; set
{
base.IsDone = value;
inRegen = false;
}
}
public override bool RegenType { get => regenType; set => regenType = value; }
public override float RegenValue
{
get => regenValue; set
{
if (value < regenValue) inRegen = false;//这里只做增加时的判断,如果下次来的值小于上次的值,则为减少,意味着不再自动恢复了
regenValue = Mathf.Clamp(value, 0, RegenMaxValue);
OnRegenValue?.Invoke(regenValue);
OnRegenValueNormalize?.Invoke(regenValue / RegenMaxValue);
}
}
private float startTime;
[SerializeField]
private bool inRegen;//是否处于恢复中
public override void UpdateRegenValue(float tick)
{
if (!Regenerated || !Active) return;
if (RegenWaitTime > 0)
{
if (!inRegen)//不在恢复状态
{
if (!Tools.ElapsedTime(startTime, RegenWaitTime)) return; //如果没有达到固定时间
inRegen = true;//下一帧开始恢复
}
else
{
C_Regen(tick);
startTime = Time.time;
}
}
else
{
C_Regen(tick);
}
}
void C_Regen(float tick)
{
if (RegenType)
{
RegenValue += tick * RegenRate;
}
else
{
RegenValue -= tick * RegenRate;
}
if (RegenType)
{
if (RegenValue == RegenMaxValue)
{
IsDone = true;
OnEmptyOrFull?.Invoke(true);
}
}
else
{
if (RegenValue == 0)
{
IsDone = true;
OnEmptyOrFull?.Invoke(false);
}
}
}
}
脚本测试
public class ValueToString : MonoBehaviour
{
//这个脚本挂载text上,就可以看到数值的编号了
public Text txt;
private void Awake()
{
if (txt == null) txt = GetComponent<Text>();
}
public void FloatToString(float value) => txt.text = value.ToString("#0.00");
}
public class StatusTest : MonoBehaviour
{
public List<Status> stas = new List<Status>();
public Dropdown dpd_Type;
[Header("生命值")]
public Image heathl;
public Image stamina;
public Image hungry;
public Text heathlText;
public Text staminaText;
public Text hungryText;
private void Start()
{
foreach (var item in stas)
{
switch (item.stateType)
{
case StateType.Health:
item.OnRegenValueNormalize += HeathlAmount;
item.OnRegenValue += heathlText.GetComponent<ValueToString>().FloatToString;
break;
case StateType.Stamina:
item.OnRegenValueNormalize += StaminaAmount;
item.OnRegenValue += staminaText.GetComponent<ValueToString>().FloatToString;
break;
case StateType.Hungry:
item.OnRegenValueNormalize += HungryAmount;
item.OnRegenValue += hungryText.GetComponent<ValueToString>().FloatToString;
break;
}
item.OnRegenValue(item.RegenValue);
item.OnRegenValueNormalize(item.RegenValue/item.RegenMaxValue);
}
}
void HeathlAmount(float value) => heathl.fillAmount = value;
void StaminaAmount(float value) => stamina.fillAmount = value;
void HungryAmount(float value) => hungry.fillAmount = value;
private void Update()
{
foreach (var item in stas)
{
item.UpdateRegenValue(Time.deltaTime);
}
}
//按钮onclick调用,测试增加或者减少
public void DoStatusValue(int value)
{
var sta = stas.Find(a => a.stateType == (StateType)dpd_Type.value+1 );
if(sta != null)
{
sta.RegenValue += value;
}
}
}
编辑器挂的脚本
UI挂载