如何加快在画布上绘制瓷砖

How to speed up drawing tiles on canvas?

本文关键字:绘制 何加快      更新时间:2023-09-26

我试着写一个等距贴图游戏引擎,有这个代码的速度问题:

$(function() {
var canvas = document.getElementById('GameCanvas');
var context = document.getElementById('GameCanvas').getContext('2d');
var imgObj = new Image();
imgObj.src = 'img/sand_surface.png';
var Game = {
    tileScaleX: 64,
    tileScaleY: 32,
    FPSLimit: 50, // max allowed framerate
    realFPS: 0, // real framerate
    init: function() {

        this.cycle(); // main animation loop
    },
    cycle: function() {
        this.debug(); // print framerate
        startTime = new Date; // start fps time
        this.clear(); // celar canvas       
        this.draw(); // draw frame
        endTime = new Date; // end fps time
        setTimeout(function() {
            endTimeWithSleep = new Date; // end fps time with sleep
            this.realFPS = 1000 / (endTimeWithSleep - startTime);
            this.cycle(); // repeat animation loop
        }.bind(this), (1000 / this.FPSLimit) - (endTime - startTime));
    },
    debug: function() {
        $('.DebugScreen').html('<b>FPS:</b> ' + Math.round(this.realFPS*1)/1);
    },
    clear: function() {
        canvas.width = canvas.width; // clear canvas
    },
    draw: function() {
        Location.drawSurface(); // draw tiles
    },
}
var Location = {
    width: 60,
    height: 120,
    drawSurface: function() {
        for (y = 0; y < this.height; y++) {
            for (x = 0; x < this.width; x++) {
                if ((y % 2) == 0) {
                    rowLeftPadding = 0;
                } else {
                    rowLeftPadding = Game.tileScaleX / 2;
                }
                context.drawImage(imgObj, (x * Game.tileScaleX + rowLeftPadding), y * (Game.tileScaleY / 2), Game.tileScaleX, Game.tileScaleY);
            }
        }
    },
}
Game.init(); // start game
});

如果我设置了Location。宽度和位置。高度到低的数字,然后它运行速度快(50 fps),但在这个例子中(Location.width = 60, Location.height = 120)帧率是10 fps,我需要50 fps,你有什么建议如何加快这个脚本?

1)在我看来,你在画每一块瓷砖,即使它们不在视野中。使用"剪切"。在调用context.drawImage()之前,您需要计算tile是否在视图中。

2)如果你的场景是静态的,提前计算它(尽可能多)。然而,创建一个巨大的图像也不是一个好主意,你宁愿预先计算一些大块(即512x512)。

3)在一些浏览器中,据说你可以得到更好的帧率,如果不是使用'setTimeout()',你使用requestAnimationFrame(我也发现这篇文章很有趣)。

4)调整大小/缩放可能会影响性能(特别是在较旧的浏览器或硬件)。如果你的贴图已经是32x64,你可以使用drawImage()只有3个参数,避免调整大小(不适用,如果你需要缩放实现缩放效果或类似)。

除了@jjmontes的优秀答案,你还应该在游戏中使用多个画布元素,并且只更新画布中已更改的部分。现在你每次都在清理和重画所有的东西。

在我这边弄乱了你的代码之后,我得到了45-50之间的代码。一个建议是不要使用jQuery,也不要修改元素的html来显示fps。我还修改了你的演示,使其最大帧数为100帧,它的帧数约为70帧/秒。

您也可以尝试缓存调整大小的图像并使用它,您应该会看到性能的提高。在下面的演示中,我将调整大小的图像缓存在临时画布上,并使用它来代替。

实时演示(我不想为图像实现onload,所以如果它是一个白屏,就再次点击运行)