蓝图接口:解耦第一步

先看不加接口的典型混乱:

玩家走进一个机关,机关要通知"附近的敌人"进入警戒。最直觉的写法:机关蓝图里 Cast 到 BP_Enemy,调用其 EnterAlert()。然后策划做了第二种敌人 BP_FlyingEnemy……Cast 失败,敌人没反应,bug 出现。

问题的根源是机关"认识"了具体的敌人类型。蓝图接口(Blueprint Interface)就是来切断这种认识的。

用法

  1. 新建 Blueprint Interface(如 BPI_EnemyReaction),里面声明函数 EnterAlert(FName Reason);
  2. 敌人蓝图"实现"这个接口(Class Settings → Interfaces 添加);
  3. 机关蓝图只持有一个 Actor 引用,调用 EnterAlert——不需要知道对方是什么具体类型。
机关蓝图                     BPI_EnemyReaction
   │ (只持有 Actor* 引用)          ▲
   └── Call EnterAlert ──────────┤ 实现
                          BP_Enemy / BP_FlyingEnemy / ...

这一步的价值是:以后再加 100 种敌人,机关蓝图一个字都不用改。

C++ 侧的接口

C++ 里用 UINTERFACE 实现,蓝图同样可用:

UINTERFACE(BlueprintType)
class UEnemyReaction : public UInterface
{
    GENERATED_BODY()
};

class IEnemyReaction
{
    GENERATED_BODY()
public:
    // 蓝图可实现的接口函数
    UFUNCTION(BlueprintNativeEvent)
    void EnterAlert(FName Reason);
};

C++ 调用时:

if (IEnemyReaction* React = Cast<IEnemyReaction>(TargetActor))
{
    React->EnterAlert_Implementation(TEXT("Noise"));   // 带默认实现的调用方式
}

接口 vs Cast 的取舍

Cast 到具体类 蓝图接口
耦合 认识具体类型 只认识"能力"
扩展新类型 每种都要改调用方 实现接口即可
性能 Cast 本身有开销 接口调用极快
适用 自己项目内部、类型封闭 跨系统、可扩展

经验:只要"调用方不该知道被调方具体类型",就用接口。角色对敌人、机关对可触发物、UI 对数据源,都属此类。

接口函数应当是"行为"而非"查询"

接口定义的是"你能做什么",不是"你叫什么"。好的接口函数名:EnterAlert、BeInteracted、Highlight;坏的:GetEnemyComponent(泄露内部结构)。

本章小结

  • 接口切断"调用方认识具体类型"的耦合,是蓝图通信解耦的第一步。
  • C++ 用 UINTERFACE/IInterface,蓝图用 Blueprint Interface 资产,两层可互通。
  • 凡是"不该知道对方是谁"的调用都该走接口;扩展新类型时调用方零修改。