游戏 UI 观察者模式

FINCTIVE 2019-10

前言

参考:

本文为示例游戏项目 FINCTIVE/lost-in-the-wilderness-nightmare 开发笔记系列文章之一:

应用场景

假如有一天,你在一个游戏项目中实现了一个角色控制器。这个控制器相对复杂,于是你想新开一个空场景来单独测试这个控制器脚本。你发现在新场景中,游戏角色对象缺乏相关UI对象的引用,导致程序无法测试。

public Slider hpSlider; // 举个例子,角色HP的血条
void GetDamage()
{
  	// ...处理受伤代码...
  	// 更新相应UI
	hpSlider.value = newValue; // 在新场景中导致空引用
}

解决方案

使用C#委托和事件来建立hp更新和UI更新的联系。 在管理玩家属性的脚本中(本例中是PlayerInfo.cs)

public event Action OnPlayerHpChange;
public int hp
{
    get => _hp;
    set
    {
        _hp = value;
        if (OnPlayerHpChange != null)
            OnPlayerHpChange(_hp);
    }
}

在控制UI更新行为的脚本中(本例是PlayerHpUI.cs)

void Start()
{
    // 通过全局变量获取player示例中的playerInfo对象(与上一个代码示例对应)
    PlayerController.player.playerInfo.OnPlayerHpChange += _OnPlayerHpChange; 
}

private void OnPlayerHpChange(int hp)
{
    hpSlider.value = (float)hp / 100f;
}

在本例中Player控制器部分代码与UI更新代码分离开了,实际工程项目中会出现更复杂的情况;本文例子是“一对一”的情况,实际工程中有可能会出现“一对多”甚至“多对多”的情况。

更经典的应用场景是游戏成就系统:游戏成就千奇百怪,把判定游戏成就的代码耦合到其他游戏系统中不是一个明智的做法。