依赖注入

依赖注入的概念为,不让一个对象自己创建或自己寻找它依赖的东西,而是让外部直接告诉它。

依赖注入这个名字听着很高级,但是我们在平时写代码时肯定都用过。比如形式为 SetXXX 的函数就是最常见的依赖注入方式,它通过 Set 函数设置依赖。另一种常见的方式是在构造函数这个阶段传递依赖项。

在本篇文章中,我们需要 Box 组件(Trigger)和移动组件(Mover)进行“交互”:Box 组件检测到重叠之后,通过移动组件移动对象。

触发对象移动的功能已经实现,有些久远,可以看 《实现移动组件功能》 回顾。

在移动组件中,我们通过设置 ShouldMove 变量来触发所在的 Actor 移动。原来的 ShouldMove 是在编辑器里勾选设置的,现在如代码清单 1 所示,我们去掉 UPROPERTY 宏,并通过添加 SetShouldMove() 接口来设置。

代码清单 1 设置移动
  1. UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
  2. class CRYPTRAIDER_API UMover : public UActorComponent
  3. {
  4.     GENERATED_BODY()
  5.  
  6. public:
  7.     void SetShouldMove(bool NewShouldMove);
  8.  
  9. private:
  10.     // Checkbox to toggle movement
  11.     bool ShouldMove = false;
  12. };

接着我们来到 Box 组件的代码所在。如代码清单 2 所示,我们添加 SetMover() 函数设置移动组件,并保存在 Mover 变量中。这就是文章开头所说的依赖注入。

注意此处的 UFUNCTION() 宏。SetMover 需要在蓝图里调用,因为移动组件是在编辑器里添加创建的。

代码清单 2 依赖注入
  1. UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent))
  2. class CRYPTRAIDER_API UTriggerComponent : public UBoxComponent
  3. {
  4.     GENERATED_BODY()
  5.  
  6. public:
  7.     UFUNCTION(BlueprintCallable)
  8.     void SetMover(UMover* NewMover);
  9.  
  10. private:
  11.     UMover* Mover = NULL;
  12. };

如代码清单 3 所示,我们在 Box 组件的检测逻辑之后继续完善功能。当检测到有对象重叠时,我们就调用移动组件的函数,让其触发移动。

代码清单 3 逻辑实现
  1. // Called every frame
  2. void UTriggerComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
  3. {
  4.     Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
  5.  
  6.     AActor* Actor = GetAcceptableActor();
  7.     if (Actor != NULL)
  8.     {
  9.         UE_LOG(LogTemp, Display, TEXT("Unlocking"));
  10.         if (Mover != NULL)
  11.             Mover->SetShouldMove(true);
  12.     }
  13.     else
  14.     {
  15.         if (Mover != NULL)
  16.             Mover->SetShouldMove(false);
  17.     }
  18. }

最后我们来到门资产的对应蓝图里。如图 1 所示,我们在 BeginPlay 时调用 Box 组件的 SetMover 接口。传递的移动组件就是当下资产下附加的名为 Mover 的移动组件对象。

图1 蓝图

运行的效果如下方视频所示。可以看到存在一点小问题,Box 组件没有覆盖门内部上面的拱形,所以重叠事件到上方就停止了,导致门没有继续下降。