javascript - Canvas Sprite 表错误

标签 javascript html canvas sprite-sheet

我在 Canvas Sprite 表动画上发现了一个可爱的代码片段。这是 ts:

http://jsfiddle.net/m1erickson/h85Gq/

我尝试通过编写一个接受 Image 对象的动画函数来美化这段代码,以便我可以同时为 Canvas 中的多个图像设置动画。这是我的尝试:

    $(function(){
        var canvas=document.getElementById("canvas");
        var ctx=canvas.getContext("2d");
        var spritePosition=0;
        var spriteWidth=100;
        var spriteHeight=100;
        var spriteCount=40;
        var spritePlayCount=0;
        var maxSpritePlays=2;

        var objectS=new Image();
        objectS.src="sprites/first.png";

        var fps = 50;
        function animate(sprite) {
            setTimeout(function() {

                if(spritePlayCount<maxSpritePlays){
                    requestAnimationFrame(animate);
                }

                // Drawing code goes here
                ctx.clearRect(0,0,canvas.width,canvas.height);
                ctx.drawImage(sprite,spritePosition*spriteWidth, 0,spriteWidth, spriteHeight, 0,0,spriteWidth, spriteHeight);

                spritePosition++;
                if(spritePosition>spriteCount-1){
                    spritePosition=0;
                    spritePlayCount++;
                }
            }, 1000 / fps);
        }

        objectS.onload=function(){
            animate(objectS);
        }
    }); // end $(function(){});

我收到了一个经常被观察到的错误,但我似乎找不到修复它的方法:

index3.html:59 Uncaught TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)'

你能帮我找到我的错误吗?

最佳答案

天哪!

quote OP "Imagine having 50 spritesheets you want to animate."

50!

查看代码“接受的答案版本”

function animate(sprite) {
    // create a timer event to fire in 1/50th second 
    setTimeout(function() {
         if (spritePlayCount < maxSpritePlays) {
            // create a animation frame event that may fire at some time
            // between 0 and 16ms or 32ms from now
            requestAnimationFrame(function() { 
                animate(sprite);
            });
        }
        // Drawing code etc... Make canvas dirty
        // exiting with dirty canvas outside the requestAnimationFrame
        // forces DOM to swap canvas backbuffer immediately on exit.

    }, 1000 / 50);
}

这是对一个 Sprite 进行动画处理的最糟糕的方式,更不用说对多个 Sprite 进行动画处理了。

  1. 时间与显示刷新不同步。
  2. 使用 requestAnimationFrame 的回调来创建渲染的定时事件,完全否定了使用 requestAnimationFrame 的原因。 requestAnimationFrame 告诉 DOM 您在回调中绘制的内容是动画的一部分。使用计时器进行绘制意味着您不会在请求的帧中绘制任何内容,从而使请求变得多余。
  3. requestAnimationFrame 会尽力在下一次显示刷新(1/60)之前获取所有回调,但如果在下一次刷新之前没有时间更新 DOM(交换所有脏缓冲区),它将延迟回调。您无法控制动画的时间,它们可能会在 20 毫秒到 36 毫秒甚至更长的时间内触发,并且随着时间的推移并不一致。
  4. 通过使用计时器在 Canvas 上绘制,您将强制为您绘制的每个 Sprite 进行后台缓冲区交换。这是一个昂贵的过程,并且会严重限制您绘制 Sprite 的速度,并导致 Sprite 在动画过程中随机闪烁和剪切。

最佳实践方法。

  • 使用由 requestAnimationFrame 触发的单个动画循环。
  • 使用数组存储所有 Sprite ,并根据需要在主循环中更新它们。
  • 仅在主循环内渲染。不要在主循环执行之外对 DOM 进行渲染或执行任何操作(定期)。
  • 不要渲染内部事件,例如计时器、IO 或任何其他快速触发的事件。

关于javascript - Canvas Sprite 表错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43159465/

相关文章:

javascript - 如何让我的代码不那么慢 (JavaScript) - 最大素数

html - Google 未列出网站,但没有错误且内容显得丰富

javascript - 调整 Canvas 大小而不裁剪

javascript - HTML5的canvas元素有重绘事件吗?

javascript - 在 momentjs 中格式化 0 会转换为 1

javascript - Grunt-injector - 首先注入(inject)父目录

jquery - 使用 jquery 获取 select 中所有被选元素的索引

html - div 内容不在外部固定 div 内

javascript - Processing.js 值得吗?

javascript - 如何在 Google App Engine 上的 HTML 页面中嵌入处理草图