javascript - Canvas 矩形和球碰撞不起作用

标签 javascript html canvas collision-detection

我正在制作一个 html5 Canvas 游戏,但遇到碰撞问题。 问题是,当球与任何平台碰撞时,球重力应为 -1,并以与平台相同的速度上升,但它仅适用于最后一个平台和左侧平台。我该如何修复它?谢谢!

HTML:

<html>
    <head>
        <title>Falldown</title>
    </head>
    <body>
      <canvas id="canvas" width = "380" height= "640"></canvas>  
      <script src="beta.js"></script>
    </body>
</html>

JS 代码:

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var isMenu = true;
var isPlaying = false;
var testing = true;
var pressingLeft = false;
var pressingRight = false;

var Platforms = [];

var difficulty = 1;

var gravity = 1;

var Player = {
    color: "red",
    radius: 7.5,
    stepY: 1.5,
    x: 175,
    y: 75
};

function RectCircleColliding(circle, rect) {
    var distX = Math.abs(circle.x - rect.x - rect.width / 2);
    var distY = Math.abs(circle.y - rect.y - 20 / 2);

    if (distX > (rect.width / 2 + circle.radius)) return false;
    if (distY > (20 / 2 + circle.radius)) return false;

    if (distX <= (rect.width / 2)) return true;
    if (distY <= (20 / 2)) return true;

    var dx = distX - rect.width / 2;
    var dy = distY - 20 / 2;
    return (dx * dx + dy * dy <= (circle.radius * circle.radius)); 
}

function drawBackground() {
    ctx.fillStyle = "black";
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    if (isMenu && !isPlaying) {
        createText("60px monospace", "white", "FallDown", 45, 130);
        createText("34px Arial", "white", "PLAY", 130, 260);
        createText("34px Arial", "white", "LEADERBOARD", 50, 340);
        createText("34px Arial", "white", "SETTINGS", 90, 420);
    } else {
        if (testing) {
            Platforms = [];
            for (var i = 0; i < 13; i++) {
                Platforms.push({
                    "x": 10,
                    "y": 160 + (i * 70),
                    "width": (Math.random() * canvas.width) - 60
                });
            }
            testing = false;
        }

        for (var i in Platforms) {
            ctx.fillStyle = "#00ffff";
            ctx.fillRect(10, Platforms[i].y, Platforms[i].width, 20);

            var totalTest = Platforms[i].width + 60;
            ctx.fillRect(totalTest + 30, Platforms[i].y, canvas.width - totalTest, 20);

            Platforms[i].y -= 1;

            if (RectCircleColliding(Player, Platforms[i])) {
                gravity = -1;
            } else {
                gravity = 1;
            }
        }

        detectBorderCollision();
        detectPlayerCollision();
        drawPlayer();
        drawBorder();

        if (Platforms.length === 7) Platforms = [];
    }
}

function detectBorderCollision() {
    if (Player.x > 370 - Player.radius) {
        Player.x = 370 - Player.radius;
    } else if (Player.x < 3.8 + Player.radius * 2) {
        Player.x = 3.8 + Player.radius * 2
    }
}

function detectPlayerCollision() {

}

function drawPlayer() {
    ctx.beginPath();
    ctx.fillStyle = Player.color;
    ctx.arc(Player.x, Player.y, Player.radius, 0, 2 * Math.PI);
    ctx.fill();
    ctx.closePath();

    Player.y += gravity;

    if (pressingRight) {
        Player.x += 2;
    } else if (pressingLeft) {
        Player.x -= 2;
    }

    /*
ctx.fillStyle = "#00ffff";
        ctx.fillRect(10, 160, 300, 20);
    */
}

function drawBorder() {
    ctx.beginPath();
    ctx.strokeStyle = "#00ffff";
    ctx.lineWidth = 10;
    ctx.moveTo(5, 0);
    ctx.lineTo(5, 640);

    ctx.moveTo(375, 0);
    ctx.lineTo(375, 640);
    ctx.stroke();
    ctx.closePath();
}

function createText(font, color, value, posX, posY) {
    ctx.font = font;
    ctx.fillStyle = color;
    ctx.fillText(value, posX, posY)
}

function isInside(realX, realY, x1, x2, y1, y2) {
    return (realX > x1 && realX < x2) && (realY > y1 && realY < y2)
}

function drawGame() {
    drawBackground();
}

function startDrawing() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drawGame();
    requestAnimationFrame(startDrawing);
}

function Init() {
    requestAnimationFrame(startDrawing);

    canvas.addEventListener("click", function(evt) {
        var rect = canvas.getBoundingClientRect();
        var mouseX = evt.clientX - rect.left;
        var mouseY = evt.clientY - rect.top;

        if (isMenu && !isPlaying) {
            if (isInside(mouseX, mouseY, 115, 230, 220, 270)) {
                isPlaying = true;
                isMenu = false;
            } else if (isInside(mouseX, mouseY, 35, 320, 300, 345)) {
                console.log("Leaderboard");
            } else if (isInside(mouseX, mouseY, 75, 270, 380, 430)) {
                console.log("Settings");
            }
        }

    });

    window.addEventListener("keydown", function(evt) {
        if (!isMenu && isPlaying) {
            if (evt.keyCode === 39) { // right
                pressingRight = true;
            } else if (evt.keyCode === 37) { // left
                pressingLeft = true;
            }
        }
    });

    window.addEventListener("keyup", function(evt) {
        if (!isMenu && isPlaying) {
            if (evt.keyCode === 39) { // right
                pressingRight = false;
            } else if (evt.keyCode === 37) { // left
                pressingLeft = false;
            }
        }
    });
}

Init();

最佳答案

您的代码中有太多魔数(Magic Number),调试起来既困难又乏味。将所有数字文字替换为描述值所代表含义的标识符。

drawBackground函数部分的以下修改会导致与左侧平台的所有碰撞正常工作,但并不完美。

var hasCollided;

for (var i in Platforms) {
    ctx.fillStyle = "#00ffff";
    ctx.fillRect(10, Platforms[i].y, Platforms[i].width, 20);

    var totalTest = Platforms[i].width + 60;
    ctx.fillRect(totalTest + 30, Platforms[i].y, canvas.width - totalTest, 20);

    Platforms[i].y -= 1;

    if (!hasCollided) { 
        if (RectCircleColliding(Player, Platforms[i])) {
            gravity = -1;
            hasCollided = true;
        } else {
            gravity = 1;
        }
    }
}

关于javascript - Canvas 矩形和球碰撞不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47607492/

相关文章:

javascript - Zurb Foundation 5 选项卡不起作用

canvas - Kinetic.JS - 无法更改图层的 z-index 顺序?

javascript - 使用 canvas API 复制 CSS border-radius

javascript - 在 JavaScript 中将纬度和经度映射到 Canvas 点

javascript - 如何在 React 的所有 child 中调用函数

php - 如何修改现有的 javascript 以显示包括美分在内的货币值?

javascript - 无法解析模块说明符 "three"。相对引用必须以 "/"、 "./"或 "../"开头

javascript - 用一组选项填充两个选择框?

javascript - 我想在选中某些复选框时增加一个值

Javascript:一旦 'class/object' 变为 'extended' ,是否可以使用不同的基数 'class/object' 重新扩展它?