C++ 委托与蓝图事件的配合

把上两页的内容放进一个真实流程里看:"玩家被攻击 → 扣血 → UI 更新 → 判定死亡"。

分层实现

// C++:血量组件(只管规则与广播)
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class UHealthComponent : public UActorComponent
{
    GENERATED_BODY()
public:
    DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnHealthChanged, float, NewHealth);

    UPROPERTY(BlueprintAssignable, Category="Health")
    FOnHealthChanged OnHealthChanged;

    UFUNCTION(BlueprintCallable, Category="Health")
    void ApplyDamage(float Amount);
};

void UHealthComponent::ApplyDamage(float Amount)
{
    CurrentHealth = FMath::Clamp(CurrentHealth - Amount, 0.f, MaxHealth);
    OnHealthChanged.Broadcast(CurrentHealth);   // ← 广播给蓝图
    if (CurrentHealth <= 0.f) OnDeath.Broadcast();  // 死亡广播
}
蓝图(角色 BP_PlayerCharacter):
  Event OnHealthChanged (NewHealth)
     → 设置 UMG 血条 Widget 的百分比
     → 屏幕边缘红色受击特效(Delay 0.2s 后隐藏)

蓝图(UI 控制器):
  Event OnDeath → 播放死亡蒙太奇、弹出结算面板

规则在 C++(血量计算不可绕过),表现在蓝图(UI、特效、动画随策划调)。这就是混合开发的教科书形态。

蓝图订阅 vs 蓝图实现事件的区别

新人容易混的两个概念:

蓝图事件(BlueprintNativeEvent 等) 订阅广播(Bind Event)
触发者 C++ 直接调用"这个对象的方法" C++ 广播,任何订阅者都能收
关系 一对一(父子类覆盖) 一对多
典型 OnDeath() 这种"对象自己的行为" OnHealthChanged 这种"对外通知"

口诀:"对象自己的行为"用可重载事件;"对外通知"用广播。

注意:绑定的时机

蓝图在 Event BeginPlay 时绑定广播是常见做法,但如果广播发生在 BeginPlay 之前(如 C++ 构造函数里),订阅者会错过。解决方案:把首次"同步状态"单独做一次——订阅后主动调一次 Update 函数,而不是指望广播补发。

本章小结

  • 典型分层:C++ 组件管规则 + 广播事件;蓝图层订阅并表现。
  • 可重载事件用于"对象自身行为",广播用于"对外通知",两者各司其职。
  • 绑定时机问题:订阅后主动同步一次状态,别依赖广播补发。