Javascript Canvas 绘图 - 大量运动时像素化

Javascript Canvas Drawing - Pixelated When Lots of Movement

所以我仍在使用 HTML Canvas 和 Javascript 编写弹跳框演示。到目前为止,逻辑按预期工作(好消息!)- 然而,当 canvas 上有大量移动时,事情开始变得...像素化。这里有一个 fiddle 来证明我的意思 https://jsfiddle.net/hL8epzk3/2/

盒子数量目前是50个(问题很明显)。将数字降低到 20,一切看起来都很好!

(第67行在fiddle, var boxes = 20)

如果这是相关的,在 Google Chrome

中测试

我的代码

<!-- GAME WINDOW -->
<canvas id="canvas" width="800" height="600"></canvas>

<div id="menu">
    <button onclick="addBox();">Add Box</button>
</div>

Javascript

var Box = function(dimensions, color, x, y){
    this.width = dimensions;
    this.height = dimensions;
    this.x = x;
    this.y = y;
    this.velocityX = 10;
    this.velocityY = 10;
    this.color = color;
    this.context = document.getElementById('canvas').getContext('2d');
    this.possibleColors = ['#1abc9c', '#2ecc71', '#3498db', '#9b59b6', '#34495e', '#e67e22', '#c0392b', '#7f8c8d'];

    var that = this;

    this.update = function(){
        this.x += this.velocityX;
        this.y += this.velocityY;
        this.collisionCheck();
    };
    this.render = function(){
        this.context.fillStyle = this.color;
        this.context.fillRect(this.x, this.y, this.width, this.height);
    };
    this.collisionCheck = function(){
        if(this.y > 600 - this.height || this.y < 0){
            this.velocityY *= -1;
            this.generateColor();
        }
        if(this.x > 800 - this.width || this.x < 0){
            this.velocityX *= -1;
            this.generateColor();
        }
    };
    this.generateColor = function(){
        this.color = this.possibleColors[Math.floor((Math.random() * 10) - 1)];
    };

    function addBox(){
        console.log('box added');
    }

    window.renderLayer.addObject(this);
};

var RenderLayer = function(){
    this.objects = [];

    this.addObject = function(obj){
        this.objects[this.objects.length] = obj;
        console.log(this.objects[this.objects.length - 1]);
    };

    this.updateObjects = function(){
        for(var x = 0; x < this.objects.length; x++)
            this.objects[x].update();
    };

    this.renderObjects = function(){
        for(var x = 0; x < this.objects.length; x++)
            this.objects[x].render();
    };
};

function init(){
    window.renderLayer = new RenderLayer();

    window.box = [];
    var boxes = 20;

    for(var x = 0; x < boxes; x++){
        window.box[x] = new Box(50, 'red', Math.floor((Math.random() * 750) + 1),  Math.floor((Math.random() * 550) + 1));
    }

    requestAnimationFrame(update);
}

function update() {
    document.getElementById('canvas').width = document.getElementById('canvas').width;

    window.renderLayer.updateObjects();

    requestAnimationFrame(update);
    requestAnimationFrame(render);
}

function render() {
    window.renderLayer.renderObjects();
}

function addBox(){
    window.box[window.box.length] = new Box(50, 'red', Math.floor((Math.random() * 750) + 1),  Math.floor((Math.random() * 550) + 1));
}

这是出于性能原因吗?有什么办法可以预防吗?箱子重叠的时候好像是这样,但是箱子多了就很难说了。

没有发生像素化,如果您添加一个暂停按钮,或者通过将 canvas 复制到另一个并查看它来捕捉副本,您可以看到这一点。或者画圆圈而不是方框。它看起来像素化的原因是因为当盒子撞到墙上时你改变了它们的颜色,从而产生了一种奇怪的效果。不改变颜色会减少视错觉。你的弹跳也关闭了,盒子每次撞到墙上都会被部分剪掉,这也增加了错觉。

最后,您有导致页面锁定的危险,并最终通过在一个框架上调用 requestAnimationFrame 两次的方式抛出调用堆栈溢出。负载低时一切都很好,但随着负载增加并且帧时间超过帧时间的 1/60,首先您将开始在单独的帧上进行更新和渲染,然后请求将开始累积在调用堆栈上,导致更奇怪的行为并最终引发调用堆栈溢出。

每帧只调用一次requestAnimationFrame以避免这个问题。