Tick的三种方式

  • 包括

    • 默认 Tick (Actor、Component、UMG)
    • TimerManager 定时器
    • FTickableGameObject
      • 可以写原生 Object
      • 也可以继承UObject 使用
  • 下面利用 AActor 直接实现三种 Tick
class  FTickableObject :public FTickableGameObject
{
public:
bool bEnableTick = false;
int32 TickCounter = 0; virtual void Tick(float DeltaTime)override {
UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__"\t [TickCounter]%d"), TickCounter);
}
virtual bool IsTickable()const override { return bEnableTick; }
virtual TStatId GetStatId() const override { RETURN_QUICK_DECLARE_CYCLE_STAT(UTickableObject, STATGROUP_Tickables); }
}; UCLASS()
class DESIGNPATTERNS_API AAsyncTickActor : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AAsyncTickActor(); // Called every frame
virtual void Tick(float DeltaTime) override;
void TimerTick();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override; private:
int32 TickCounter = 0;
FTimerHandle TimeHandle;
TSharedPtr<FTickableObject> TickableObject;
};
AAsyncTickActor::AAsyncTickActor()
{
// 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;
} // Called when the game starts or when spawned
void AAsyncTickActor::BeginPlay()
{
Super::BeginPlay();
TickableObject = MakeShareable(new FTickableObject());
TickableObject->bEnableTick = true;
GetWorld()->GetTimerManager().SetTimer(TimeHandle, this, &AAsyncTickActor::TimerTick, 0.1f, true);
} // Called every frame
void AAsyncTickActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__"\t[TickCounter]%d"), TickCounter);
if (TickableObject.IsValid())
{
TickableObject->TickCounter = TickCounter;
} } void AAsyncTickActor::TimerTick()
{
TickCounter++;
UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__"%\t [TickCounter]%d"), TickCounter);
}

异步蓝图节点

使用方法

  • 继承 UBlueprintAsyncActionBase

    • 成员函数 Activate 用于内部触发委托绑定的事件
    • 成员函数 RegisterWithGameInstance 允许将该对象注册到 GameInstance,防止GC
    • 注册后,调用成员方法 SetReadyToDestroy 销毁、释放,从 GameInstance 注销
    • 源码
      class UGameInstance;
      
      UCLASS()
      class ENGINE_API UBlueprintAsyncActionBase : public UObject
      {
      GENERATED_UCLASS_BODY() /** Called to trigger the action once the delegates have been bound */
      UFUNCTION(BlueprintCallable, meta=(BlueprintInternalUseOnly="true"))
      virtual void Activate(); /**
      * Call to globally register this object with a game instance, it will not be destroyed until SetReadyToDestroy is called
      * This allows having an action stay alive until SetReadyToDestroy is manually called, allowing it to be used inside loops or if the calling BP goes away
      */
      virtual void RegisterWithGameInstance(UObject* WorldContextObject);
      virtual void RegisterWithGameInstance(UGameInstance* GameInstance); /** Call when the action is completely done, this makes the action free to delete, and will unregister it with the game instance */
      virtual void SetReadyToDestroy(); protected:
      TWeakObjectPtr<UGameInstance> RegisteredWithGameInstance;
      };
  • 声明静态函数

  • 需要动态多播委托,作为多个输出节点

代码实现

  • 代码

    UCLASS()
    class DESIGNPATTERNS_API AAsyncTickActor : public AActor
    {
    public:
    UPROPERTY(BlueprintReadWrite)
    TArray<int32>CountdownNums;
    }; // 定义委托类型
    DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FCompleteHandleDelegate, int32, Result); UCLASS()
    class DESIGNPATTERNS_API UMyBPAsyncAction : public UBlueprintAsyncActionBase
    {
    GENERATED_BODY()
    public:
    UMyBPAsyncAction() { UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__"")); }
    ~UMyBPAsyncAction() { UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__"")); } // 自定义的异步蓝图节点
    UFUNCTION(BlueprintCallable, meta = (WorldContext = "WorldContextObject"), Category = "MyBPAsyncAction")
    static UMyBPAsyncAction* AsyncCountdown(UObject* WorldContextObject, AAsyncTickActor* AsyncTickActor, int32 StartNum);
    public:
    //输出节点
    UPROPERTY(BlueprintAssignable)
    FCompleteHandleDelegate OnSucceeded; //输出节点
    UPROPERTY(BlueprintAssignable)
    FCompleteHandleDelegate OnFailed;
    private:
    FTimerHandle TimerHandle; protected:
    virtual void Activate() override;
    };
    void UMyBPAsyncAction::Activate()
    {
    // 开新的线程,测试 Activate 调用情况
    Async(EAsyncExecution::ThreadPool, [&]()
    {
    UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" Start Delay 1s."));
    FPlatformProcess::Sleep(1.0f);
    UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" Delay Finished."));
    });
    } UMyBPAsyncAction* UMyBPAsyncAction::AsyncCountdown(UObject* WorldContextObject, AAsyncTickActor* AsyncTickActor, int32 StartNum)
    {
    if (WorldContextObject == nullptr)
    {
    FFrame::KismetExecutionMessage(TEXT("Invalid WorldContextObject"), ELogVerbosity::Error);
    UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" Invalid WorldContextObject."));
    return nullptr;
    } UMyBPAsyncAction* MyBPAsyncActionNode = NewObject<UMyBPAsyncAction>();
    // Lambda 表达式
    auto CountdownFunc = [&,MyBPAsyncActionNode, WorldContextObject, AsyncTickActor, StartNum]() {
    if (IsValid(AsyncTickActor))
    {
    if (AsyncTickActor->CountdownNums.Num() == StartNum)
    {
    // OnSucceeded输出节点
    MyBPAsyncActionNode->OnSucceeded.Broadcast(1); // 清空定时器
    WorldContextObject->GetWorld()->GetTimerManager().ClearTimer(MyBPAsyncActionNode->TimerHandle); // 如果不使用,则销毁
    MyBPAsyncActionNode->SetReadyToDestroy();
    UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" Countdown Completed."));
    }
    else
    {
    int32 length = AsyncTickActor->CountdownNums.Num();
    AsyncTickActor->CountdownNums.Add(length + 1);
    UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" Counting down... %d"), length + 1);
    }
    }
    else
    {
    // OnFailed 输出节点
    MyBPAsyncActionNode->OnFailed.Broadcast(-1);
    WorldContextObject->GetWorld()->GetTimerManager().ClearTimer(MyBPAsyncActionNode->TimerHandle);
    UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" Invalid AsyncTickActor."));
    FFrame::KismetExecutionMessage(TEXT("Invalid AsyncTickActor"), ELogVerbosity::Error);
    }
    }; // 设置定时器并开始
    WorldContextObject->GetWorld()->GetTimerManager().SetTimer(MyBPAsyncActionNode->TimerHandle, FTimerDelegate::CreateLambda(CountdownFunc), 1.0f, true);
    UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" Countdown Starting."));
    return MyBPAsyncActionNode;
    }

【UE4 C++】Tick的三种方式、异步蓝图节点的更多相关文章

  1. [UE4]C++创建对象的三种方式

    #include <iostream> using namespace std; class A { private: int n; public: A(int m):n(m) { } ~ ...

  2. [UE4]更新UI的三种方式

    一.函数绑定 二.属性绑定 只会列出匹配的数据类型. 三.事件驱动更新 啦啦啦啦啦 结论:函数和属性绑定的原理都是每帧都去调用绑定的函数/属性,效率比较低下,一般不推荐使用.事件驱动更新的效率最好,性 ...

  3. js异步执行 按需加载 三种方式

    js异步执行 按需加载 三种方式 第一种:函数引用 将所需加载方法放在匿名函数中传入 //第一种 函数引用 function loadScript(url,callback){ //创建一个js va ...

  4. 0036 Java学习笔记-多线程-创建线程的三种方式

    创建线程 创建线程的三种方式: 继承java.lang.Thread 实现java.lang.Runnable接口 实现java.util.concurrent.Callable接口 所有的线程对象都 ...

  5. Linux就这个范儿 第15章 七种武器 linux 同步IO: sync、fsync与fdatasync Linux中的内存大页面huge page/large page David Cutler Linux读写内存数据的三种方式

    Linux就这个范儿 第15章 七种武器  linux 同步IO: sync.fsync与fdatasync   Linux中的内存大页面huge page/large page  David Cut ...

  6. Kafka生产者发送消息的三种方式

    Kafka是一种分布式的基于发布/订阅的消息系统,它的高吞吐量.灵活的offset是其它消息系统所没有的. Kafka发送消息主要有三种方式: 1.发送并忘记 2.同步发送 3.异步发送+回调函数 下 ...

  7. Android录制音频的三种方式

    对于录制音频,Android系统就都自带了一个小小的应用,可是使用起来可能不是特别的灵活.所以有提供了另外的俩种. 下边来介绍下这三种录制的方式; 1.通过Intent调用系统的录音器功能,然后在录制 ...

  8. python 全栈开发,Day94(Promise,箭头函数,Django REST framework,生成json数据三种方式,serializers,Postman使用,外部python脚本调用django)

    昨日内容回顾 1. 内容回顾 1. VueX VueX分三部分 1. state 2. mutations 3. actions 存放数据 修改数据的唯一方式 异步操作 修改state中数据的步骤: ...

  9. 根据服务端生成的WSDL文件创建客户端支持代码的三种方式

    第一种:使用wsimport是JDK自带的工具,来生成 生成java客户端代码常使用的命令参数说明: 参数 说明 -p 定义客户端生成类的包名称 -s 指定客户端执行类的源文件存放目录 -d 指定客户 ...

随机推荐

  1. 性能测试工具JMeter 基础(七)—— 测试元件: 逻辑控制器之if逻辑控制器

    逻辑控制器线程组指定了其取样器执行的逻辑条件.顺序,并且执行顺序是按照位置顺序从上至下执行的 if逻辑控制器(If Controller) 在逻辑控制器中可设置条件,当条件满足的时候才会被执行 一共有 ...

  2. 乐肴2.0环境改名后,需要删除原来的软链接(public/storage)

    rm -rf public/storage php artisan storage:link

  3. C#提取程序的图标

    需要添加对System.Management.dll的引用  ,并且不要忘记导入下面的名称空间. using System.Management; 将ListView和  ImageList控件从可视 ...

  4. webgl 图像处理 加速计算

    webgl 图像处理 webgl 不仅仅可以用来进行图形可视化, 它还能进行图像处理 图像处理1---数据传输 webgl 进行图形处理的第一步: 传输数据到 GPU 下图为传输点数据到 GPU 并进 ...

  5. 记一次docker compose的低级错误

    记一次docker compose的低级错误 问题 ​ 今天在学习dockercompose的时候,启动docker compose up,结果却出现异常 Error response from da ...

  6. PHP中的文件系统函数(一)

    从这篇文章开始,我们将学习一系列的 PHP 文件系统相关函数.其实这些函数中,有很多都是我们经常用到的,大家并不需要刻意地去记住它们,只要知道有这么个东西,在使用的时候记得来查文档就可以了. 文件路径 ...

  7. 如何创建 Office LTSC 2021 VL(批量许可)版本的安装 ISO

    Office LTSC 2021 发布 2021 年 9 月 16 日,微软正式发布了支持 Office 2021 的部署工具(Office Deployment Tool),这意味着 Office ...

  8. jmeter5.2 性能测试 资源监控 JMeterPlugins1.4 ServerAgent2.2.1

    一.性能工具的安装部署 1.下载JMeterPlugins-Standard-1.4.0.zip的安装包 2.解压JMeterPlugins-Standard-1.4.0.zip,将其中\lib\ex ...

  9. [手机编程]Aid Learning--换源+数据库安装

    换源+MYSQL安装 Aid Learning下载安装 http://www.aidlearning.net/ 切换源 打开Terminal复制回车即可 cd /etc/apt/&& ...

  10. centos 7 部署 zookeeper

    Zookeeper集群搭建 由于公司缓存方案改进,准备采用codis集群作为主要的缓存解决方案(codis:国内豌豆荚开发的redis集群解决方案,已开源,github地址:https://githu ...