如何控制KineticJS中的帧率?

时间:2014-03-16 16:29:33

标签: javascript ios html5 html5-canvas kineticjs

如何在KineticJS中控制渲染循环帧速率? Kinetic.Animation的文档显示帧速率被传递给渲染回调,而Kinetic.Tween似乎没有帧​​速率逻辑,但我还是看不到强制,例如,当60fps可能时强制30fps。

充满了好奇心的背景,但问题很简单。如果有人继续阅读,欢迎其他建议。如果您已经知道答案,请不要浪费时间阅读!

我正在开发一个音乐应用程序,它结合了一些基于DOM的GUI控件(使用jQuery Mobile进行当前迭代)和基于Canvas的GUI控件(使用KineticJS)。后者涉及一些动画。因为动画元素是由音乐播放触发的,所以我使用Kinetic.Tween来避免记住给定音符已播放多长时间的复杂性(Kinetic.Animation需要这样做)。

这种方法在Chrome中的60fps(在快速机器上)效果很好,但在iOS 6.1 Safari(iPad 2)上运行控件时动画控制的速度非常慢,而且动画正在发生变得有点笨拙。我没有使用WebGL(除非KineticJS或Chrome默认为canvas执行此操作?),当我打包本机UIWebView时,这不是一个选项。

当我超越原型而想要做出更多承诺的技术决策时,我会看到以下选项,按照感知良好的顺序:

  1. 了解如何限制帧速率。因为我的动画大量使用alpha淡化但不涉及动作,我相信我可以用20-30fps逃脱并且看起来很好。还可以在更快的设备上扩展它。

  2. 不要立即响应触摸输入,但是将它们添加到我以恒定间隔轮询的队列中,并且只使用最新的触摸移动。这对我的非交互式动画元素没有影响,但是从另一个方向解决问题,试图减少用户交互的负担。这将需要使Kinetic控件静态并手动跟踪触摸坐标(如果实际上有帮助的话,不是可怕的努力)。

  3. 将基于DOM的GUI重写为基于画布(KineticJS);将基于WebAudio的引擎重写为HTML5音频;利用CocoonJS或Ejecta实现GPU加速。这意味着必须手动编码文件选择器和导航菜单之类的东西(坏)。丢失WebAudio非常严重,因为它消除了DSP效果和非常细粒度,低延迟时序(在iPad 2上正常工作)等功能。

  4. 重写应用程序,将基于DOM的GUI和WebAudio与基于Canvas的元素分开,利用CocoonJS。我不确定它是否/如何运作,但CocoonJS将JavaScript代码作为两个组件之间的字符串传递这一事实让我对这个想法的稳固程度非常不满。这可能是可行的,但最好的情况是我与CocoonJS前进很紧密相关。我不喜欢这样的架构,但也许它没有听起来那么糟糕?

  5. 让动画不那么多汁。这是最不好的,不是因为它的设计影响,而是因为,在我的中央视图组件中,我只能在任何时候动画~20个简单的形状,但它们包括透明度并跨越一个面积~1000x300。像滑块这样的其他组件同样是简单的。换句话说,它现在不是很多汁。

  6. 克服对Objective-C的严重过敏;忘记浏览器,Android和其他移动操作系统。拥有一个本机执行的快速应用程序,并拥有闪亮的Apple批准的小部件。我对这种方法的最大问题是不想陷入Objective-C现实多年,技能方面。我只是不喜欢它。

  7. 购买iPad 3或更高版本。由于我已经假装Android不存在(我没有任何设备可以测试),为什么不假装没有人还有iPad 2?我认为这是推卸责任 - 如果我能在iPad 2上获得可接受的性能,我会对应用程序的性能充满信心,因为我添加了更多功能。

  8. 我可能会忽略选择或以其他方式天真地解决这个问题。有人会说我试图建立的只是愚蠢的。但它的工作非常好尚未准备好在iPad 2上黄金时段。

2 个答案:

答案 0 :(得分:1)

是的,您可以控制Kinetic.Animation帧速率

Kinetic.Animation发送一个具有frame.time属性的帧对象。

.time是一个可以用来限制动画速度的运行计时器。

这是一个限制Kinetic.Animation的例子:http://jsfiddle.net/m1erickson/Hn3cC/

var lastTime;
var frameDelay=1000;

  var loop = new Kinetic.Animation(function(frame) {

      var time = frame.time

      if(!lastTime){lastTime=time;}

      var elapsed = time-lastTime;

      if(elapsed>=frameDelay){

          // frameDelay has expired, so animate stuff now

          // set lastTime for the next loop 
          lastTime=time;

      }
  }, layer);

loop.start();

答案 1 :(得分:0)

根据@ markE的建议,我尝试了一些事情并找到了解决方案。它最终不是火箭科学,而是分享我的想法:

首先,尝试将Tween持续时间和目标加倍,并使用计时器将其停止在50%。这种类型有点工作,但很难看起来很好,并且在编码伪目标,如负不透明度或高度等等时非常容易出错。

其次,在读取Tween的源代码并再次查看动画文档之后,我决定在本地使用动画实例而不是Tween实例,并允许闭包范围挂在相关的注释属性上。最终让这个工作顺利,终于实现了一个大杜!这就是限制几个独立动画事物的帧速率并不以任何方式限制整体帧速率。

最后,决定给我的组件一个render()方法,该方法使用requestAnimationFrame在循环中调用自身,如果在我的钳位时间之前调用则立即退出,并在render()内部更新Kinetic画布和调用层中的所有对象。 drawScene函数()。因为现在只有一个动画,所以这会将帧速率降低到我需要的水平,并且iPad 2上的应用程序 fast (我的眼睛看起来也完全相同)。

所以Kinetic仍然在帮助它的更高级别的画布API,到目前为止,我的其他控制小部件仍然是使用Kinetic处理用户输入和拖动的简单代码,现在表现得更好,因为大型野兽组件没有占用CPU 。

对我原始问题的简短回答是,不能,您无法锁定非常复杂动画的整体帧速率,但正如Mark所说,您可以选择适合单个动画实例的任何内容。

请注意,我仍然可以使用动画而不给它一个图层或显式调用任何draw()方法,但是因为我仍然需要编写所有逻辑来确定单个元素的当前视觉状态这样做没有任何好处。如果Tween可以接受不自动渲染的参数,那将是非常有用的。这样可以简化像我这样的代码,因为我可以在单个对象上简化动画,但仍然选择何时实际执行渲染所有内容的繁重工作。看看整个练习在iPad 2上的表现有多大,可能值得在框架中添加此选项。