之前在我的游戏主循环中,时间被管理在 60 FPS 和相应的 Delay 时间延迟。
Sprite 序列动画如下:
<pre>
if(++ciclos > 10){
siguienteSprite++;
ciclos = 0;
}
</pre>
鉴于我正在使用带有 DeltaTime 的平滑运动,因此我从主循环中消除了延迟;这使得动画的 Sprite 周期更快,不仅如此,而且每个序列之间的时间也不同。
有人可以帮我一把,只有这个问题的逻辑,先谢谢你。 :)
最佳答案
delay
在主循环中并不是一个很好的方法(因为它没有考虑主循环中其他内容所花费的时间)。当您删除延迟时,速度会更大并且变化更大,因为主循环计时中的其他内容更重要并且通常由于多种原因而不稳定,例如:
- 操作系统粒度
- 与 gfx 卡/驱动同步
- 处理时间不固定
有更多的方法来处理这个问题:
测量时间
<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
是一些保存“最后”测量时间 os Sprite 变化的全局变量。t1
是实际时间,animation_T
是动画变化之间的时间常数。要测量时间,您需要使用 OS api,如PerformanceCounter
在 Windows 或RDTSC
在 asm 或你手边的任何其他语言中,但分辨率足够小。操作系统计时器
简单地增加
siguienteSprite
在一些带有animation_T
的计时器中间隔。这很简单,但操作系统计时器并不精确,通常约为 1 毫秒或更多 + 操作系统粒度(类似于Sleep
精度)。线程定时器
您可以出于计时目的创建单线程,例如:
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
上使用 RDTSC 的 32 位部分CPU 核心 每隔2^32/3.2e9 = 1.342 sec
就会溢出所以这是真正的可能性。如果我没记错的话,Windows 中的性能计数器通常运行在 3.5 MHz
左右。在较旧的 OS 系统和 60-120 MHz
附近在较新的(至少我上次检查时)并且是 64 位的,所以溢出不是什么大问题(除非你运行 24/7)。此外,在使用 RDTSC 的情况下,您应该将进程/线程关联设置为单个 CPU 核心,以避免在多核 CPU 上出现计时问题。
多年来,我在低水平上参与了基准测试和高级高分辨率计时,因此这里有一些相关的QA我的:
wrong clock cycle measurements with rdtsc - 操作系统粒度
Measuring Cache Latencies - 测量 CPU 频率
Cache size estimation on your system? - PerformanceCounter
例子
Questions on Measuring Time Using the CPU Clock - PIT 作为替代定时源
关于c++ - 通过 DeltaTime 控制 Sprite 序列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41917471/