zuluoaaa / blog

blog
6 stars 0 forks source link

基于经过时间的帧渲染 #1

Open zuluoaaa opened 6 years ago

zuluoaaa commented 6 years ago

最近在看游戏引擎架构这本书,记录一些书中知识点。

很多人在刚开始学GUI编程的时候,都会在不借助框架或其他外部工具的情况下,实现一些简单或复杂动画效果。这些动画一般都是基于一个whilte(true)、setInterval 或一些专门用来做帧渲染的方法(例如requestanimationframe)。

这是一段简单的动画伪代码,每次渲染的时候去移动对象的位置。

let obj = { x:0, y:0, };//初始化一个对象 `

let fn = ()=>{
    //每次渲染的时候去修改对象的坐标位置
    ++obj.x;
    ++obj.y;

    //渲染该对象
    render();

    requestAnimationFrame(fn);
}
requestAnimationFrame(fn)`

据我观察,有不少人(比如我:D),都写过类似的代码,这段代码里有个很常见的错误。那就是直接在循环方法里,算出一个固定值(如果是加速或缓速,这个固定值每次都会递增或递减),每次都直接加上这个固定值,直接进行位移操作。

这个错误导致的后果便是,对象的动画效果,完全是基于当前CPU的效率,如果CPU足够空闲的话,看上去就会一切正常。如果这时CPU忙碌或者其他导致原因(导致代码执行效率下降的,上面的代码就会开始出错,对象的移动速度开始变慢。最终导致的后果就是,这个动画效果,在不同的平台或机器上显示,物体的移动速度不一致。

解决的方法也很简单,那么就是改成基于经过时间的更新。

举个例子说明-

假设: 有个动画:对象X,从A点移动到B点,耗时N秒,移动M像素。 绘制频率不可控(大于16帧,小于60帧),要保证在N秒内准时移动到B点,保证每帧的绘制准确;

新建一个变量L,保存相对于当前帧的前5帧耗费时间的平均时间;(因为每帧的执行时间都可能是不一样的,每次都通过前几次绘制的平均时间来预测下一次的执行时间会比较准确)

获取每帧的消耗时间:在每帧绘制执行的时候,before:获取当前时间,after:获取当前时间,两者相减为该帧的消耗时间;

绘制帧率K = 1000/L

每帧移动的像素距离J = M/K

一开始X的当前位置是A, 每帧执行的时候,X的当前位置 += J

这里就不贴具体的实现代码了,大家可以自行写一下:D