【问题标题】:Javascript Canvas Drawing - Pixelated When Lots of MovementJavascript 画布绘图 - 大量运动时像素化
【发布时间】:2015-12-15 06:26:28
【问题描述】:

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

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

(小提琴中的第 67 行,var box = 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));
}

这是出于性能原因吗?有什么办法可以预防吗?当盒子重叠时似乎会发生这种情况,但很难说什么时候有这么多盒子。

【问题讨论】:

  • addBox 未定义
  • @RafałŁużyński 谢谢!修改了问题和代码/小提琴以否定该功能(不知道如何在 jsfiddle 上调用内联 js 语句)
  • 它对我来说很好,是否有可能不是“像素化”你的意思是运动口吃?
  • @ericjbasti 奇怪!它肯定看起来像素化(质量较低)。但是,我现在想知道这是否是一种眼花缭乱,因为当我尝试在其上使用 sn-p 工具时,渲染暂停时,它看起来很好。嗯!
  • 我能够获得超过 3000 个盒子而没有明显问题。我想知道您是否在浏览器和显示器之间遇到了 vsync 问题。您可以运行一些测试并查看结果testufo.com

标签: javascript html canvas drawing


【解决方案1】:

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

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

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

【讨论】:

  • 感谢您的回答,这一切都说得通。我需要研究解决碰撞问题,我认为这是因为盒子的速度在检查碰撞之前将其推过。也许我需要先检查碰撞,然后再移动盒子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-08
  • 1970-01-01
相关资源
最近更新 更多