实战:角色与武器的通信架构

把本章四种手段放进一个具体系统里。

需求

  • 武器可拾取、装备、攻击;
  • 武器攻击命中敌人 → 敌人扣血;
  • UI 要显示当前武器与弹药;
  • 换武器要有表现(动画、音效)。

架构设计

C++ 层
  UWeaponComponent(角色持有)     —— 拥有当前武器、管理装备流程
  AWeaponBase(Actor)             —— 武器基类,含 USkeletalMeshComponent
  BPI_Damageable(接口)           —— 可受伤者的统一契约
  UHealthComponent(血量组件)     —— 规则与 OnHealthChanged 广播(上页已写)

蓝图层
  BP_Weapon_Sword、BP_Weapon_Bow   —— 继承 AWeaponBase,各自表现
  WBP_WeaponHUD                    —— 订阅 OnWeaponChanged 刷新显示

三个关键通信点

① 角色通知 UI"换武器了"(一对多 → 广播)

// UWeaponComponent
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnWeaponChanged, AWeaponBase*, NewWeapon);
UPROPERTY(BlueprintAssignable) FOnWeaponChanged OnWeaponChanged;

void UWeaponComponent::Equip(AWeaponBase* W)
{
    if (CurrentWeapon) CurrentWeapon->OnUnequip();   // 接口/事件:旧武器收起
    CurrentWeapon = W;
    CurrentWeapon->OnEquip();                        // 新武器装备表现
    OnWeaponChanged.Broadcast(W);                    // 通知 UI
}

② 武器命中敌人(不认识具体敌人 → 接口)

// AWeaponBase::OnHit 里
if (IDamageable* D = Cast<IDamageable>(HitActor))
{
    FDamageInfo Info; Info.Amount = Damage; Info.Instigator = GetOwner();
    D->ApplyDamage_Implementation(Info);   // 走接口,不知对方是小怪还是Boss
}

③ 敌人扣血通知 UI(上页已有:HealthComponent 广播)

为什么这样分层

  • 武器不知道"敌人是谁" → 接口,加新敌人无成本;
  • UI 不知道"武器怎么换" → 广播订阅,UI 换皮不动武器逻辑;
  • 规则全部在 C++(扣血、装备状态机)→ 性能与正确性有保障;
  • 表现全在蓝图(蒙太奇、音效、UI 动画)→ 美术策划自己迭代。

常见演进:网络化后怎么办?

单机版架构做好后,要加多人:ApplyDamage 变成 Server RPC + OnHealthChanged 广播加 Replicated 回调。多数架构改动集中在 C++ 层,蓝图表现层几乎不用动——这就是分层带来的可维护性。

本章小结

  • 实战架构原则:规则在 C++、表现走接口与广播、UI 只订阅不决策。
  • 角色↔武器↔敌人↔UI 四段通信,分别对应组合/接口/广播三种手段。
  • 分层做好后,网络化等大改动集中在 C++ 层,蓝图层稳定不动。