通过 DeltaTime 控制精灵序列
Sprites sequence control through DeltaTime
之前在我的游戏主循环中,时间被管理在 60 FPS 和相应的 Delay 时间延迟。
Sprite 序列动画如下:
<pre>
if(++ciclos > 10){
siguienteSprite++;
ciclos = 0;
}
</pre>
考虑到我在 DeltaTime 中使用 Smooth Motion,因此我从 Main Cycle 中消除了 Delay;使动画的精灵循环更快,不仅如此,而且每个序列之间的时间也不同。
谁能帮帮我,只有这个问题的逻辑,先谢谢了。 :)
delay
在主循环中并不是真正的好方法(因为它没有考虑主循环中其他内容所花费的时间)。当您删除延迟时,速度会更大并且变化更大,因为主循环计时中的其他内容更重要并且通常由于多种原因而不稳定,例如:
- OS粒度
- 与 gfx 同步 card/driver
- 非常数处理时间
有更多的方法来处理这个问题:
测量时间
<pre>
t1=get_actual_time();
while (t1-t0>=animation_T)
{
siguienteSprite++;
t0+=animation_T;
}
// t0=t1; // this is optional and change the timing properties a bit
</pre>
其中 t0
是一些保存 "last" 测量时间 os 精灵变化的全局变量。 t1
是实际时间,animation_T
是动画变化之间的时间常数。要测量时间,您需要使用 OS api 就像 PerformanceCounter
on windows 或 RDTSC
in asm 或任何其他你手头有但分辨率足够小。
OS定时器
简单地增加 siguienteSprite
在一些计时器中 animation_T
间隔。这很简单,但 OS 计时器并不精确,通常约为 1 毫秒或更多 + OS 粒度(类似于 Sleep
精度)。
线程定时器
您可以为定时 purposes 创建单线程,例如:
for (;!threads_stop;)
{
Delay(animation_T); // or Sleep()
siguienteSprite++;
}
不要忘记 siguienteSprite
必须 volatile
并在渲染期间进行缓冲以避免闪烁和/或访问冲突错误。这种方法更精确一些(除非你有单核CPU)。
您还可以改为增加一些时间变量,并将其用作您应用中的实际时间,具有您想要的任何分辨率。但请注意,如果 delay
没有将 CPU 控制权返回给 OS,那么此方法将利用您的 CPU 到 100%/CPU_cores
。对此有补救措施,那就是用这个替换你的delay
:
Sleep(0.9*animation_T);
for (;;)
{
t1=get_actual_time();
if (t1-t0>=animation_T)
{
siguienteSprite++;
t0=t1;
break;
}
如果您使用的是测量时间,那么您应该处理溢出 (t1<t0)
因为任何计数器都会在时间过后溢出。例如,在 3.2 GHz
CPU core 上使用 RDTSC 的 32 位部分将每隔 2^32/3.2e9 = 1.342 sec
溢出一次,所以它是真正的 pos亲和力。如果我的记忆力很好,那么 Windows 中的性能计数器通常 运行 大约 3.5 MHz
在旧的 OS 系统和大约 60-120 MHz
在较新的版本上(至少我上次检查时是这样)并且是 64 位的,所以溢出不是什么大问题(除非你 运行 24/7)。此外,在使用 RDTSC 的情况下,您应该将 process/thread affinity 设置为单个 CPU 核心以避免多核上的时序问题CPUs.
多年来,我在低水平上参与了基准测试和高级高分辨率时序,所以这里很少有我的相关 QA:
wrong clock cycle measurements with rdtsc - OS 粒度
Measuring Cache Latencies - 测量 CPU 频率
Cache size estimation on your system? - PerformanceCounter
示例
Questions on Measuring Time Using the CPU Clock - PIT 作为替代定时源
之前在我的游戏主循环中,时间被管理在 60 FPS 和相应的 Delay 时间延迟。
Sprite 序列动画如下:
<pre>
if(++ciclos > 10){
siguienteSprite++;
ciclos = 0;
}
</pre>
考虑到我在 DeltaTime 中使用 Smooth Motion,因此我从 Main Cycle 中消除了 Delay;使动画的精灵循环更快,不仅如此,而且每个序列之间的时间也不同。
谁能帮帮我,只有这个问题的逻辑,先谢谢了。 :)
delay
在主循环中并不是真正的好方法(因为它没有考虑主循环中其他内容所花费的时间)。当您删除延迟时,速度会更大并且变化更大,因为主循环计时中的其他内容更重要并且通常由于多种原因而不稳定,例如:
- OS粒度
- 与 gfx 同步 card/driver
- 非常数处理时间
有更多的方法来处理这个问题:
测量时间
<pre> t1=get_actual_time(); while (t1-t0>=animation_T) { siguienteSprite++; t0+=animation_T; } // t0=t1; // this is optional and change the timing properties a bit </pre>
其中
t0
是一些保存 "last" 测量时间 os 精灵变化的全局变量。t1
是实际时间,animation_T
是动画变化之间的时间常数。要测量时间,您需要使用 OS api 就像PerformanceCounter
on windows 或RDTSC
in asm 或任何其他你手头有但分辨率足够小。OS定时器
简单地增加
siguienteSprite
在一些计时器中animation_T
间隔。这很简单,但 OS 计时器并不精确,通常约为 1 毫秒或更多 + OS 粒度(类似于Sleep
精度)。线程定时器
您可以为定时 purposes 创建单线程,例如:
for (;!threads_stop;) { Delay(animation_T); // or Sleep() siguienteSprite++; }
不要忘记
siguienteSprite
必须volatile
并在渲染期间进行缓冲以避免闪烁和/或访问冲突错误。这种方法更精确一些(除非你有单核CPU)。您还可以改为增加一些时间变量,并将其用作您应用中的实际时间,具有您想要的任何分辨率。但请注意,如果
delay
没有将 CPU 控制权返回给 OS,那么此方法将利用您的 CPU 到100%/CPU_cores
。对此有补救措施,那就是用这个替换你的delay
:Sleep(0.9*animation_T); for (;;) { t1=get_actual_time(); if (t1-t0>=animation_T) { siguienteSprite++; t0=t1; break; }
如果您使用的是测量时间,那么您应该处理溢出 (t1<t0)
因为任何计数器都会在时间过后溢出。例如,在 3.2 GHz
CPU core 上使用 RDTSC 的 32 位部分将每隔 2^32/3.2e9 = 1.342 sec
溢出一次,所以它是真正的 pos亲和力。如果我的记忆力很好,那么 Windows 中的性能计数器通常 运行 大约 3.5 MHz
在旧的 OS 系统和大约 60-120 MHz
在较新的版本上(至少我上次检查时是这样)并且是 64 位的,所以溢出不是什么大问题(除非你 运行 24/7)。此外,在使用 RDTSC 的情况下,您应该将 process/thread affinity 设置为单个 CPU 核心以避免多核上的时序问题CPUs.
多年来,我在低水平上参与了基准测试和高级高分辨率时序,所以这里很少有我的相关 QA:
wrong clock cycle measurements with rdtsc - OS 粒度
Measuring Cache Latencies - 测量 CPU 频率
Cache size estimation on your system? - PerformanceCounter
示例
Questions on Measuring Time Using the CPU Clock - PIT 作为替代定时源