在UE中有專門的類用來完成定時器的功能,它就是FTimerHandle類。
我們來完成一個例子,每隔一段時間之後,讓一個ACTOR自我複制,在一定範圍内随機生成。
這是ACTOR的頭檔案:
1 // Fill out your copyright notice in the Description page of Project Settings.
2
3 #pragma once
4
5 #include "CoreMinimal.h"
6 #include "GameFramework/Actor.h"
7 #include "CollisionActor.generated.h"
8
9 UCLASS()
10 class MYPROJECT6_API ACollisionActor : public AActor
11 {
12 GENERATED_BODY()
13
14 public:
15 // Sets default values for this actor's properties
16 ACollisionActor();
17
18 public:
19 UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Properties")
20 class UStaticMeshComponent* myStaticMesh;
21
22 FORCEINLINE UStaticMeshComponent* GetmyStaticMesh() {
23 return myStaticMesh;
24 }
25
26
27 UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Properties")
28 class USphereComponent* myCollision;
29
30 private:
31 FScriptDelegate startsOverlap;
32 FScriptDelegate endsOverlap;
33 public:
34 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Properties")
35 bool status;
36 public:
37 UFUNCTION(BlueprintCallable,Category = "FUNCTIONS")
38 void onOverlap();
39 UFUNCTION(BlueprintCallable, Category = "FUNCTIONS")
40 void endOverlap();
41
42 protected:
43 // Called when the game starts or when spawned
44 virtual void BeginPlay() override;
45
46 public:
47 // Called every frame
48 virtual void Tick(float DeltaTime) override;
49
50
51 public:
52 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Properties")
53 FTimerHandle StarTimer;
54
55 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Properties")
56 FTimerHandle EndTimer;
57
58 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Properties")
59 float timeInterval;
60
61
62 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Properties")
63 UClass* parentClass;
64
65 UFUNCTION(BlueprintCallable, Category = "FUNCTIONS")
66 virtual void EndPlay(EEndPlayReason::Type EndReason) override;
67
68 UFUNCTION(BlueprintCallable, Category = "FUNCTIONS")
69 void spawnSelf();
70
71 UFUNCTION(BlueprintCallable, Category = "FUNCTIONS")
72 void deletes();
73 };
這些代碼是新增在頭檔案中的:
1 public:
2 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Properties")
3 FTimerHandle StarTimer;
4
5 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Properties")
6 FTimerHandle EndTimer;
7
8 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Properties")
9 float timeInterval;
10
11
12 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Properties")
13 UClass* parentClass;
14
15 UFUNCTION(BlueprintCallable, Category = "FUNCTIONS")
16 virtual void EndPlay(EEndPlayReason::Type EndReason) override;
17
18 UFUNCTION(BlueprintCallable, Category = "FUNCTIONS")
19 void spawnSelf();
20
21 UFUNCTION(BlueprintCallable, Category = "FUNCTIONS")
22 void deletes();
23 };
擁有兩個處理TImer的對象,一個為start一個為end,他們分别會在BeginPlay和EndPlay兩個繼承自父類并重寫後的函數中實作。spawnSelf函數用來建立自身,deletes函數用來銷毀自身,以免記憶體過載。
以下是ACTOR的源檔案:
1 // Fill out your copyright notice in the Description page of Project Settings.
2
3
4 #include "CollisionActor.h"
5 #include "Components\BoxComponent.h"
6 #include "UObject\ConstructorHelpers.h"
7 #include "Components\StaticMeshComponent.h"
8 #include "Components\SphereComponent.h"
9 #include "Engine.h"
10
11 // Sets default values
12 ACollisionActor::ACollisionActor()
13 {
14 // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
15 PrimaryActorTick.bCanEverTick = true;
16 myStaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("myStaticMesh"));
17 myCollision = CreateDefaultSubobject<USphereComponent>(TEXT("myCollision"));
18
19 auto myMeshAsset = ConstructorHelpers::FObjectFinder<UStaticMesh>(TEXT("StaticMesh'/Engine/EditorMeshes/ColorCalibrator/SM_ColorCalibrator.SM_ColorCalibrator'"));
20 auto myMatAsset = ConstructorHelpers::FObjectFinder<UMaterialInterface>(TEXT("Material'/Engine/VREditor/UI/ArrowMaterial.ArrowMaterial'"));
21
22 if (myMeshAsset.Succeeded() && myMatAsset.Succeeded()) {
23 myStaticMesh->SetStaticMesh(myMeshAsset.Object);
24 myStaticMesh->SetMaterial(0, myMatAsset.Object);
25 }
26 if (!myStaticMesh->IsSimulatingPhysics()) {
27 myStaticMesh->SetSimulatePhysics(true);
28 myStaticMesh->SetEnableGravity(false);
29 }
30
31 RootComponent = myCollision;
32 myStaticMesh->SetupAttachment(GetRootComponent());
33 myCollision->InitSphereRadius(120.f);
34
35 startsOverlap.BindUFunction(this, "onOverlap");
36 myCollision->OnComponentBeginOverlap.Add(startsOverlap);
37
38
39 endsOverlap.BindUFunction(this, "endOverlap");
40 myCollision->OnComponentEndOverlap.Add(endsOverlap);
41
42 status = false;
43
44 parentClass = ACollisionActor::StaticClass();
45
46
47 timeInterval = 5.0f;
48
49 }
50
51 void ACollisionActor::onOverlap()
52 {
53 GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Red, TEXT("Touch"));
54 status = true;
55
56 }
57
58 void ACollisionActor::endOverlap()
59 {
60 GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Red, TEXT("OutTouch"));
61 status = false;
62 }
63
64
65 // Called when the game starts or when spawned
66 void ACollisionActor::BeginPlay()
67 {
68 Super::BeginPlay();
69
70 GetWorld()->GetTimerManager().SetTimer(StarTimer,this,&ACollisionActor::spawnSelf, timeInterval,true);
71 GetWorld()->GetTimerManager().SetTimer(EndTimer,this,&ACollisionActor::spawnSelf, timeInterval*8,true);
72
73 }
74
75
76
77 void ACollisionActor::spawnSelf() {
78 FVector location = FVector(FMath::RandRange(-1000.0f,1000.0f), FMath::RandRange(-1000.0f, 1000.0f), FMath::RandRange(-1000.0f, 1000.0f));
79 GetWorld()->SpawnActor(parentClass,&location);
80 }
81
82 void ACollisionActor::EndPlay(EEndPlayReason::Type EndReason)
83 {
84 Super::EndPlay(EndReason);
85 GetWorld()->GetTimerManager().ClearTimer(StarTimer);
86 GetWorld()->GetTimerManager().ClearTimer(EndTimer);
87
88 }
89
90
91 void ACollisionActor::deletes()
92 {
93 Destroy();
94 }
95
96 // Called every frame
97 void ACollisionActor::Tick(float DeltaTime)
98 {
99 Super::Tick(DeltaTime);
100
101 if (status == true) {
102 myStaticMesh->AddLocalRotation(FRotator(10.0f));
103 }
104 else {
105 myStaticMesh->AddLocalRotation(FRotator(0.0f));
106 myStaticMesh->SetRelativeRotation(FRotator(0.0f));
107 }
108 }
想要得到計時器的對象,就得先從世界中獲得時間管理對象:
1 GetWorld()->GetTimerManager().SetTimer(StarTimer,this,&ACollisionActor::spawnSelf, timeInterval,true);
通過GetWolrd()獲得世界的指針,再調用GetTimerManager()對象,調用SetTimer函數來設定計時器。
SetTimer常用有四個參數,分别是FTimerHandle類的修,該計時器指向哪個類,該計時器綁定哪個方法,計時器的時間間隔,以及是否循環。
StartTimer這個計時器對象綁定了SpawnSelf方法,通過SpawnActor方法進行自我複制,這裡需要傳入兩個參數,第一個是複制哪個類對象,第二個是在世界裡的位置。
這裡的parentClass指針實際上是指向UClass *parentClass = ACollisionActor::StaticClass();,也就是指向了自己,也就不斷自我複制。
1 void ACollisionActor::spawnSelf() {
2 FVector location = FVector(FMath::RandRange(-1000.0f,1000.0f), FMath::RandRange(-1000.0f, 1000.0f), FMath::RandRange(-1000.0f, 1000.0f));
3 GetWorld()->SpawnActor(parentClass,&location);
4 }
結束Play後調用以下方法,實作計時器清零。
EndPlay方法是繼承而來的,還需要寫入參數,意思是給一個結束遊戲的理由,在枚舉型結構體中的EEndplayReason::Type中,EndReason是各種結束理由的形式參數。
找到GetTimerManager之後,通過ClearTimer方法将我們的FTimerHandle類的對象放進去,對其清零。
1 void ACollisionActor::EndPlay(EEndPlayReason::Type EndReason)
2 {
3 Super::EndPlay(EndReason);
4 GetWorld()->GetTimerManager().ClearTimer(StarTimer);
5 GetWorld()->GetTimerManager().ClearTimer(EndTimer);
以下方法用于銷毀自身。
1 void ACollisionActor::deletes()
2 {
3 Destroy();
4 }
以下方法用于觸發碰撞體之後,進行旋轉。
1 void ACollisionActor::Tick(float DeltaTime)
2 {
3 Super::Tick(DeltaTime);
4
5 if (status == true) {
6 myStaticMesh->AddLocalRotation(FRotator(10.0f));
7 }
8 else {
9 myStaticMesh->AddLocalRotation(FRotator(0.0f));
10 myStaticMesh->SetRelativeRotation(FRotator(0.0f));
11 }
12 }
最終效果實作如下:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBHL0FWby9mZvwVZnFWbp1zczV2YvJHctM3cv1Ce-4WNHNWdVpnT4FERNp3Y65UMwMUTzkkeNlXWq1EMFRlT3NGRNdXSE1UewMVT4FlaOhXQq1kdjRUT3lERNlHOT1EeRpmT4FkaNZ3YyI2cKJDT0ljMZVXTzold41WW15UbMdXSE1UejdlYwlTeMZTTINGMShUYvwlbj5yZtlmbkN3YuQnclZnbvN2Ztl2Lc9CX6MHc0RHaiojIsJye.jpg)