Unity引擎2D游戏开发,血量更新逻辑的实现

发布时间 2023-12-29 17:12:44作者: 心霖の雨

思路

image
能够发现Fill Amount就是控制血量条长度的控件,它是一个百分比值,则可以通过当前血量除以最大血量得到当前血量的百分比。那么,也就能控制血量条的长度了。

编写基本的更新逻辑

创建C#文件
image

将C#文件挂载到Player State Bar
image

在C#文件中调用UI组件前,需要调用UI组件库

using UnityEngine.UI;

在PlayerStateBar C#文件中,创建三个全局变量,分别代表绿色血条、红色血条和精力条

// 绿色血条
public Image healthImage;
// 红色血条
public Image healthDelayImage;
// 精力条
public Image powerImage;

Hierarchy中拖动Image到各自的位置
image

在PlayerStateBar中创建OnHealthChange()方法,用于处理血量变更时执行的代码

/// <summary>
/// 接受Health的变更百分比
/// </summary>
/// <param name="percentage">百分比:current / Max</param>
public void OnHealthChange(float percentage)
{
    healthImage.fillAmount = percentage;
}

创建关于血量的ScriptableObject事件

这时候就需要从Player的Character中传递血量数据到此处,那么怎么样才能安全的完整的跨物体甚至跨场景来传递数值呢?
image

这时候需要利用ScriptableObject进行传递,它是一个持久化存储在项目中的资产文件类型,例如
image

后缀名为.Asset

在Scripts下创建ScriptableObject文件夹,并创建CharacterEventSO。因为是利用ScriptableObject来创建事件,因此以EventSO结尾
image

打开CharacterEventSO C#文件,继承ScriptableObject

public class CharacterEventSO : ScriptableObject
{
}

在上面写上描述用以生成ScriptableObject资产文件

[CreateAssetMenu(fileName = "Event/CharacterEventSO")]
public class CharacterEventSO : ScriptableObject
{
}

这样就能在Project窗口中添加此资产文件
image

创建一个UnityAction的全局变量,用于传递Character数据

// 只传递Character数据
public UnityAction<Character> OnEventRised;

创建RaiseEvent()事件启动方法

/// <summary>
/// 启动事件
/// </summary>
/// <param name="character">谁想启动这个事件,就把自己的Character传递进去</param>
public void RaiseEvent(Character character)
{
    OnEventRised?.Invoke(character);
}

在Assets中创建Events文件夹,在内部创建SriptableObject事件
image

接下来,在Character代码脚本当中,只要血量发生变化就调用EventSO,把当前血量传递过去

用Unity Event进行广播,则在Character C#脚本中,添加如下全局变量

public UnityEvent<Character> OnHealthChange;

然后在Player的Character中,将上述的ScriptableObject Event拖入,并选择RaiseEvent()方法。从而,当人物血量有了变化,即可广播出去。
image

接下来,Player State Bar来监听,因为要使血条栏变少

监听ScriptableObject事件

在Hierarchy中,创建一个GameObject,用于监听所有关于UI的事件
image

在Scripts下,创建一个UIManager的C#脚本
image

绑定到UI Manager
image

C#代码中,创建一个CharacterEventSO的全局变量

public class UIManager : MonoBehaviour
{
    [Header("事件监听")]
    public CharacterEventSO healthEvent;

}

在UI Manager中,绑定Character Event SO的Event文件
image

此时,就能够成功监听Character Event SO的Event文件,利用了Character Event SO的Event文件进行中间件传递了一些数据

继续编写血条更新逻辑

在UIManager C#脚本中,创建OnEnable()方法和OnDisable()方法。并在内部添加OnHealthEvent事件进行监听

private void OnEnable()
{
    healthEvent.OnEventRised += OnHealthEvent;
}

private void OnDisable()
{
    healthEvent.OnEventRised -= OnHealthEvent;
}

OnEnable()即启动事件方法,OnDisable()为关闭事件方法,两者均为固定方法

由于需要对血条栏进行控制,所以添加状态栏的全局变量

public PlayerStateBar playerStateBar;

然后创建OnHealthEvent()方法,在内部对血条进行计算,并赋予给playerStateBar的OnHealthChange()方法

private void OnHealthEvent(Character character)
{
    var percentage = character.currentHealth / character.maxHealth;
    playerStateBar.OnHealthChange(percentage);
}

打开Hierarchy,选中UI Manager,将对应的组件拖入
image

打开Character,虽然创建了OnHealthChange变量,但是并没有对其进行调用。那么就需要在受伤时和初始化时进行调用

public void TakeDamage(Attack attacker)
{
    if (invulnerable)
    {
        return;
    }
    if (currentHealth - attacker.damage > 0) 
    {
        currentHealth -= attacker.damage;
        TriggerInvulnerable();
        // 执行受伤
        OnTakeDamage?.Invoke(attacker.transform);
    } else
    {
        currentHealth = 0;
        // 触发死亡
        onDie?.Invoke();
    }
    // 进行血条的扣除
    OnHealthChange?.Invoke(this);
}
private void Start()
{
    currentHealth = maxHealth;
    OnHealthChange?.Invoke(this);
}

红色血条的扣除

打开PlayerStateBar脚本,由于healthDelayImage要跟随healthImage变化,所以在Update()中进行

判断红色血条是否大于绿色血条的值,如果大于,则扣除时间的修正进行变化

private void Update()
{
    if (healthDelayImage.fillAmount > healthImage.fillAmount)
    {
        healthDelayImage.fillAmount -= Time.deltaTime;
    }
}