定时器

在 Unreal Engine 中,定时器用在指定延迟后执行某个操作,或者以固定的频率重复执行某个操作。

在不需要高频率实时的情况下,相比于在 Tick() 函数中每帧手动计算时间累加,使用定时器更加高效而且代码结构更加清晰。

在上一篇文章中我们已经实现了玩家的开火,在这篇文章中我们实现炮塔的开火。炮塔的开火是 "AI" 行为,需要我们编写逻辑控制。我们准备使用定时器实现,每隔一段时间检查玩家是否在开火范围内,如果在,就开火。

我们先看代码清单 1 和清单 2 的实现。

代码清单 1 Tower.h
  1. UCLASS()
  2. class TOONTANKS_API ATower : public ABasePawn
  3. {
  4.     GENERATED_BODY()
  5.    
  6. private:
  7.     ATank* Tank;
  8.  
  9.     UPROPERTY(EditDefaultsOnly, Category = "Combat")
  10.     float FireRange = 300.0f;
  11.  
  12.     FTimerHandle FireRateTimerHandle;
  13.     float FireRate = 2.0f;
  14.     void CheckFireCondition();
  15.  
  16.     bool InFireRange();
  17. };
代码清单 2 Tower.cpp
  1. // Called when the game starts or when spawned
  2. void ATower::BeginPlay()
  3. {
  4.     Super::BeginPlay();
  5.  
  6.     Tank = Cast<ATank>(UGameplayStatics::GetPlayerPawn(this, 0));
  7.  
  8.     GetWorldTimerManager().SetTimer(FireRateTimerHandle, this, &ATower::CheckFireCondition, FireRate, true);
  9. }
  10.  
  11. void ATower::CheckFireCondition()
  12. {
  13.     if (InFireRange())
  14.     {
  15.         Fire();
  16.     }
  17. }
  18.  
  19. bool ATower::InFireRange()
  20. {
  21.     if (Tank)
  22.     {
  23.         float Distance = FVector::Dist(GetActorLocation(), Tank->GetActorLocation());
  24.         return (Distance <= FireRange);
  25.     }
  26.     return false;
  27. }

定时器系统由全局的 FTimerManager 管理,可以通过 GetWorld()->GetTimerManager() 访问到它。

FTimerHandle 是一个轻量级的结构体,充当定时器的唯一标识符。我们需要保存这个句柄,以便之后暂停、恢复或取消这个定时器。

我们可以使用 SetTimer() 函数,让定时器定时执行指定的函数。它的一个重载版本如下:

  • template< class UserClass >
  • FORCEINLINE void SetTimer(
  •     FTimerHandle& InOutHandle,
  •     UserClass* InObj,
  •     typename FTimerDelegate::TMethodPtr< UserClass > InTimerMethod,
  •     float InRate,
  •     bool InbLoop = false,
  •     float InFirstDelay = -1.f);

其中,InOutHandle 参数是引用传递,用于存储新创建定时器的唯一 ID。

InObj 参数是回调函数的对象指针,此处我们传递 this

InTimerMethod 参数指定回调函数的成员函数指针。

InRate 参数指定定时器触发的时间间隔。

InbLoop 参数指定是否循环触发。

InFirstDelay 参数指定第一次触发等待的时间。默认值 -1,表示等待时间为 InRate。