蓝图接口:解耦第一步
先看不加接口的典型混乱:
玩家走进一个机关,机关要通知"附近的敌人"进入警戒。最直觉的写法:机关蓝图里 Cast 到
BP_Enemy,调用其EnterAlert()。然后策划做了第二种敌人BP_FlyingEnemy……Cast 失败,敌人没反应,bug 出现。
问题的根源是机关"认识"了具体的敌人类型。蓝图接口(Blueprint Interface)就是来切断这种认识的。
用法
- 新建 Blueprint Interface(如
BPI_EnemyReaction),里面声明函数EnterAlert(FName Reason); - 敌人蓝图"实现"这个接口(Class Settings → Interfaces 添加);
- 机关蓝图只持有一个 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 资产,两层可互通。 - 凡是"不该知道对方是谁"的调用都该走接口;扩展新类型时调用方零修改。
