可绘制圆圈之间的javascript碰撞检测

时间:2012-10-18 10:39:17

标签: javascript html5 canvas drag-and-drop collision


首先,请不要对我的英语过于挑剔。我不是母语人士。我希望我能解释自己从未如此!此外,我读到我应该表明我已经做了一些努力来自己解决给定的问题。为了证明这一点,我的帖子变得相对较长。

我想做什么:

我是新手(三周)到javascript,我尝试通过html5 canvas和javascript构建一个游泳池台球桌。最后,用户应该能够通过拖动十六个球来在虚拟池桌面上呈现某种游戏情况。我在stackoverflow上发现了很多关于路径和拖拽的提示。下降。

已经有效的方法:

此时圆圈几乎看起来像是水池球,我可以用鼠标移动它们。到目前为止一切都很好。

问题是什么:

当然,池球碰撞实际并且不会重叠。关于碰撞检测,我发现了一个有用的帖子,告诉我使用Pythagorean therm a * a + b * b = c * c来做这件事。我理解这个概念。我绝对不明白的是我必须在我的代码中实现检测。在我的脚本中有一个函数(moveBall00(e)),如果球被拖动(dragok = true),它会计算新的x和y坐标。但是,如何在同时计算拖动球的新坐标的同时计算球之间的距离?这很容易成为新手问题!

我试过了:

  1. 新变量“x”

    var x = true;

  2. 检测球间距离的新功能

    function collision(){     if((Math.pow(bp [1] [0] - bp [1] [1],2))+(Math.pow(bp [2] [0] - bp [2] [1],2) )< = 576){         x =假;     } }

  3. 每10毫米调用“collision()”

    (function isIntersecting(){     return setInterval(collision,10); })();

  4. 如果“x = true”

    ,则仅拖动球

    function moveBall00(e){     if(dragok&& x){         bp [1] [0] = e.pageX - canvas.offsetLeft;         bp [2] [0] = e.pageY - canvas.offsetTop;     } }

  5. 结果是圆圈(球)重叠直到它们休息。他们覆盖的越多,我拖得更快。这接缝是第一个问题?!

    对于经验丰富的开发人员来说,最重要的是在公园散步,但不适合我。

    我是坚持不懈的类型,并会学习在javascript中做这些事情,但目前我不知道如何解决上述问题。

    我很感激任何帮助,这将在未来的结果发布!

    这是我到目前为止所做的:

    (为了简化它,只有白球是可绘制的。)

    <!doctype html>
    
    <html>
    
        <head>
        <meta charset="UTF-8" />
                <title>Collision detection</title>
        </head>
    
        <body>
    
                <canvas id="pooltable" width="1200" height="660">This text is displayed if your browser does not support HTML5 Canvas</canvas>
    
            <script>
    
                var canvas;
                var ctx;
                var width = 1200;
                var height = 660;
                var dragok = false;
    
                var bp = new Array();
                    // color of balls "ballColor"
                    bp[0] = new Array("rgba(255,255,255,1)","rgba(231,214,8,1)");
                    // x-position of balls "xBallPosition"
                    bp[1] = new Array(20,50);
                    // y-position of balls "yBallPosition"
                    bp[2] = new Array(50,50);
                    // color of stripes "stripe"
                    bp[3] = new Array("rgba(255,255,255,0)","rgba(231,214,8,1)");
                    // color of stripe strokes "stripeStroke"
                    bp[4] = new Array("rgba(255,255,255,0)","rgba(231,214,8,1)");
                    // ball numbers "ballNumber"
                    bp[5] = new Array(" ","1");
                    // position of ball numbers "positionBallNumber"
                    bp[6] = new Array();
    
                function init() {
                    canvas = document.getElementById("pooltable");
                    ctx = canvas.getContext("2d");
                    return setInterval(draw, 1);
                }
    
                function clear() {
                    ctx.clearRect(0, 0, width, height);
                }
    
                function rect(x,y,w,h) {
                    ctx.beginPath();
                    ctx.rect(x,y,w,h);
                    ctx.closePath();
                    ctx.fill();
                }
    
                function ball(ballColor, xBallPosition, yBallPosition, ballRadius, angle, stripe, stripeStroke, circleRadius, ballNumber, positionBallNumber) {
    
                    ctx.fillStyle = ballColor;
                    ctx.shadowBlur = 5;
                    ctx.shadowColor = "rgba(0,0,0,1)";
                    ctx.beginPath();
                    ctx.arc(xBallPosition, yBallPosition, ballRadius, angle, Math.PI * 2, true);
                    ctx.closePath();
                    ctx.fill();
    
                    ctx.fillStyle = stripe;
                    ctx.strokeStyle = stripeStroke;
                    ctx.shadowColor = "rgba(0,0,0,0)";
                    ctx.beginPath();
                    ctx.moveTo(xBallPosition - 7, yBallPosition - 8);
                    ctx.bezierCurveTo(xBallPosition - 8, yBallPosition - 13, xBallPosition + 8, yBallPosition - 13, xBallPosition + 7, yBallPosition - 8);
                    ctx.lineTo(xBallPosition + 7, yBallPosition + 8);
                    ctx.bezierCurveTo(xBallPosition + 8, yBallPosition + 13, xBallPosition - 8, yBallPosition + 13, xBallPosition - 7, yBallPosition + 8);
                    ctx.closePath();
                    ctx.stroke();
                    ctx.fill();
    
                    ctx.fillStyle =  "rgba(255,255,255,1)";
                    ctx.shadowColor = "rgba(0,0,0,0)";
                    ctx.beginPath();
                    ctx.arc(xBallPosition, yBallPosition, circleRadius, angle, Math.PI * 2, true);
                    ctx.closePath();
                    ctx.fill();
    
                    ctx.fillStyle = "rgba(0,0,0,1)";
                    ctx.font = "normal normal lighter 7px Helvetica";
                    ctx.textBaseline = "middle";
                    ctx.fillText(ballNumber, xBallPosition - positionBallNumber, yBallPosition + 1);
    
                    var gradient = ctx.createRadialGradient(xBallPosition, yBallPosition, 1, xBallPosition + 3, yBallPosition + 3, 12);
                    gradient.addColorStop(0, "rgba(255,255,255,0.6)");
                    gradient.addColorStop(1, "rgba(0,0,0,0.2)");
                    ctx.fillStyle = gradient;
                    ctx.strokeStyle = "rgba(0,0,0,0.4)";
                    ctx.shadowColor = "rgba(0,0,0,0)";
                    ctx.beginPath();
                    ctx.arc(xBallPosition, yBallPosition, ballRadius, angle, Math.PI * 2, true);
                    ctx.closePath();
                    ctx.stroke();
                    ctx.fill();
    
                }
    
                function draw() {
    
                    clear();
    
                    table = new rect(0,0,width,height);
    
                    ball00 = new ball(bp[0][0], bp[1][0], bp[2][0], 12, 0, bp[3][0], bp[4][0], 6, bp[5][0], 0);
                    ball01 = new ball(bp[0][1], bp[1][1], bp[2][1], 12, 0, bp[3][0], bp[4][1], 6, bp[5][1], 2);
    
                }
    
                function myDown(e) {
                    if (e.pageX < bp[1][0] + 6 + canvas.offsetLeft && e.pageX > bp[1][0] - 6 + canvas.offsetLeft && e.pageY < bp[2][0] + 6 + canvas.offsetTop && e.pageY > bp[2][0] - 6 + canvas.offsetTop) {
                        bp[1][0] = e.pageX - canvas.offsetLeft;
                        bp[2][0] = e.pageY - canvas.offsetTop;
                        dragok = true;
                        canvas.onmousemove = moveBall00;
                    }
                    else {
                        dragok = false;
                    }
                }
    
                function myUp() {
                    dragok = false;
                    canvas.onmousemove = null;
                }
    
                function moveBall00(e) {
                    if (dragok) {
                        bp[1][0] = e.pageX - canvas.offsetLeft;
                        bp[2][0] = e.pageY - canvas.offsetTop;
                    }
                }
    
                init();
    
                canvas.onmousedown = myDown;
                canvas.onmouseup = myUp;
    
            </script>
    
        </body>
    
    </html>
    

1 个答案:

答案 0 :(得分:5)

您面临的问题与底层渲染技术完全无关。这只是一个数学问题。

你基本上想要做的是计算你拖动的球和桌子上的任何球之间的距离。如果距离太短,则发生碰撞。

对于两个对象,这很简单,你需要三个值:球的x和y坐标及其半径。

var ball = {
    x: 100,
    y: 100
    r: 10
};

要计算距离,请执行以下操作:

var squareX = Math.pow(Math.abs(ballA.x - ballB.x), 2);
var squareY = Math.pow(Math.abs(ballA.y - ballB.y), 2);
var hypothenuse = Math.sqrt(squareX + squareY);
var distance = hypothenuse - ballA.r - ballB.r;

if (distance >= 0) {
    // new position is valid
}

由于你在台球桌上有许多球,你需要为桌子上的每个球调用一次这个代码,这个球不会被移动以比较所有球。

function canMove(ballA, ballB) {
    var squareX = Math.pow(Math.abs(ballA.x - ballB.x), 2);
    var squareY = Math.pow(Math.abs(ballA.y - ballB.y), 2);
    var hypothenuse = Math.sqrt(squareX + squareY);
    var distance = hypothenuse - ballA.r - ballB.r;

    if (distance >= 0) {
        return true;
    }
    return false;
}


function canDrag(ball, balls) {
    var isMovable = true;
    for (var i = balls.length-1; i >= 0; i--) {
        isMovable = canMove(ball, balls[i]);
        if (!isMovable) {
            return false;
        }
    }
    return true;
}

在最后一个片段中,我假设您的球对象存储在球阵列中。我希望这会有所帮助。