JavaScript中的重叠/碰撞测试

3
我正在尝试在以下代码中实现命中测试/重叠测试。该代码在画布上随机创建200个圆,我试图将圆的位置存储在一个数组中,并在for循环中每次创建另一个圆时检查该数组,如果随机创建的x和y与已创建的圆太接近,则应继续获取新的随机x和y,直到它不太接近已创建的圆。
但是,在while循环中,我无法将其正常工作。
请帮忙解决问题...
谢谢
    <script type="text/javascript">

    document.addEventListener("DOMContentLoaded", canvasDraw);


    function canvasDraw () {
    var c = document.getElementById("canvas");
    var w = window.innerWidth;
    var h = window.innerHeight;
    c.width = w;
    c.height = h;

    var ctx = c.getContext("2d");
    ctx.clearRect(0,0,c.width, c.height);
    var abc = 0;

    var colours = new Array ("rgb(0,100,0)", "rgb(51,102,255)");
    var positions = new Array();


    function hitTest(x, y) {
    for(var p in positions) {
            pp = p.split(",");
        pp[0] = parseInt(pp[0]);
        pp[1] = parseInt(pp[1]);

        if(((x > (pp[0] - 24)) && (x < (pp[0] + 24))) && ((y > (pp[1] - 24)) && (y < (pp[1] + 24)))) {

            return true;
        }
    }
    return false;
}


            //Loop 200 times for 200 circles
    for (i=0; i<200; i++) {

        var x = Math.floor(Math.random()*c.width);
        var y = Math.floor(Math.random()*c.height);

        while(hitTest(x, y) == true){
            var x = Math.floor(Math.random()*c.width);
            var y = Math.floor(Math.random()*c.height);
        }

        var pos = x.toString() + "," + y.toString();
        positions.push(pos);

        var radius = 10;
        var r = radius.toString();

        var b = colours[Math.floor(Math.random()*colours.length)];

        circle(ctx,x,y, radius, b);

    }   
   }



    function circle (ctx, x, y, radius, b) {
  ctx.fillStyle = b;
  ctx.beginPath();
  ctx.arc(x, y, radius, 0, Math.PI*2, true);
  ctx.closePath();
  ctx.fill();
   }
  </script>


你的圆形半径永远都会保持一致吗? - Phrogz
1个回答

3

在开始之前,有几点需要注意:

  1. 不要使用new Array()创建数组,除非你指定了初始长度。使用[]代替;
  2. 不要使用for...in遍历数组:使用带计数器的标准for循环。这是一个好习惯;
  3. 将数字转换为字符串再转回数字是无用且昂贵的。使用一个小数组来存储这两个值;
  4. 不要使用“魔法数字”,即具有特定值但难以立即识别的数字。使用命名的“常量”或在每个数字旁边放置注释以告知它们的含义,以便未来维护。

好的,让我们看看代码。

if(((x > (pp[0] - 24)) && (x < (pp[0] + 24))) && ((y > (pp[1] - 24)) && (y < (pp[1] + 24))))

老实说,这是什么?我会称之为一个古怪而晦涩的片段。回想一下你在学校所学到的知识:
var dx = pp[0] - x, dy = pp[1] - y;
if (dx * dx + dy * dy < 400) return true;

它不是更加清晰了吗?

让我们看看整个函数:

function canvasDraw () {
    var c = document.getElementById("canvas");
    var w = window.innerWidth;
    var h = window.innerHeight;
    c.width = w;
    c.height = h;

    var ctx = c.getContext("2d");
    ctx.clearRect(0,0,c.width, c.height);
    // Lolwut?
    // var abc = 0;

    var colours = ["rgb(0,100,0)", "rgb(51,102,255)"];
    var positions = [];


    function hitTest(x, y) {
        for (var j = 0; j < positions.length; j++) {
            var pp = positions[j];
            var dx = pp[0] - x, dy = pp[1] - y;
            if (dx * dx + dy * dy < 400) return true;
        }
        return false;
    }


    // You declare the radius once and for all
    var radius = 10;
    // Declare the local scoped variables. You forgot i
    var x, y, i;
    for (i=0; i<200; i++) {

        // How about a do...while instead of a while?
        do {
            var x = Math.floor(Math.random()*c.width);
            var y = Math.floor(Math.random()*c.height);
        // Testing with === is faster, always do it if you know the type
        // I'll let it here, but if the type is boolean, you can avoid testing
        // at all, as in while (hitTest(x, y));
        } while (hitTest(x, y) === true);

        positions.push([x, y]);

        // This instruction is useless
        // var r = radius.toString();

        var b = colours[Math.floor(Math.random()*colours.length)];

        circle(ctx,x,y, radius, b);

    }   
}

注意,根据画布的尺寸不同,可能已经没有空间来放置另一个圆形了,这会导致无限循环。试着把半径为 10 的 200 个圆形放进一个 40 x 40 的方框里...

还有另一个需要测试的步骤,而且可能比较复杂。


+1 特别是针对距离平方进行测试,而不涉及不必要的 Math.sqrt 调用。 - Phrogz
谢谢你的回复。但是在一个足够大的画布上放置了200个圆,它们仍然有重叠的部分,我无法确定哪里出了问题。 - user1294320
啊咔嚓!我给你的问题点了个赞,这样你就有了更多的声望。但是我注意到你还问了另一个问题,别忘了也去查看那里的答案。 - MaxArt
说“更好的做法”而不是“更好的做法”,这是一个良好的实践。 - WKx
@WKx 我说的是“更好的实践”,而不是“更好的实践” ;) - MaxArt
显示剩余5条评论

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