【问题标题】:bounce check function for HTML5 canvas fails at cornersHTML5 画布的弹跳检查功能在角落处失败
【发布时间】:2023-03-18 08:36:01
【问题描述】:

我有一个 HTML5 画布,每次单击它时都会生成一个弹跳框。盒子数组存储每个创建的盒子的 x 值、y 值、x 速度和 y 速度。盒子最初会沿随机方向移动,并且会在画布的两侧反弹,但如果它撞到角落,盒子就会消失而不是弹回。编辑:我回答了我自己的问题,注意到 soundY 和 soundX 函数导致了问题。

var box = new Array();
var width  = window.innerWidth;
var height = window.innerHeight;
var field = document.getElementById('canvas');

field.width  = width;
field.height = height; 
field.ctx = field.getContext('2d');
field.ctx.strokeStyle = 'rgba(255,255,255,1)'; 
setInterval('redraw()', 200);
addEventListener('click', createBox, false);

function createBox(e) { // this box will always fail collision detection at the upper-left corner
  box.push(100); // x-value is normally mouse position
  box.push(100); // y-value is normally mouse position
  box.push(-5); // x-speed is normally random
  box.push(-5); // y-speed is normally random
}

function redraw() {
  field.ctx.clearRect(0,0,width,height); 

  for(var i = 0; i < box.length; i+=4) {
         if(box[i] < 0)        { box[i+2] *= -1; soundY(box[i+1]); } // parameter of soundY is less than 0 
    else if(box[i] > width)    { box[i+2] *= -1; soundY(box[i+1]); } // which is invalid and causes this to break

         if(box[i+1] < 0)      { box[i+3] *= -1; soundX(box[i]); }
    else if(box[i+1] > height) { box[i+3] *= -1; soundX(box[i]); }

    box[i] += box[i+2];
    box[i+1] += box[i+3];
    field.ctx.strokeRect(box[i], box[i+1], 4, 4);
  }
}

function soundX(num) {
  // play a sound file based on a number between 0 and width
}

function soundY(num) {
  // play a sound file based on a number between 0 and height
}

【问题讨论】:

  • 你有相应的 HTML 来配合这个吗?

标签: javascript html animation canvas collision-detection


【解决方案1】:

我可以重现该问题的唯一方法是在其中一个角生成盒子,以便在正确的 x 和 y 速度下,盒子最初是在画布边界之外创建的。发生这种情况时,速度的反转不足以将项目带回边界,等等下一帧速度再次反转(等等)。

我认为这可能会解决您的问题:

        var boxes = [];
        var boxSize = 4;
        var width = window.innerWidth;
        var height = window.innerHeight;
        var field = document.getElementById('canvas');

        function redraw() {
            field.ctx.clearRect(0, 0, width, height);
            var box;
            for (var i = 0; i < boxes.length; i++) {

                box = boxes[i];
                field.ctx.strokeRect(box.x, box.y, boxSize, boxSize);

                if (box.x < 0) {
                    box.x = 0;
                    box.dx *= -1;
                } else if (box.x > width - boxSize) {
                    box.x = width - boxSize;
                    box.dx *= -1;
                }

                if (box.y < 0) {
                    box.y = 0;
                    box.dy *= -1;
                } else if (box.y > height - boxSize) {
                    box.y = height - boxSize;
                    box.dy *= -1;
                }

                box.x += box.dx;
                box.y += box.dy;
            }
        }

        field.width = width;
        field.height = height;
        field.ctx = field.getContext('2d');
        field.ctx.strokeStyle = 'rgba(0,0,0,1)';

        setInterval(redraw, 200);
        addEventListener('click', createBox, false);

        function createBox(e) {
            boxes.push({
                x: e.clientX - 10,
                y: e.clientY - 10, // arbitrary offset to place the new box under the mouse
                dx: Math.floor(Math.random() * 8 - boxSize),
                dy: Math.floor(Math.random() * 8 - boxSize)
            });
        }

我修复了您的代码中的一些错误并进行了一些更改以使其更具可读性(我希望如此)。最重要的是,我扩展了您的碰撞检测,以便它将框的坐标重置为画布的边界,以防速度将其带到外面。

创建了一个jsfiddle,如果需要进一步讨论,它可能会很方便。

【讨论】:

  • 我同意在碰撞后重置坐标会有所帮助。但我不明白为什么需要它。既然速度是恒定的,如果一个坐标过了一个阈值,然后倒退了一步,为什么只有两个坐标都受到影响才会失败呢?
  • 我更改了 setInterval 调用的第一个(函数)参数,因为通过字符串引用它会导致 jsfiddle 出现错误,否则这是您的测试代码 link,在我看来是工作(就像我说的,我无法重现这样的问题)。尽管与此问题无关,但我认为您应该查看在阵列上存储框的数据的方式。使用一个对象来表示每个框更易于阅读和维护。
  • 我发现实际上是其他代码导致了问题(见上文)。当 x 超出范围时,我正在根据 y 值播放声音,反之亦然。我猜如果我访问的 x 或 y 值无效,边界检查和更新代码可能会中断。不过,您的建议很有帮助。
【解决方案2】:

这是我遗漏的附加代码(请参阅编辑),假设它与问题无关,但删除代码解决了问题,因为看起来这个用例会导致这部分代码中的输入无效。

【讨论】:

    猜你喜欢
    • 2013-12-22
    • 1970-01-01
    • 2012-02-26
    • 1970-01-01
    • 2017-09-25
    • 1970-01-01
    • 2013-04-05
    • 1970-01-01
    • 2013-02-07
    相关资源
    最近更新 更多