热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

定义定时器1秒后执行调用自己_UE4Timer(定时器)相关源码分析

前言文章属于旧有文章搬运,之前在csdn上面2019.11.6修改Timer是定时器,用途:延时执行事件周期性执行事件参考官方文档UsingTimersTimer可以Time

前言

  • 文章属于旧有文章搬运, 之前在csdn上面
  • 2019.11.6修改

Timer是定时器, 用途:

  • 延时执行事件
  • 周期性执行事件
参考官方文档Using Timers

Timer可以...

Timer能...

Timer...

...

编不下去了, 自己百度谷歌吧(手动狗头)


TimerManager

fd3a221d69bc32bd58785909ba1332a4.png

Timer的管理类是FTimerManager, 是一个全局的Timer管理类.

3feaead8d99c33eac0b64088d1b34425.png

通常通过UWorld::GetTimerManager()获得
可以看到实际实现是先判断GameInstance是否存在, 存在返回UGameInstanceTimerManger, 否则返回UWorld自己的TimerManger

3de885cc5cd77f8eecd32899c8627533.png
39890aceae142d0ea7a57d8c0bafb50c.png

接着, 如上图, TimerMangerUWorldUGameInstance的构造函数中创建, 调用构造函数, 不试图赋值UGameInstance

3a18c8d9d6fb7615f2b18f4c54acb19a.png
44ec7138cc9d22b041d04e3658d0564e.png

TimerManger的构造函数中, 主要还是给InternalTime设0, 该值是TimerManger内部的一个独立时钟, 在TimerManger的每次Tick调用时计时.

0c173a4767d1304b24c494025c22e236.png

UWorld::Tick中调用FTimerManagerTick函数实际执行Timer里面的操作

af63ca6636a3a97444ccf05a818a73a9.png
cbc6acc01113b1aea4c67e994964ce3d.png

TimerManger的销毁是在UWorld::FinishDestroy和UGameInstance::FinishDestroy中

delete然后置nullptr, 简单粗暴.


Timer的执行

9a87d0ee58a3804b7100d45b18bd4c8d.png

从堆栈中也可以FTimerManger::TickUWorld::Tick调用

cec8b7fb18f28749b7f78b5e83879042.png

如图, 这个函数体主要做了如下内容 :

  • 先调用FTimerManager::HasBeenTickedThisFrame, 并维护LastTickedFrame避免一帧内被多次执行.
8562bc655c876d46888f4a252aca3807.png
ce2e056e4640228e518c2094cdeb2110.png
  • 然后InternalTime计时, 增加DeltaTime偏移量
  • 接着对ActiveTimerHeapPendingTimerSet进行一定逻辑处理
7a87648f4eb80725dcde34063495c818.png

ActiveTimerHeap是一个当前活跃的, 待处理的FTimerHandle数组

b9ca641d20fc4b39cec92d3d2c4158ae.png

while循环体主体逻辑:

不断取堆顶的FTimerHandle, 并得到对应的FTimerData.

如果该FTimerData的状态是可被移除, 那么移除, 继续
不断执行, 直到InternalTimer(内部的独立时钟)大于FTimerDataExpireTime, 即定时器到时间了, 那么执行一定逻辑, 否则, 没有过时间, 就直接break跳出循环

因为ActiveTimerHeap是按照过期时间排序的

f813ad01ff28ace15276d2297d15bbd8.png

接着看, 如果定时器到时间了, 会将ActiveTimerHeap的堆顶元素移动置CurrentlyExecutingTimer(当前正在执行的Timer), 并更新FTimerDataStatusETimerStatus::Executing

注意, 这里的CurrentlyExecutingTimer上文中的TopHandler是同一个值, 所以改Top(FTImerData)修改的是同一Timer的信息

然后, 重点来了

划重点了!

划重点了!

划重点了!

上图圈起来的代码, CallCount(执行次数), 为了避免在两帧之间时间过长而导致丢掉一些定时器的间隔执行, 计算, 两帧之间实际需要执行多少次.

设一个Timer, 每0.1秒执行一次, Tick总共过了5秒, 有

  • 定时器必定执行50次, 执行次数恒定
  • 如果比较卡顿, 每0.5秒执行1帧, 即定时器可能也可以在同一帧执行多次
  • 定时器是假定时, 即期望0.1s, 0.2s, 0.3s, 0.4s, 0.5s执行, 实际可能是0.5s, 0.5s, 0.5s, 0.5s, 0.5s执行5次
607f16a253efda16506a482b40d80459.png
8e38d7aa0f9464ce935dbe347328260f.png

而Timer的执行, 实际上也就是绑定的代理执行. 此处略

// 可以参考代理相关的文章自己啃, 难度不大

cd589fa7d6bc0e4182bd0479ee203b13.png

在执行后有个更新指针的操作, 为了防止执行后无效, 这是为什么呢?

考验你C++功底的时候到了, 自行理解, 此处忽略(手动狗头)

57b6238ebd3047a9f8b0ec59cd1777d0.png

Timer执行完毕之后, 做清理.

如果Timer不循环, 执行一次, 那么完成使命了, 清理掉吧!

如果Timer代理无效了, 那么无法完成使命, 也清理掉吧!

否则, 嗯, 设置下次时间, 打回去, 接着干活(手动狗头)

// 所以循环Timer啊, Timer对应的代理实际对象啊, 多数是不需要人工维护移除的
// 即多数Timer绑定好, 不清除, 也没啥影响, 他会自动移除无效的Timer

b44706687421d87e63785c24b9813d20.png

最后再看PendingTimerSet的处理, 这是在当前Tick帧添加的定时器集合, 将里面的定时器添加到ActiveTimerHeap里面

即很明显, Timer最少也会延迟一帧调用


Timer的使用

ca97d8e4af390e19d8ba3ffcdff6a344.png

参照上面若干函数, 最后都通过FTimerManger::InternalSetTimer函数SetTimerForNextTick相关基本同, 略

25a3444cddc50a64e34cd3b2d42f3ac1.png

FTimerManger::InternalSetTimer中在设置Timer时, 会查找一下TimerHandle是否有效, 有效会清除.

c2d4bc454b5ae14e4f8802a2623bcabe.png

接着就是创建一个FTimerData信息, 并维护, 具体略了


4461b15766890d3d0d55191126bda701.png
65f3e171987d444da5fad34fc7073576.png

最后贴一张使用图, 一些基础知识就懒得提了.

// 基础知识 : TimerHandler清除, 获得剩余时间, 暂停和取消暂停, 是否存在等函数
// 看看头文件, 配合使用即可.

以及提一下这两个Timer的代理:

  • DECLARE_DELEGATE(FTimerDelegate)
  • DECLARE_DYNAMIC_DELEGATE(FTimerDynamicDelegate)

自行参考代理相关文章, 配合使用, 能玩出花(笑)


结语

  • 骗赞, 骗评论了.



推荐阅读
  • PHP反射API的功能和用途详解
    本文详细介绍了PHP反射API的功能和用途,包括动态获取信息和调用对象方法的功能,以及自动加载插件、生成文档、扩充PHP语言等用途。通过反射API,可以获取类的元数据,创建类的实例,调用方法,传递参数,动态调用类的静态方法等。PHP反射API是一种内建的OOP技术扩展,通过使用Reflection、ReflectionClass和ReflectionMethod等类,可以帮助我们分析其他类、接口、方法、属性和扩展。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • 如何提高PHP编程技能及推荐高级教程
    本文介绍了如何提高PHP编程技能的方法,推荐了一些高级教程。学习任何一种编程语言都需要长期的坚持和不懈的努力,本文提醒读者要有足够的耐心和时间投入。通过实践操作学习,可以更好地理解和掌握PHP语言的特异性,特别是单引号和双引号的用法。同时,本文也指出了只走马观花看整体而不深入学习的学习方式无法真正掌握这门语言,建议读者要从整体来考虑局部,培养大局观。最后,本文提醒读者完成一个像模像样的网站需要付出更多的努力和实践。 ... [详细]
  • 本文由编程笔记#小编整理,主要介绍了关于数论相关的知识,包括数论的算法和百度百科的链接。文章还介绍了欧几里得算法、辗转相除法、gcd、lcm和扩展欧几里得算法的使用方法。此外,文章还提到了数论在求解不定方程、模线性方程和乘法逆元方面的应用。摘要长度:184字。 ... [详细]
  • 本文分析了Wince程序内存和存储内存的分布及作用。Wince内存包括系统内存、对象存储和程序内存,其中系统内存占用了一部分SDRAM,而剩下的30M为程序内存和存储内存。对象存储是嵌入式wince操作系统中的一个新概念,常用于消费电子设备中。此外,文章还介绍了主电源和后备电池在操作系统中的作用。 ... [详细]
  • Netty源代码分析服务器端启动ServerBootstrap初始化
    本文主要分析了Netty源代码中服务器端启动的过程,包括ServerBootstrap的初始化和相关参数的设置。通过分析NioEventLoopGroup、NioServerSocketChannel、ChannelOption.SO_BACKLOG等关键组件和选项的作用,深入理解Netty服务器端的启动过程。同时,还介绍了LoggingHandler的作用和使用方法,帮助读者更好地理解Netty源代码。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • 本文整理了315道Python基础题目及答案,帮助读者检验学习成果。文章介绍了学习Python的途径、Python与其他编程语言的对比、解释型和编译型编程语言的简述、Python解释器的种类和特点、位和字节的关系、以及至少5个PEP8规范。对于想要检验自己学习成果的读者,这些题目将是一个不错的选择。请注意,答案在视频中,本文不提供答案。 ... [详细]
  • 本文介绍了GTK+中的GObject对象系统,该系统是基于GLib和C语言完成的面向对象的框架,提供了灵活、可扩展且易于映射到其他语言的特性。其中最重要的是GType,它是GLib运行时类型认证和管理系统的基础,通过注册和管理基本数据类型、用户定义对象和界面类型来实现对象的继承。文章详细解释了GObject系统中对象的三个部分:唯一的ID标识、类结构和实例结构。 ... [详细]
  • 标题: ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • Oracle seg,V$TEMPSEG_USAGE与Oracle排序的关系及使用方法
    本文介绍了Oracle seg,V$TEMPSEG_USAGE与Oracle排序之间的关系,V$TEMPSEG_USAGE是V_$SORT_USAGE的同义词,通过查询dba_objects和dba_synonyms视图可以了解到它们的详细信息。同时,还探讨了V$TEMPSEG_USAGE的使用方法。 ... [详细]
author-avatar
ruanpinger
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有