画布上多个弹跳的正方形 - 清除画布

3
我用canvas和javascript创建了一个小型弹跳盒子演示。每个“盒子”类处理自己的更新和渲染。然而,我的问题在于在绘制下一帧之前清除画布。当盒子移动时,它可以很好地清除,但是在撞到墙壁后会留下痕迹。这里有一个fiddle链接:https://jsfiddle.net/dzuvL7ph/1/ 以下是我的代码:
function init(){
    window.box1 = new Box(50, 'red', 0, 0);
    window.box2 = new Box(50, 'blue', 400, 20);
    requestAnimationFrame(update);
}

function update() {
    window.box1.update();
    window.box2.update();

    requestAnimationFrame(update);
    requestAnimationFrame(render);
}

function render() {
    window.box1.render();
    window.box2.render();
}

// -------------------------------------------------------------------------------------------------------
// --
// -------------------------------------------------------------------------------------------------------
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.update = function(){
        this.x += this.velocityX;
        this.y += this.velocityY;
        this.collisionCheck();
    };
    this.render = function(){
        this.context.fillStyle = this.color;
        this.context.clearRect(this.x  - this.velocityX, this.y - this.velocityY, this.width, this.height);
        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;
        if(this.x > 800 - this.width || this.x < 0)
            this.velocityX *= -1;
    };
};

我猜这与 this.context.clearRect(this.x - this.velocityX, this.y - this.velocityY, this.width, this.height); 有关,但我搞不清我错在哪里了。

1
尝试使用 this.context.clearRect (0, 0, canvas.width, canvas.height) 来清除整个画布。但这会影响性能... - Rayon
1个回答

4

你每个方块都清理一次有点奇怪。通常,你会在每一帧上擦除整个画布https://jsfiddle.net/yb58fd47/

为什么会发生这种情况

你的update函数检查碰撞,这可能会反转速度分量。但是,你的render函数依赖于该速度分量准确地表示上一个速度。如果你不想清除整个画布,你可以跟踪盒子之前的实际速度(我添加了velocityXLastvelocityYLast):

function init(){
    window.box1 = new Box(50, 'red', 0, 0);
    window.box2 = new Box(50, 'blue', 120, 20);
    requestAnimationFrame(update);
}

function update() {
    window.box1.update();
    window.box2.update();
  
    requestAnimationFrame(update);
    requestAnimationFrame(render);
}

function render() {
    window.box1.render();
    window.box2.render();
}

// -------------------------------------------------------------------------------------------------------
// --
// -------------------------------------------------------------------------------------------------------
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.update = function(){
        this.x += this.velocityX;
        this.y += this.velocityY;
        this.velocityXLast = this.velocityX;
        this.velocityYLast = this.velocityY;
        this.collisionCheck();
    };
    this.render = function(){
        this.context.fillStyle = this.color;
        this.context.clearRect(this.x  - this.velocityXLast, this.y - this.velocityYLast, this.width, this.height);
        this.context.fillRect(this.x, this.y, this.width, this.height);
    };
    this.collisionCheck = function(){
        if(this.y > 150 - this.height || this.y < 0)
            this.velocityY *= -1;
        if(this.x > 400 - this.width || this.x < 0)
            this.velocityX *= -1;
    };
};

init();
canvas {border: 1px solid black}
<canvas id="canvas" width="400" height="150"></canvas>


我会更新这个答案,解释为什么出现那些伪影。 - Shomz
谢谢!我尝试在每次渲染时清除整个画布,但是它要么只渲染一个框,要么什么都不渲染。我无法正确地使清除/绘制顺序工作。 - Lewis
2
是的,我只是在写更新,但清除画布是标准操作。想象一下,如果画布上有一个背景——你没有办法在不重新生成每个框和背景的情况下对这些框进行动画处理。 - Shomz
@Shomz 哦,好的,这很有道理,谢谢!清除画布的技巧很棒,每次更新时重置宽度,我不知道那是可能的。 - Lewis
@Lewis,当你清除画布时,这是非常重要的。由于你只渲染了一个方框,我想象你是在方框的方法中进行清除操作,这就是为什么最后一个方框会同时擦除之前渲染的方框。是的,有3或4种清除画布的方法,它们的性能在每个浏览器版本中略有不同...但这只是纳秒级别的差异。 - Shomz
1
另外,清除整个画布的另一个原因是当方框重叠时,顶部的方框会擦掉底部方框的一部分(请参见我的片段,蓝色方框始终会擦掉红色方框的一部分)。这可以通过检查干净区域是否有其他东西来解决,但在我看来,随着对象数量的增加,这样做可能会变得非常复杂,不值得。 - Shomz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接