简体   繁体   English

画布精灵表错误

[英]canvas sprite sheet error

I found a lovely code snippet on canvas spritesheet animations. 我在画布Spritesheet动画上找到了一个可爱的代码段。 this is ts: 这是ts:

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

I tried to beautify this code, by writing an animate function that accepts Image objects, so that I can animate multiple images in my canvas simultaneously. 我试图通过编写一个接受Image对象的动画函数来美化此代码,以便可以同时对画布中的多个图像进行动画处理。 This is my attempt at it: 这是我的尝试:

    $(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(){});

I am getting a much observed error, but I cant seem to find the fix for it: 我收到了一个观察到的错误,但似乎无法找到解决方法:

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)' index3.html:59未捕获的TypeError:无法在'CanvasRenderingContext2D'上执行'drawImage':提供的值不是'(CSSImageValue或HTMLImageElement或HTMLVideoElement或HTMLCanvasElement或ImageBitmap或OffscreenCanvas)类型的值

Can you help me out finding my bug? 你能帮我找到我的虫子吗?

OMDG! OMDG!

quote OP "Imagine having 50 spritesheets you want to animate." 引用OP “想象一下,要创建50个要制作动画的Spritesheets。”

50! 50!

Looking at the code "accepted answer version" 查看代码“可接受的答案版本”

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);
}

This is the worst possible way to animate one, let alone more than one sprite. 这是制作一个动画的最糟糕的方法,更不用说一个以上的精灵了。

  1. The timing is out of sync with the display refresh. 计时与显示刷新不同步。
  2. Using requestAnimationFrame's callback to create a timed event that renders, completely negates the reason for using requestAnimationFrame. 使用requestAnimationFrame的回调创建一个呈现的定时事件,完全消除了使用requestAnimationFrame的原因。 requestAnimationFrame tells the DOM that what you draw in the callback is part of an animation. requestAnimationFrame告诉DOM您在回调中绘制的内容是动画的一部分。 Using a timer to draw means you don't draw anything in the requested frame making the request redundant. 使用计时器进行绘制意味着您不会在请求的帧中绘制任何东西,从而使请求变得多余。
  3. requestAnimationFrame does its best to get all the callbacks in before the next display refresh (1/60th) but it will delay the callback if there is no time to update the DOM (swap all dirty buffers) before the next refresh. requestAnimationFrame会尽最大努力在下一次显示刷新(1/60)之前获取所有回调,但是如果没有时间在下一次刷新之前更新DOM(交换所有脏缓冲区),它将延迟回调。 You have no control over the timing of your animation, they may fire anywhere from 20ms to 36ms or more with no consistency over time. 您无法控制动画的时间,它们可能会在20毫秒到36毫秒或更长的时间内触发,并且随着时间的推移没有一致性。
  4. By using timers to draw to the canvas you are forcing a backbuffer swap for each sprite you draw. 通过使用计时器绘制到画布上,您将强制为每个绘制的精灵进行后缓冲区交换。 This is an expensive process and will severely limit the speed that you can draw sprites at, and cause sprites to flicker and shear randomly during animation. 这是一个昂贵的过程,将严重限制您绘制精灵的速度,并导致精灵在动画过程中随机闪烁和剪切。

The best practice way. 最佳做法。

  • Use a single animation loop triggered by requestAnimationFrame. 使用由requestAnimationFrame触发的单个动画循环。
  • Use an array to store all sprites and update them in the main loop if/as needed. 使用数组存储所有精灵,并根据需要在主循环中更新它们。
  • Only render from within the main loop. 仅从主循环内渲染。 Do not render or do anything (at a regular interval) to the DOM outside the main loop's execution. 不要在主循环执行之外对DOM进行渲染或进行任何操作(以固定间隔)。
  • Don't render inside events like timers, IO, or any other rapidly firing event. 不要渲染内部事件,例如计时器,IO或任何其他快速触发事件。

You'll also need to pass the sprite parameter when calling the animate function using requestAnimationFrame . 使用requestAnimationFrame调用动画函数时,还需要传递sprite参数。

$(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(function() {
                    animate(sprite);
                });
            }
            // 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);
    };
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM