平滑的画布动画

3
我正在尝试学习如何使用HTML5的canvas创建平滑的JavaScript动画。但是,动画不太流畅,而是有些“卡顿”。
您可以在这个jsFiddle上看到我构建的框架,目前只使用Webkit属性。
另一位开发人员使用他们的WebViews源码创建了相同的概念,该源码基于Ext.js。出于学习目的,我希望避免使用任何库,以更好地理解JavaScript。WebViews的概念可以在这个jsFiddle上查看,显示出更加平滑的动画效果。
我已经阅读并尝试了各种不同的方案,从将update调用从requestAnimationFrame中提取到自己的循环中,到将上下文转换为绘制位置,再到绘制到后备缓冲区上并将其复制到视口中。以下代码代表了我迄今为止最好的努力。
请问,有什么建议可以改善性能,以使对象在没有外部库的情况下平滑移动?
先行致谢。
var app;
var now = then = delta = 0;
var viewport = document.createElement( 'canvas' );
var viewportContext = viewport.getContext( '2d' );

function App( )
{
    this.circle = {
        position : viewport.width / 2,
        radius : 10
    };
}

App.prototype.initialize = function( )
{
    app = this;
    document.body.appendChild( viewport );
    viewport.width = 320;
    viewport.height = 200;

    webkitRequestAnimationFrame( app.render, viewport );
};

App.prototype.render = function( )
{
    now = performance.webkitNow( );
    delta = ( now - then ) / 1000.0;
    then = now;

    app.update( delta );
    viewportContext.clearRect( 0, 0, viewport.width, viewport.height );
    app.draw( viewportContext );

    webkitRequestAnimationFrame( app.render, viewport );
};

App.prototype.draw = function( context )
{
    context.fillStyle = "white";
    context.beginPath( );
    context.arc( this.circle.position | 0, viewport.height / 2 | 0, this.circle.radius | 0, 0, Math.PI * 2, true );
    context.closePath( );
    context.fill( );
};

App.prototype.update = function( deltaTime )
{
    this.circle.position += viewport.width / 5 * deltaTime;

    if( this.circle.position >= viewport.width )
    {
        this.circle.position = 0;
    }
};

window.onload = function( )
{
    new App( ).initialize( );
};​

对我来说运行很顺畅。话虽如此,您可以通过访问F12开发人员工具并查看分析选项来分析您的应用程序 - 这将向您展示哪些部分的应用程序正在消耗最多的资源和时间。 - Sampson
我没有看出你的演示与你的WebViews演示在流畅度方面有显著差异。我正在运行Chrome 21.0.1180.89 m。 - Seth Flowers
此外,这个页面有大量关于这个主题的信息。 - Shmiddty
1
请注意这里的改进平滑度:http://jsfiddle.net/3TAVu/1/。虽然不太合理,但我认为这与画布的大小有关。 - Shmiddty
@MrSlayer 画布跟踪其状态的更改(如fillStyle/等),因此可能是需要收集的垃圾。 - Shmiddty
显示剩余3条评论
2个回答

4
请参阅此页面以获取许多常见的优化方法,并了解它们为什么以及如何提高性能的详细解释。
此外,由于浏览器的优化,性能似乎在更中等尺寸的画布上有所提高。我不完全确定这是为什么,但我相信与浏览器优化有关。
您可以通过进行一些小的修改来提高性能:http://jsfiddle.net/3TAVu/1/ 具体来说,在此处删除了对fillStyle的多余赋值。
App.prototype.draw = function( context )
{
    context.beginPath( );
    context.arc( this.circle.position | 0, viewport.height / 2 | 0, this.circle.radius | 0, 0, Math.PI * 2, true );
    context.closePath( );
    context.fill( );
};

我还通过只清除画布的相关部分而非整个画布来修改了渲染方法:
App.prototype.render = function( )
{
    now = performance.webkitNow( );
    delta = ( now - then ) / 1000.0;
    then = now;

    var cX = app.circle ? (app.circle.position - app.circle.radius) : 0;
    var cY = Math.round(viewport.height/2) - app.circle.radius;
    var w = app.circle ? app.circle.radius * 2 : 0;

    viewportContext.clearRect(cX - 1, cY - 1, w + 2, w + 2);

    app.update( delta );
    app.draw( viewportContext );

    webkitRequestAnimationFrame( app.render, viewport );
};

感谢您的帮助,@Shmiddty。我认为我已经有足够的信息来继续使用这个框架了。很可能,我需要重新添加完整的画布清除功能,因为场景通常比水平移动的球更有趣。此外,感谢提供文档链接。我已经阅读了大部分内容,但由于信息过载,我可能需要再次复习。 - jeffjenx
当然可以。我通常觉得这些东西非常有趣。 - Shmiddty

4

嘿,我发现了这个很好解释requestAnimationFrame的页面:这里,它处理更平滑的动画。如果你或者以后的人看到这个问题时可能会发现这个页面有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接