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

标签 javascript html canvas drag-and-drop collision


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

我想做什么:

我是 javascript 的新手(三周),我尝试通过 html5 canvas 和 javascript 构建台球 table 。最后,用户应该能够通过拖动 16 个球来在虚拟台球 table 上呈现特定的比赛情况。我在 stackoverflow 上发现了很多关于路径和拖放的提示。

已经有效的:

同时,圆圈看起来几乎像台球,我可以用鼠标移动它们。到目前为止一切顺利。

问题是什么:

当然,撞球在现实中会发生碰撞并且不会重叠。关于碰撞检测,我找到了一篇有用的帖子,告诉我使用毕达哥拉斯热力学 a*a + b*b = c*c 来做到这一点。我理解这个概念。我绝对不明白的是我必须在代码中的什么地方实现检测。在我的脚本中有一个函数 (moveBall00(e)),如果球被拖动 (dragok = true),它会计算新的 x 和 y 坐标。但是如何在计算被拖动球的新坐标的同时计算球与球之间的距离呢?这很容易成为新手问题!

我试过这个:

  1. 新变量“x”

    var x = true;

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

    函数碰撞(){ if((Math.pow(bp[1][0] - bp[1][1], 2)) + (Math.pow(bp[2][0] - bp[2][1], 2) ) <= 576 ) { x = 假; }

  3. 每 10 毫秒调用一次“collision()”

    (函数是交集(){ 返回设置间隔(碰撞,10); })();

  4. 只有在“x=true”时才拖动球

    函数 moveBall00(e) { 如果(德拉戈克 && x){ bp[1][0] = e.pageX - canvas.offsetLeft; bp[2][0] = e.pageY - canvas.offsetTop; }

结果是圆圈(球)重叠直到静止。我拖球越快,它们重叠得越多。这似乎是先有后有的问题?!​​

对于有经验的开发人员来说,步行穿过公园是最确定的,但对我来说不是。

我是一个坚持不懈的人,我会学习用 javascript 做这些事情,但目前我不知道如何解决上述问题。

我将不胜感激,并将在此发布 future 的结果!

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

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

<!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>

最佳答案

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

对于您的情况,您基本上想要做的是计算您拖动的球与桌面上任何球之间的距离。如果距离太短,就会发生碰撞。

对于两个对象来说这很简单,您需要三个值:球的 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
}

由于台球 table 上有许多球,因此您需要为 table 上未移动的每个球调用此代码一次以比较所有球。

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;
}

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

关于可绘制圆圈之间的javascript碰撞检测,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12952752/

相关文章:

javascript - HTML Canvas - 基于鼠标移动移动文本并显示后面的图层

javascript - jquery 用值关联数组替换选择选项

javascript - 如果元素有子 html 元素

javascript - javascript 旋转器内的标签不会点击

javascript - 在 Canvas 中使用javascript获取鼠标位置

javascript - 如何删除 Fabric 中之前添加的矩形对象?

javascript - 使用 JavaScript 和 Require.JS 选择 jQuery 1.9 或 2.0

javascript - 我如何修复 connect-flash 中的 div,它们始终处于事件状态(我使用的是哈巴狗)?

php - 无论如何捕获网页的打印并将其保存在服务器端?

javascript - 无法获取 img 宽度和高度 jQuery