Ball gets trapped inside the paddle

时间:2016-12-02 05:07:27

标签: javascript html css canvas

I'm trying to make a video game like ping pong.

I've drawn the paddle and the ball using the rect() and arc() functions respectively. These are drawn on the HTML <canvas> element. Event handlers are attached to the document for the up and down arrow keys. These allow to be able to move the paddle. The ball's x and y coordinates are changed after 10 milliseconds using the setInterval() function.

The issue I'm having is that sometimes the ball gets trapped in the paddle and starts moving in a zigzag fashion inside it.

How can I fix this? I want to change the x velocity of the ball as soon as it hits the front of the paddle and its y velocity if it hits its sides.

Here's my code:

<!-- index.html -->
<html>
    <head>
        <link type="text/css" rel="stylesheet" href="stylesheet.css"/>
    </head>
    <body>
        <canvas id="my-canvas" height="300px" width="400px"></canvas>

        <script src="jquery-3.1.1.min.js"></script>
        <script src="script.js"></script>
    </body>
</html>

/* stylesheet.css */
body {
    background-color: #f00;
}

canvas {
    background-color: #fff;
}

/* script.js */
$(document).ready(function () {
    var canvas = $("#my-canvas")[0];
    var ctx = canvas.getContext("2d");
    var paddleHeight = 8;
    var paddleWidth = 70;
    var paddleY = (canvas.height - paddleWidth) / 2;
    var ballRadius = 8;
    var ballX = canvas.width / 2;
    var ballY = canvas.height / 2;
    var xDir = 2;
    var yDir = -2;
    var upPressed = false;
    var downPressed = false;

    $(document).keydown(function (e) {
        switch (e.which) {
            case 38:
                upPressed = true;
                break;
            case 40:
                downPressed = true;
        }
    });

    $(document).keyup(function (e) {
        switch (e.which) {
            case 38:
                upPressed = false;
                break;
            case 40:
                downPressed = false;
        }
    });

    function drawPaddle () {
        ctx.beginPath();
        ctx.rect(0, paddleY, paddleHeight, paddleWidth);
        ctx.fillStyle = "#0f0";
        ctx.fill();
        ctx.closePath();
    }

    function drawBall () {
        ctx.beginPath();
        ctx.arc(ballX, ballY, ballRadius, 0, Math.PI*2);
        ctx.fillStyle = "#00f";
        ctx.fill();
        ctx.closePath();
    }

    function draw () {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        drawPaddle();

        ballX += xDir;
        ballY += yDir;

        // Collision detection with the sides of the canvas
        if (ballY == canvas.height - ballRadius || ballY == ballRadius) {
            yDir = -yDir;
        } else if (ballX == ballRadius || ballX == canvas.width - ballRadius) {
            xDir = -xDir;
        }

        // Collision detection with the front of the paddle
        if (ballX == paddleHeight + ballRadius && ballY >= paddleY && ballY <= paddleY + paddleWidth) {
            xDir = -xDir;
        }
        // Collision detection with the top side of the paddle
        if (ballX < paddleHeight + ballRadius && ballY < paddleY && ballY >= paddleY - ballRadius) {
            yDir = -yDir;
        }
        // Collision detection with the bottom side of the paddle
        if (ballX < paddleHeight + ballRadius && ballY > paddleY + paddleWidth && ballY <= paddleY + paddleWidth + ballRadius) {
            yDir = -yDir;
        }

        drawBall();

        // Paddle moving logic
        if (downPressed && paddleY < canvas.height - paddleWidth) {
            paddleY += 7;
        } else if (upPressed && paddleY > 0) {
            paddleY -= 7;
        }
    }

    setInterval(draw, 10);
});

1 个答案:

答案 0 :(得分:0)

Maybe:

<!-- index.html -->
<html>
    <head>
        <link type="text/css" rel="stylesheet" href="stylesheet.css"/>
    </head>
    <body>
        <canvas id="my-canvas" height="300px" width="400px"></canvas>

        <script src="jquery-3.1.1.min.js"></script>
        <script src="script.js"></script>
    </body>
</html>

/* stylesheet.css */
body {
    background-color: #f00;
}

canvas {
    background-color: #fff;
}

/* script.js */
$(document).ready(function () {
    var canvas = $("#my-canvas")[0];
    var ctx = canvas.getContext("2d");
    var paddleHeight = 8;
    var paddleWidth = 70;
    var paddleY = (canvas.height - paddleWidth) / 2;
    var ballRadius = 8;
    var ballX = canvas.width / 2;
    var ballY = canvas.height / 2;
    var xDir = 2;
    var yDir = -2;
    var upPressed = false;
    var downPressed = false;

    $(document).keydown(function (e) {
        switch (e.which) {
            case 38:
                upPressed = true;
                break;
            case 40:
                downPressed = true;
        }
    });

    $(document).keyup(function (e) {
        switch (e.which) {
            case 38:
                upPressed = false;
                break;
            case 40:
                downPressed = false;
        }
    });

    function escapePaddle() {
      // I copy and pasted your collision logic and composed a super long condition. Brace yourself...
      while ((ballX == paddleHeight + ballRadius && ballY >= paddleY && ballY <= paddleY + paddleWidth) || (ballX < paddleHeight + ballRadius && ballY < paddleY && ballY >= paddleY - ballRadius) || (ballX < paddleHeight + ballRadius && ballY > paddleY + paddleWidth && ballY <= paddleY + paddleWidth + ballRadius)) {
        ballX+= xDir;
        ballY += yDir;
      }
    }

    function drawPaddle () {
        ctx.beginPath();
        ctx.rect(0, paddleY, paddleHeight, paddleWidth);
        ctx.fillStyle = "#0f0";
        ctx.fill();
        ctx.closePath();
    }

    function drawBall () {
        ctx.beginPath();
        ctx.arc(ballX, ballY, ballRadius, 0, Math.PI*2);
        ctx.fillStyle = "#00f";
        ctx.fill();
        ctx.closePath();
    }

    function draw () {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        drawPaddle();

        ballX += xDir;
        ballY += yDir;

        // Collision detection with the sides of the canvas
        if (ballY == canvas.height - ballRadius || ballY == ballRadius) {
            yDir = -yDir;
        } else if (ballX == ballRadius || ballX == canvas.width - ballRadius) {
            xDir = -xDir;
        }

        // Collision detection with the front of the paddle
        if (ballX == paddleHeight + ballRadius && ballY >= paddleY && ballY <= paddleY + paddleWidth) {
            xDir = -xDir;
            escapePaddle();
        }
        // Collision detection with the top side of the paddle
        if (ballX < paddleHeight + ballRadius && ballY < paddleY && ballY >= paddleY - ballRadius) {
            yDir = -yDir;
            escapePaddle();
        }
        // Collision detection with the bottom side of the paddle
        if (ballX < paddleHeight + ballRadius && ballY > paddleY + paddleWidth && ballY <= paddleY + paddleWidth + ballRadius) {
            yDir = -yDir;
            escapePaddle();
        }

        drawBall();

        // Paddle moving logic
        if (downPressed && paddleY < canvas.height - paddleWidth) {
            paddleY += 7;
        } else if (upPressed && paddleY > 0) {
            paddleY -= 7;
        }
    }

    setInterval(draw, 10);
});

I added an escapePaddle() function that basically moves the ball until it is not colliding with the paddle. Then I added to all the paddle collision test conditions.