找回密码
 点一下
查看: 984|回复: 4

关于触发器执行时间,顺序的研究

[复制链接]
发表于 2020-4-16 18:09:52 | 显示全部楼层 |阅读模式
之前碰到类似问题。稍微做了点研究。有不对的希望指正。


以下时间均指的现实生活的真实时间。


地图初始化中的wait之前的内容会在地图加载中执行。wait后的内容会在地图加载完毕后才开始执行。而不是地图加载中。

wait貌似相当于新注册了一个触发器。


游戏逝去时间0秒 触发器。wait之前的内容会在地图加载中执行,但是会在地图初始化之后。

触发器大概执行2-3亿次无内容for循环。就会出现执行时间过长的报错。导致后面的动作全部跳过。

触发器执行触发器的时间会算在被执行的触发器里,不会累加到调用者的时间里。调用动作(函数)的执行时间会算在调用它的触发器里。但是无论执行触发器还是动作。如果被调用者自身出现执行时间过长。调用者也会出现执行过长。(比方执行10次写好的"1亿次循环的触发器"不会报错全部执行完。但执行10次自定义的"1亿次循环的动作"就会报错。 但无论执行“10亿次循环”触发器还是动作,都会报错。主触发器里的剩余动作会跳过。)

在初始化地图或者其他运行时间很长的触发器。建议用执行触发器分成很多子触发器,而不是执行函数,或一个个动作的写,以防止出现执行触发器时间过长跳过后面动作产生bug。

执行触发器所需的时间似乎不会影响(任何类型?)的计时器,游戏时间。游戏左下角的计时器也无法捕捉到他们。
触发器是单线程的。就算是同一事件引发的多个触发器也并不是同时进行的。而是先执行完排序在面的再执行后面的。但是由于。触发器执行时,游戏时间是"冻结"的。因此在游戏时间里看起来同时执行。




发表于 2020-4-18 20:58:06 | 显示全部楼层
谢谢分享,大概理解了,之前不小心出现嵌套调用同一个动作的时候都是直接强制关闭的。

这个2-3亿次是怎么知道的?
回复

使用道具 举报

 楼主| 发表于 2020-4-19 19:02:01 | 显示全部楼层
试的。2亿次不报错。3亿次就报过长。

点评

厉害,没想到呢  详情 回复 发表于 2020-4-22 19:20
回复

使用道具 举报

发表于 2020-4-22 19:20:28 | 显示全部楼层
Nostalie 发表于 2020-4-19 19:02
试的。2亿次不报错。3亿次就报过长。

厉害,没想到呢
回复

使用道具 举报

发表于 2020-4-23 17:30:59 | 显示全部楼层
本帖最后由 yxxiaobin 于 2020-4-23 17:47 编辑

大部分是对的,不过有几个描述不是很准确。
1.地图初始化不是加载中执行,而是加载完毕进入游戏前才执行。为什么看起来不占用游戏时间,和下一条要说的内容有关,继续往下看。
2.触发器调用自定义动作也可以设置创建线程,这样被调用的动作就不算做调用者线程的一部分。主要的好处是你可以在被调用代码里使用等待,而调用者却不会受影响(但要注意顺序问题)。另外过长的循环可以拆成若干线程,避免代码超时。
3.触发器计算是否需要时间?当然需要,现实世界任何变化一定不是瞬时的,这是基本物理规律。但是在游戏世界看来是瞬时的,不占用时间。其实是由于游戏运行机制导致的。游戏把一秒(游戏时间)分成16份,每份就是0.0625秒,这称作一个游戏周期,每个周期开始的瞬间,游戏就会根据现有情况计算一个周期后的情况,所有计算应该在周期结束前完成,并在周期结束时呈现出来,然后再根据该结果进一步计算下一个周期结束时的情况,如此循环(为了视觉平滑性,演算体会计算一次中间状态,实际刷新频率为32Hz)。也就是说,游戏世界其实是定格动画,并非连续世界,只是刷新频率高,我们感觉起来像是连续的。为啥代码不能太长呢(比如执行太多循环)?因为一个周期的时间可能不足以运算如此多的数据,到周期结束时还不知道该干啥,游戏就会出错。为了避免这个问题,游戏限制了一个线程的代码数量。对于大的循环可以使用增加线程的方案来绕开这一限制。
看到这里就可以解释初始化为啥不使用等待看起来像加载中执行,而使用等待则看起来像是游戏中才执行的。其实根本原因就在于,初始化触发器在极短时间内完成,并在游戏开始立即呈现画面,而且游戏时间也是在呈现画面时才开始计数的。如何证明这一点也很简单:初始化依然会因为代码过长而超时。如果是加载中执行,那么没必要限定一个游戏周期就要计算完成,理论上代码可以无限长的(使用无限长的加载时间)。

关于线程还有一点很重要的提示:如果被调用的自定义动作使用独立线程,且不使用等待,则游戏会运行被调用动作中的代码,然后在执行自身的,这样看起来它们像是在一个线程中一样,你不必担心顺序错误。但是如果使用等待,则调用者不会等待,而是直接执行自身的下一条代码。
补充一下:如果被调用的动作集创建自己的线程,则在调用者中无法使用“最后创建的某某”来获取被调用者创建的物件(无论是单位还是对话框什么的)。这个特点有时有害,因为你需要特别设计传参方式。但有时也很有用。我在自己的RPG强化mod里多次用到这个特点,封装强化UI部件。思路是定义一个自定义动作集A,叫做创建某某UI部件,A不创建线程,在A中用模板创建一个UI部件(一般是框架或按钮),然后让A再调用另一个自定义动作集B,B创建线程,在B中衔接A创建UI部件中的子部件并保存它们。这样,当用户使用A创建自定UI部件后,使用“最后创建的对话框项”能正确获取该UI部件,而不是它内部的子部件,而且,立即获取该UI部件的子部件并设置它们的属性也不受影响。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 点一下

本版积分规则

Archiver|移动端|小黑屋|地精研究院

GMT+8, 2024-12-22 11:09 , Processed in 0.046515 second(s), 23 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表