在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 }
最终效果实现如下: