使用HTML Canvas时如何将游戏重置为以前的状态

问题描述

这是我的乒乓球比赛。

一旦球击中左侧3次,比赛就结束了。

我想要一种可以在游戏结束后重置游戏并可以开始新游戏解决方案。

但是我发现很难做,也许是因为画布的行为异常。 这个问题有解决办法吗?

并且重置鼠标悬停后,该东西也会停止工作

  • 请注意,我在HTML文件点击事件中的游戏开始和游戏结束消息框都使用了相同的功能
    let canvas = document.getElementById("canvas");
    let canvasX = 0,canvasY = 0;
    
    canvas.width = window.innerWidth - 100;
    canvas.height = window.innerHeight - 100;
    
    // Game logic
    let tick;
    let gameEnd = false;
    let mistakeCount = 0;
    let playerHeights = 150;
    let executed = false;
    let ctx = canvas.getContext("2d");
    ctx.fillStyle = "blue";
    
    // canvas
    let cw = canvas.width;
    let ch = canvas.height;
    ctx.fillRect(canvasX,canvasY,cw,ch);
    
    // player who is playing
    let playerPos = ch / 2;
    ctx.fillStyle = "white";
    ctx.fillRect(10,playerPos,10,playerHeights);
    
    // ball position
    let ballX = cw / 2,ballY = ch / 2,ballHorizontalDirection = true,//right side
        ballAngle = 5; // The amount of pixels the ball has to move upwards
    
    ctx.fillStyle = "white";
    ctx.beginPath();
    ctx.arc(ballX,ballY,2 * Math.PI);
    ctx.fill();
    ctx.closePath();
    
    // computer player
    let computerPos = ch / 2;
    ctx.fillStyle = "white";
    ctx.fillRect(cw - 20,computerPos,playerHeights);
    
    function gameloop(buttonId) {
        document.addEventListener("mousemove",(e) => {
            // e.clientX,e.clientY
            playerPos = e.clientY;
        });
        document.getElementById(buttonId).style.display = "none";
        let i = 0;
        draw();
    }
    
    function resetTheGame() {
        cancelAnimationFrame(tick);
        document.getElementById("gameover").style.display = "flex";
        executed = false;
        gameEnd = false;
        mistakeCount = 0;
        playerPos = ch / 2;
        ballX = cw / 2;
        ballY = ch / 2;
        ballHorizontalDirection = true; //right side
        ballAngle = 5;
        computerPos = ch / 2;
    }
    
    function checkForPlayerCollision() {
        if (ballX <= 25 && ballY < playerPos + playerHeights && ballY > playerPos) {
            ballHorizontalDirection = !ballHorizontalDirection;
            let firstHalf = playerPos + playerHeights / 2;
            if (ballY > firstHalf + 20) {
                ballAngle = 5;
            } else if (ballY > firstHalf - 20 && ballY < firstHalf + 20) {
                ballAngle = 0;
            } else {
                ballAngle = -5;
            }
        }
        if (ballX >= cw - 20) {
            ballHorizontalDirection = !ballHorizontalDirection;
        }
    }
    
    function selectBallPosition() {
        if (ballHorizontalDirection) {
            ballX += 5;
        } else {
            ballX -= 5;
        }
    }
    
    function gameEnds() {
        if (!executed) {
            if (ballX >= cw || ballX <= 5) {
                if (mistakeCount == 2) {
                    alert("Game End");
                    executed = true;
                    resetTheGame();
                    return true;
                }
                ballHorizontalDirection = !ballHorizontalDirection;
                mistakeCount++;
                return false;
            }
            return false;
        }
        return true;
    }
    
    function setPlayerPositions() {
        if (playerPos + playerHeights >= ch - 40 || playerPos <= 20) {
            playerPos = playerPos;
        }
        if (computerPos + playerHeights >= ch - 20 || computerPos <= 20) {
            computerPos = computerPos;
        }
    }
    
    function checkForTopBottomCollision() {
        if (ballY <= 10 || ballY >= ch - 20) {
            ballAngle = -1 * ballAngle;
        }
    }
    
    function draw() {
        cancelAnimationFrame(tick);
        ctx.clearRect(10,ch);
    
        // context
        ctx.fillStyle = "blue";
        ctx.fillRect(10,ch);
    
        // player
        ctx.fillStyle = "white";
        ctx.fillRect(10,playerHeights);
        ballY += ballAngle;
    
        // computer
        ctx.fillStyle = "white";
        ctx.fillRect(cw - 20,ballY - 20,playerHeights);
    
        // ball
        ctx.fillStyle = "white";
        ctx.beginPath();
        ctx.arc(ballX,2 * Math.PI);
        ctx.fill();
        ctx.closePath();
    
        // frame
        ctx.fillStyle = "gray";
        ctx.beginPath();
        ctx.linewidth = "20";
        ctx.rect(0,ch);
        ctx.stroke();
    
        // dotted line in between
        ctx.beginPath();
        ctx.linewidth = "1";
        ctx.setLineDash([20,5]);
        ctx.moveto(cw / 2,0);
        ctx.lineto(cw / 2,ch);
        ctx.stroke();
        ctx.setLineDash([]);
        ctx.closePath();
    
        // score board for player
        ctx.fillStyle = "skyblue";
        ctx.font = "100px Arial,Helvetica,sans-serif";
        ctx.fillText("0",cw / 2 - 150,ch / 2 + 35);
    
        // score board for computer
        ctx.fillText(mistakeCount,cw / 2 + 100,ch / 2 + 35);
    
        if (!gameEnd) {
            tick = requestAnimationFrame(draw);
            selectBallPosition();
            setPlayerPositions();
            checkForPlayerCollision();
            checkForTopBottomCollision();
            gameEnd = gameEnds();
        }
    }
    * {
        margin: 0;
        padding: 0;
        Box-sizing: border-Box;
        font-family: Arial,sans-serif;
    }
    
    body {
        width: 100vw;
        height: 100vh;
        display: flex;
        align-items: center;
        justify-content: center;
        background: rgba(0,255,0.5);
    }
    
    #gameover {
        display: none;
        width: 100vw;
        height: 100vh;
        align-items: center;
        justify-content: center;
        flex-direction: column;
        background-color: rgba(247,14,0.7);
    }
    
    #start {
        position: fixed;
        z-index: 1;
        width: 100vw;
        height: 100vh;
        line-height: 100vh;
        text-align: center;
        font-size: xx-large;
        background-color: rgba(14,247,0.7);
    }
    <head>
        <Meta charset="UTF-8">
        <Meta name="viewport" content="width=device-width,initial-scale=1.0">
        <title>Document</title>
        <link rel="stylesheet" href="style.css">
    </head>
    
    <body>
        <div id="start" onclick="gameloop('start')">
            Click any where to continue
        </div>
        <div id="gameover" onclick="gameloop('gameover')">
            Game Over! <br> Click any where to continue
        </div>
        <canvas id="canvas"></canvas>
        <script src="script.js"></script>
    </body>

解决方法

所以基本上我已经自己解决了这个问题。 除了使用单独的“ gameover” div来显示游戏结束,我还可以使用下面的给定代码。

@register.filter

从初始代码对代码所做的更改是

let canvas = document.getElementById("canvas");
let canvasX = 0,canvasY = 0;

canvas.width = window.innerWidth - 100;
canvas.height = window.innerHeight - 100;

// Game logic
let tick;
let gameEnd = false;
let mistakeCount = 0;
let playerHeights = 150;
let ctx = canvas.getContext("2d");
ctx.fillStyle = "blue";

// canvas
let cw = canvas.width;
let ch = canvas.height;
ctx.fillRect(canvasX,canvasY,cw,ch);

// player who is playing
let playerPos = ch / 2;
ctx.fillStyle = "white";
ctx.fillRect(10,playerPos,10,playerHeights);

// ball position
let ballX = cw / 2,ballY = ch / 2,ballHorizontalDirection = true,//right side
    ballAngle = 5; // The amount of pixels the ball has to move upwards

ctx.fillStyle = "white";
ctx.beginPath();
ctx.arc(ballX,ballY,2 * Math.PI);
ctx.fill();
ctx.closePath();

// computer player
let computerPos = ch / 2;
ctx.fillStyle = "white";
ctx.fillRect(cw - 20,computerPos,playerHeights);

function gameloop(buttonId) {
    document.addEventListener("mousemove",(e) => {
        // e.clientX,e.clientY
        playerPos = e.clientY;
    });
    document.getElementById(buttonId).style.display = "none";
    let i = 0;
    draw();
}

function resetTheGame() {
    mistakeCount = 0;
    ballX = cw / 2;
    ballY = ch / 2;
    ballHorizontalDirection = true;
}

function checkForPlayerCollision() {
    if (ballX <= 25 && ballY < playerPos + playerHeights && ballY > playerPos) {
        ballHorizontalDirection = !ballHorizontalDirection;
        let firstHalf = playerPos + playerHeights / 2;
        if (ballY > firstHalf + 20) {
            ballAngle = 5;
        } else if (ballY > firstHalf - 20 && ballY < firstHalf + 20) {
            ballAngle = 0;
        } else {
            ballAngle = -5;
        }
    }
    if (ballX >= cw - 20) {
        ballHorizontalDirection = !ballHorizontalDirection;
    }
}

function selectBallPosition() {
    if (ballHorizontalDirection) {
        ballX += 5;
    } else {
        ballX -= 5;
    }
}

function gameEnds() {
    if (ballX >= cw || ballX <= 5) {
        if (mistakeCount == 2) {
            resetTheGame();
            return true;
        }
        ballHorizontalDirection = !ballHorizontalDirection;
        mistakeCount++;
        return false;
    }
    return false;
}

function setPlayerPositions() {
    if (playerPos + playerHeights >= ch - 40 || playerPos <= 20) {
        playerPos = playerPos;
    }
    if (computerPos + playerHeights >= ch - 20 || computerPos <= 20) {
        computerPos = computerPos;
    }
}

function checkForTopBottomCollision() {
    if (ballY <= 10 || ballY >= ch - 20) {
        ballAngle = -1 * ballAngle;
    }
}

function draw() {
    cancelAnimationFrame(tick);
    ctx.clearRect(10,ch);

    // context
    ctx.fillStyle = "blue";
    ctx.fillRect(10,ch);

    // player
    ctx.fillStyle = "white";
    ctx.fillRect(10,playerHeights);
    ballY += ballAngle;

    // computer
    ctx.fillStyle = "white";
    ctx.fillRect(cw - 20,ballY - 20,playerHeights);

    // ball
    ctx.fillStyle = "white";
    ctx.beginPath();
    ctx.arc(ballX,2 * Math.PI);
    ctx.fill();
    ctx.closePath();

    // frame
    ctx.fillStyle = "gray";
    ctx.beginPath();
    ctx.lineWidth = "20";
    ctx.rect(0,ch);
    ctx.stroke();

    // dotted line in between
    ctx.beginPath();
    ctx.lineWidth = "1";
    ctx.setLineDash([20,5]);
    ctx.moveTo(cw / 2,0);
    ctx.lineTo(cw / 2,ch);
    ctx.stroke();
    ctx.setLineDash([]);
    ctx.closePath();

    // score board for player
    ctx.fillStyle = "skyblue";
    ctx.font = "100px Arial,Helvetica,sans-serif";
    ctx.fillText("0",cw / 2 - 150,ch / 2 + 35);

    // score board for computer
    ctx.fillText(mistakeCount,cw / 2 + 100,ch / 2 + 35);

    if (!gameEnd) {
        tick = requestAnimationFrame(draw);
        selectBallPosition();
        setPlayerPositions();
        checkForPlayerCollision();
        checkForTopBottomCollision();
        gameEnd = gameEnds();
    } else {
        cancelAnimationFrame(tick);
        ctx.clearRect(0,ch);
        // context
        ctx.fillStyle = "blue";
        ctx.fillRect(0,ch);
        ctx.fillStyle = "skyblue";
        ctx.font = "50px Arial,sans-serif";
        ctx.fillText("You Lose!",cw / 4,ch / 2);
        ctx.fillText("Click to continue",ch / 2 + 100);

        canvas.addEventListener("click",() => {
            tick = requestAnimationFrame(draw);
            gameEnd = false;
            canvas.removeEventListener("click");
        });
    }
}

并在此处添加一个else循环?


function resetTheGame() {
    mistakeCount = 0;
    ballX = cw / 2;
    ballY = ch / 2;
    ballHorizontalDirection = true;
}