UE4 不受游戏暂停影响的Timer /Delay C++蓝图都能用

编程入门 行业动态 更新时间:2024-10-06 04:01:11

UE4 <a href=https://www.elefans.com/category/jswz/34/1755929.html style=不受游戏暂停影响的Timer /Delay C++蓝图都能用"/>

UE4 不受游戏暂停影响的Timer /Delay C++蓝图都能用

发现了一个比较正宗的写法!!!!!!!!

(3.2的那条)
通过上面的博主的方法,实现一个actor私有的timermanager,对该actor执行SetTickableWhenPaused(true),这就非常完美

我是真他娘的蠢驴

以下都是错误示范 不需要在意 直接看上面超链

UE4 不受游戏暂停影响的Timer /Delay C++蓝图都能用

原因

业务逻辑需要,以及因为序列帧实现的ui动图是通过tick刷的,暂停时ui tick会暂停,只能通过写一个不受暂停影响的timer去刷序列帧,为了填一个坑,而出来的另一个坑,大家都是挖坑人。

基本原理

重点就是 actorSetTickableWhenPaused(true),就是标记actor在游戏
暂停时,是否能够执行Tick(float DeltaTime)

运用了什么知识

通过FName调用蓝图方法,
C++通过委托绑定方法进行回调
蓝图异步节点(UBlueprintAsyncActionBase)

效果图


使用时必须创建一个SuperTimer对象
可以看到SetGamePause true后,我的delay没有停止,并执行了我的timer并再刷计时任务

源码 SuperTimer.h demo地址:

>下载链接: 提取码: j9q9

// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h"
#include "TimerManager.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "GameFramework/Actor.h"
#include "SuperTimer.generated.h"DECLARE_DYNAMIC_MULTICAST_DELEGATE(FSuperDelayDelegate);USTRUCT(BlueprintType)
struct FSuperTimerHandler
{GENERATED_USTRUCT_BODY()UPROPERTY(BlueprintReadWrite,EditAnywhere)FName FunctionName;UPROPERTY(BlueprintReadWrite, EditAnywhere)bool Loop;UPROPERTY(BlueprintReadWrite, EditAnywhere)UObject* object;UPROPERTY(BlueprintReadWrite, EditAnywhere)float time;bool bEnable = true;int type = 0; //0 是蓝图 1 是c++FTimerUnifiedDelegate* delegateFunc;friend inline bool operator==(const FSuperTimerHandler& A, const FSuperTimerHandler& B){return A.FunctionName == B.FunctionName && A.Loop == B.Loop && A.object == B.object && A.time == B.time;}friend inline uint32 GetTypeHash(const FSuperTimerHandler& Key){uint32 Hash = 0;Hash = HashCombine(Hash, GetTypeHash(Key.FunctionName));Hash = HashCombine(Hash, GetTypeHash(Key.Loop));Hash = HashCombine(Hash, GetTypeHash(Key.object));Hash = HashCombine(Hash, GetTypeHash(Key.time));return Hash;}//TODO :做一个直接通过handler对象实现清理的方法,不需要调用SuperTimer对象的方法//就像蓝图里面的 ClearAndInvalidateTimerHandle////inline void ClearThisTimer()//{//	FSuperTimerHandler tmp = this->StaticStruct;//	ASuperTimer::GetSuperTimer()->RemoveTimer(tmp);//}
};UCLASS()
class MYP_API ASuperTimer : public AActor
{GENERATED_BODY()public:// Sets default values for this actor's propertiesASuperTimer();UFUNCTION(BlueprintPure)static ASuperTimer* GetSuperTimer();UFUNCTION(BlueprintCallable,meta =(DefaultToSelf = "object"))static FSuperTimerHandler SetSuperTimer(FName FuncName, UObject* object, bool loop, float time);UFUNCTION(BlueprintCallable)void ClearAllSuperTimer(){// TimerList.Empty();for (auto& timer : TimerList){timer.Key.bEnable = false;}UE_LOG(LogTemp, Warning, TEXT("Timerlist clear ,now count:%d"), TimerList.Num())}UFUNCTION(BlueprintCallable,meta =(DefaultToSelf = "object"))void ClearSuperTimer(FName FuncName, UObject* object);FSuperTimerHandler InternalSetSuperTimer(FTimerUnifiedDelegate* exefun, bool loop, float time);//c++创建Timer,仿照ue4c++timer写的一套,直接把 ue4的 FTimerUnifiedDelegate给搬过来了//其实虚幻源码就是通过创建delegate,时间一到直接执行delegatetemplate <class UserClass>FORCEINLINE FSuperTimerHandler SetSuperTimerDelegate(UserClass* InObj,typename FTimerDelegate::TUObjectMethodDelegate<UserClass>::FMethodPtr InTimerMethod, bool loop, float time){FTimerUnifiedDelegate* TimerDelegateFunc = new FTimerUnifiedDelegate(FTimerDelegate::CreateUObject(InObj, InTimerMethod));FSuperTimerHandler val = InternalSetSuperTimer(TimerDelegateFunc, loop, time);return val;};//c++清理timervoid RemoveTimer(FSuperTimerHandler timer){for (auto& localTimer : TimerList){if (localTimer.Key == timer){localTimer.Key.bEnable = false;}}}protected:// Called when the game starts or when spawnedvirtual void BeginPlay() override;public:// Called every framevirtual void Tick(float DeltaTime) override;protected:TMap<FSuperTimerHandler, float> TimerList;
};UCLASS()
class MYP_API USuperDelay : public UBlueprintAsyncActionBase
{GENERATED_BODY()UPROPERTY(BlueprintAssignable)FSuperDelayDelegate Completed;UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true", WorldContext = "WorldContextObject", Delay ="0.5"))static USuperDelay* SuperDelay(UObject* WorldContextObject, float DelayTime);protected:void  DelayCallBack(){if (Completed.IsBound()){Completed.Broadcast();}}
};

SuperTimer.cpp

// Fill out your copyright notice in the Description page of Project Settings.#include "SuperTimer.h"static ASuperTimer* SuperTimerInstance = nullptr;
// Sets default values
ASuperTimer::ASuperTimer()
{// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.PrimaryActorTick.bCanEverTick = true;this->SetTickableWhenPaused(true);SuperTimerInstance = this;
}ASuperTimer* ASuperTimer::GetSuperTimer()
{if(!SuperTimerInstance){UE_LOG(LogTemp,Warning,TEXT("Supertimer Actor not Vaild"));}return SuperTimerInstance;
}FSuperTimerHandler ASuperTimer::SetSuperTimer(FName FuncName, UObject* object, bool loop, float time)
{FSuperTimerHandler _handler;_handler.FunctionName = FuncName;_handler.Loop = loop;_handler.object = object;_handler.time = time;_handler.bEnable = true;_handler.type = 0;ASuperTimer::GetSuperTimer()->TimerList.Add(_handler, time);return _handler;
}void ASuperTimer::ClearSuperTimer(FName FuncName, UObject* object)
{TArray<FSuperTimerHandler> TempAllTimer;TimerList.GetKeys(TempAllTimer);for (auto timer : TempAllTimer){if (timer.FunctionName == FuncName && timer.object == object){TimerList.Remove(timer);break;}}
}FSuperTimerHandler ASuperTimer::InternalSetSuperTimer(FTimerUnifiedDelegate* exefun, bool loop, float time)
{FSuperTimerHandler _handler;_handler.Loop = loop;_handler.time = time;_handler.bEnable = true;_handler.type = 1;_handler.delegateFunc = exefun;TimerList.Add(_handler, time);return _handler;
}// Called when the game starts or when spawned
void ASuperTimer::BeginPlay()
{Super::BeginPlay();
}// Called every frame
void ASuperTimer::Tick(float DeltaTime)
{Super::Tick(DeltaTime);TArray<FSuperTimerHandler> AllTimerArray;TimerList.GetKeys(AllTimerArray);for (FSuperTimerHandler timer : AllTimerArray){if (!timer.bEnable){TimerList.Remove(timer);continue;}TimerList[timer] -= DeltaTime;if (TimerList[timer] <= 0.0f){if (timer.type == 0){if (!timer.object){TimerList.Remove(timer);continue;}UFunction* fun = timer.object->FindFunction(timer.FunctionName);if (!fun){TimerList.Remove(timer);continue;}if (timer.Loop){TimerList[timer] = timer.time;}else{TimerList.Remove(timer);}timer.object->ProcessEvent(fun, NULL);UE_LOG(LogTemp, Warning, TEXT("Super Timer Start Calling BP %s ,Func %s"), *timer.object->GetName(),*timer.FunctionName.ToString());}else{if (timer.Loop){TimerList[timer] = timer.time;}else{TimerList.Remove(timer);}timer.delegateFunc->Execute();// UE_LOG(LogTemp, Warning, TEXT("Super Timer Start Calling c++ Func "));}}}
}USuperDelay* USuperDelay::SuperDelay(UObject* WorldContextObject, float DelayTime) 
{USuperDelay* SuperDelayNode = NewObject<USuperDelay>();ASuperTimer::GetSuperTimer()->SetSuperTimerDelegate(SuperDelayNode, &USuperDelay::DelayCallBack, false, DelayTime);return SuperDelayNode;
}

使用时得把MYP_API 改成自己项目的 API
C++的使用下次有空在更新吧
demo奉上
下载链接: 提取码: j9q9

更多推荐

UE4 不受游戏暂停影响的Timer /Delay C++蓝图都能用

本文发布于:2024-02-28 06:42:37,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1768489.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:不受   能用   蓝图   游戏   Delay

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!