如何检查 Javascript 中方形画布是否重叠?

How to check if square canvases are overlapping in Javascript?

我正在创建一个游戏,其中黄色方块必须穿过所有其他方块才能到达屏幕顶部。我无法测试方块是否重叠以重置黄色方块。我已经尝试实施在该网站上找到的其他方法,但 none 似乎有效,除非我实施错误。

现在,在方法 intersectRect(i) 中,我正在检查方块的边缘到玩家方块的边缘。

我遇到的另一个错误,虽然不是最重要但值得一提的是,当黄色方块到达屏幕顶部时,分数会上升很多值,而不仅仅是 1。

谢谢。

<html>

   <canvas id="gameCanvas" width="800" height="600">   
</canvas>

<script>

    var canvas;
    var canvasContext;


    //square variables
    var squares = [];
    var squareX = [50, 0, 640, 400, 575, 300, 373];
    var squareY = [100, 150,200, 250, 300, 350, 400];
    var forward = [true, true, true, true, true, true, true];
    var interval = [15, 15, 15, 15, 15, 15];
    const SQUARE_SIZE = 50;

    //player variables
    var player;
    var playerX = 0;
    var playerY = 0;
    var intervalPlayer = 0;
    const PLAYER_SIZE = 50;

    var score = 0;



    window.onload = function(){

        canvas=document.getElementById('gameCanvas');
        canvasContext = canvas.getContext('2d');

        function calcMousePos(evt){

            var rect = canvas.getBoundingClientRect();
            var root = document.documentElement;
            var mouseX = evt.clientX - rect.left - root.scrollLeft;
            var mouseY = evt.clientY - rect.top - root.scrollTop;
            return{
                x:mouseX,
                y:mouseY
            };
        }

        //get mouse movement
        canvas.addEventListener('mousemove', function(evt){

            var mousePos = calcMousePos(evt);

            playerX = mousePos.x;
            playerY = mousePos.y;

        });

        //update screen
        var framesPerSecond = 30;
        setInterval(function(){
              moveEverything();
              drawEverything();
        },1000/framesPerSecond);


    }

    //moves each square based on the interval
    function moveEverything(){

        for(var i = 0; i < squareX.length; i++){
             if(!forward[i]){
            forward[i] = false;
             if(interval[i] > 0){
                interval[i] *= -1;
            }

            if(squareX[i] < 0){
                forward[i] = true;    
            }
        }else if(forward[i]){
            if(interval[i] < 0){
                interval[i] *= -1;
            }

            if(squareX[i] > canvas.width - 50)
            {
                forward[i] = false;        
            }
        }else{
            console.log("Error ball " + i);    
        }

        }

    }

    //draws each square on the background canvas
    function drawEverything(){ 

        for(var i = 0; i < squareX.length; i++){
            squareX[i] += interval[i];
        }

        //background
        colorRect(0,0,canvas.width,canvas.height, 'salmon');

        //score
        canvasContext.fillStyle = 'black';
        canvasContext.fillText(score, 10, 10);

        //red square
        squares[0] = colorRect(squareX[0],squareY[0],SQUARE_SIZE,SQUARE_SIZE, 'red');
        //blue square
        squares[1] = colorRect(squareX[1],squareY[1],SQUARE_SIZE,SQUARE_SIZE, 'blue');  
        //green square
        squares[2] = colorRect(squareX[2],squareY[2],SQUARE_SIZE,SQUARE_SIZE, 'green');
        //white square
        squares[3] = colorRect(squareX[3],squareY[3],SQUARE_SIZE,SQUARE_SIZE, 'white');
        //black square
        squares[4] = colorRect(squareX[4],squareY[4],SQUARE_SIZE,SQUARE_SIZE, 'black');
        //orange square
        squares[5] = colorRect(squareX[5],squareY[5],SQUARE_SIZE,SQUARE_SIZE, 'orange');
        //purple square
        squares[6] = colorRect(squareX[6],squareY[6],SQUARE_SIZE,SQUARE_SIZE, 'mediumPurple');

        //player
        player = colorRect(playerX,playerY,PLAYER_SIZE,PLAYER_SIZE,'yellow');

        checkContact();
        checkWin();


    }

    //functions to reate rects
    function colorRect(leftX, topY, width, height, drawColor){     
        canvasContext.fillStyle = drawColor;
        canvasContext.fillRect(leftX,topY,width,height);    
    }

    function colorCircle(centerX, centerY, radius, color){
         //draws ball
        canvasContext.fillStyle=color;
        canvasContext.beginPath();
        canvasContext.arc(centerX,centerY,radius,0,Math.PI * 2, true);
        canvasContext.fill();

    }

    //check for contact between the squares
    function checkContact(){

       for(var i = 0; i < squareX.length; i++){
            if(intersectRect(i))
            {
                console.log("Overlap");
                playerReset();
            }
            else
            {
               //none
            }

        } 

        //while(playerY < squareY[i] )


    }

    //check the borders of the squares for contact
    function intersectRect(i){
      return !(playerX > squareX[i] + 50 || 
               playerX + 50 < squareY[i] || 
               playerY > squareY[i] + 50 ||
               playerY + 50 < squareY[i]);
    }

    //check if yellow square is at top of square
    function checkWin(){

        window.setTimeout(function(){
            if(playerY < PLAYER_SIZE){

                playerReset();

                for(var i = 0; i < squareX.length; i++)
                {
                    interval[i] += score/2;
                } 
                score++;
            }  

        },1000);



    }

    //reset the player to original position
    function playerReset(){
        playerX = canvas.width/2;
        playerY = canvas.height - 50;    
    }


</script>

感谢您修复我的主要错误。我现在唯一看不到的是创建的暂停方法。这是我修改后的代码的样子。这是一个问题的主要原因是当它重置时,它没有给玩家时间将鼠标移回原处,它只是在鼠标移动后立即转到鼠标。谢谢。


<script>

    var canvas;
    var canvasContext;

    var gamePaused = false;


    //square variables
    var squares = [];
    var squareX = [50, 0, 640, 400, 575, 300, 373];
    var squareY = [100, 150,200, 250, 300, 350, 400];
    var forward = [true, true, true, true, true, true, true];
    var interval = [15, 15, 15, 15, 15, 15, 15];
    const SQUARE_SIZE = 50;

    //player variables
    var player;
    var playerX = 0;
    var playerY = 0;
    var intervalPlayer = 0;
    const PLAYER_SIZE = 50;

    var score = 0;

    //pause game
    function unpause() { gamePaused = false } // un pause game
    function pauseFor(time = 1000){ // defaults to 1 second
        pauseGame = true;
        setTimeout(unpause,time);
    }


    window.onload = function(){

        canvas=document.getElementById('gameCanvas');
        canvasContext = canvas.getContext('2d');

        function calcMousePos(evt){

            var rect = canvas.getBoundingClientRect();
            var root = document.documentElement;
            var mouseX = evt.clientX - rect.left - root.scrollLeft;
            var mouseY = evt.clientY - rect.top - root.scrollTop;
            return{
                x:mouseX,
                y:mouseY
            };
        }

        //get mouse movement
        canvas.addEventListener('mousemove', function(evt){

            var mousePos = calcMousePos(evt);

            playerX = mousePos.x;
            playerY = mousePos.y;

        });

        //update screen
        var framesPerSecond = 30;
        function mainLoop(){
            moveEverything();
            drawEverything();       
            requestAnimationFrame(mainLoop); // request the next frame
        }
        requestAnimationFrame(mainLoop);


    }

    //moves each square based on the interval
    function moveEverything(){

        for(var i = 0; i < squareX.length; i++){
             if(!forward[i]){
            forward[i] = false;
             if(interval[i] > 0){
                interval[i] *= -1;
            }

            if(squareX[i] < 0){
                forward[i] = true;    
            }
        }else if(forward[i]){
            if(interval[i] < 0){
                interval[i] *= -1;
            }

            if(squareX[i] > canvas.width - 50)
            {
                forward[i] = false;        
            }
        }else{
            console.log("Error ball " + i);    
        }

        }

    }

    //draws each square on the background canvas
    function drawEverything(){ 

        for(var i = 0; i < squareX.length; i++){
            squareX[i] += interval[i];
        }

        //background
        colorRect(0,0,canvas.width,canvas.height, 'salmon');

        //score
        canvasContext.fillStyle = 'black';
        canvasContext.fillText(score, 10, 10);

        //red square
        squares[0] = colorRect(squareX[0],squareY[0],SQUARE_SIZE,SQUARE_SIZE, 'red');
        //blue square
        squares[1] = colorRect(squareX[1],squareY[1],SQUARE_SIZE,SQUARE_SIZE, 'blue');  
        //green square
        squares[2] = colorRect(squareX[2],squareY[2],SQUARE_SIZE,SQUARE_SIZE, 'green');
        //white square
        squares[3] = colorRect(squareX[3],squareY[3],SQUARE_SIZE,SQUARE_SIZE, 'white');
        //black square
        squares[4] = colorRect(squareX[4],squareY[4],SQUARE_SIZE,SQUARE_SIZE, 'black');
        //orange square
        squares[5] = colorRect(squareX[5],squareY[5],SQUARE_SIZE,SQUARE_SIZE, 'orange');
        //purple square
        squares[6] = colorRect(squareX[6],squareY[6],SQUARE_SIZE,SQUARE_SIZE, 'purple');

        //player
        player = colorRect(playerX,playerY,PLAYER_SIZE,PLAYER_SIZE,'yellow');

        if(! gamePaused ) { // if not pause
           // do everything that should not be done during paused game
           checkContact();
           checkWin();
        } else {
           // you may want to show that you are waiting from the next round
           canvasContext.fillStyle = "black";
           canvasContext.textAlign = "center";
           canvasContext.fillText("Get ready",canvas.width / 2, canvas.height / 4);
        }


    }

    //functions to reate rects
    function colorRect(leftX, topY, width, height, drawColor){     
        canvasContext.fillStyle = drawColor;
        canvasContext.fillRect(leftX,topY,width,height);    
    }

    function colorCircle(centerX, centerY, radius, color){
         //draws ball
        canvasContext.fillStyle=color;
        canvasContext.beginPath();
        canvasContext.arc(centerX,centerY,radius,0,Math.PI * 2, true);
        canvasContext.fill();

    }

    //check for contact between the squares
    function checkContact(){
       for(var i = 0; i < squareX.length; i++){
            if(intersectRect(i)){                 
                resetPlayer();
                pauseFor(); // pause for default 1 second
                break; // this breaks out of the for loop
                       // no point checking for other hits 
                       // once you found one.
            }     
        } 
    }

    //check the borders of the squares for contact
    function intersectRect(i){
      return !(playerX > squareX[i] + 50 || 
               playerX + 50 < squareX[i] || 
               playerY > squareY[i] + 50 ||
               playerY + 50 < squareY[i]);
    }

    //check if yellow square is at top of square
    function checkWin(){
        if(playerY < PLAYER_SIZE){
            gamePaused = true;
            score += 1;
            resetPlayer(); // reset the player
            speedUpSquare(); // create a function that speeds up the squares
            pauseFor(); // pause for default 1 second
        }
     }


       function speedUpSquare(){
             for(var i = 0; i < squareX.length; i++)
             {
                interval[i] += score/2;
             } 
       }


    //reset the player to original position
    function resetPlayer(){
        playerX = canvas.width/2;
        playerY = canvas.height - 50;  
        pauseFor();
    }


</script>

加分多少?

win 的问题在于您每 30 秒调用一次函数 checkWin,而在该函数中您除了安排在一秒钟内检查 win 之外什么都不做。我必须 运行 它才能确切地看到发生了什么,但更好的解决方案是执行以下操作

// create a global that pauses the game
// when this is true then you are waiting to start the next play
var gamePaused = false;  
function unpause() { gamePaused = false } // un pause game
function pauseFor(time = 1000){ // defaults to 1 second
    pauseGame = true;
    setTimeout(unpause,time);
}

function checkWin(){
    if(playerY < PLAYER_SIZE){
        gamePaused = true;
        score += 1;
        resetPlayer(); // reset the player
        speedUpSquare(); // create a function that speeds up the squares
        pauseFor(); // pause for default 1 second
    }
 }

主循环

你的主循环也有点问题,用requestAnimationFrame

会好很多
    // where you had 
     setInterval(function(){ ...

    // replace that interval function with 
    // create a mainloop function
    function mainLoop(){
        moveEverything();
        drawEverything();       
        requestAnimationFrame(mainLoop); // request the next frame
    }
    requestAnimationFrame(mainLoop); // this will start the me main loop

这将为您提供更好的帧速率 (60fps),因此您需要降低速度(interval 您用于速度的变量)

暂停游戏

在函数 drawEverything 中,您需要确保在等待下一轮开始时不检查是否获胜。正如 gamePaused 标志

    if(! gamePaused ) { // if not pause
       // do everything that should not be done during paused game
       checkContact();
       checkWin();
    } else {
       // you may want to show that you are waiting from the next round
       ctx.fillStyle = "black";
       ctx.textAlign = "center";
       ctx.fillText("Get ready",c.width / 2, c.height / 4);
    }

击中正方形的测试很好,但有一个错字

function intersectRect(i){
  return !(playerX > squareX[i] + 50 || 
           playerX + 50 < squareY[i] || 
           //...................^........ Should be squareX[i]
           playerY > squareY[i] + 50 ||
           playerY + 50 < squareY[i]);
}

使用该固定更改 checkContact 函数

// modify the to pause the game on hit 
function checkContact(){
   for(var i = 0; i < squareX.length; i++){
        if(intersectRect(i)){                 
            playerReset();
            pauseFor(500); // pause for default 1/2 second
            break; // this breaks out of the for loop
                   // no point checking for other hits 
                   // once you found one.
        }     
    } 
}

认为这涵盖了大部分内容。

一些小技巧

奇数位代码

   // you do this ?? colorRect does not return anything so dont know why 
   // you do this. Same for the squares
   player = colorRect(playerX,playerY,PLAYER_SIZE,PLAYER_SIZE,'yellow');

   // would be better as
   colorRect(playerX,playerY,PLAYER_SIZE,PLAYER_SIZE,'yellow');

使用对象

使用对象可以节省您的输入时间并使游戏更易于管理。

你有以下内容,这使得添加、修改、访问方块变得困难,而且很乱

var squareX = [50, 0, 640, 400, 575, 300, 373];
var squareY = [100, 150,200, 250, 300, 350, 400];
var forward = [true, true, true, true, true, true, true];
var interval = [15, 15, 15, 15, 15, 15];
const SQUARE_SIZE = 50;

您可以为每个方块创建一个对象并将它们添加到数组中

 var squares = [{
       x : 50,
       y : 100,
       forward : true,
       interval : 15,
       size : 50,
       color : "blue"
    },{
       x : 0,
       y : 150,
       forward : true,
       interval : 15,
       size : 50,
       color : "Green"
    },
    // and so on 
 ]

或者如果你有信心

const SQUARE_SPEED = 15 / 2; // frame rate now 60 so half speed
const SQUARE_SIZE = 50;
const squares = [];
// when you create a function with arguments you can set defaults with
// the equal eg function blah(data = 1). If I call blah() without the
// argument it will default to 1. If I call with the argumen blah(2) data
// will be set to the argument 2
const addSquare = (x,y,color,forward = true,interval = SQUARE_SPEED,size = SQUARE_SIZE) => {
    squares.push({  x, y, color, forward, interval, size, });
}
addSquare(50,  100, 'red');
addSquare(0,   150, 'blue');
addSquare(640, 200, 'green');
addSquare(400, 250, 'white');
addSquare(575, 300, 'black');
addSquare(300, 350, 'orange');
addSquare(373, 400, 'mediumPurple');

您可以通过数组访问一个正方形。例如测试 player hit

  function testForHit(){
      var i;
      for(i = 0; i < squares.length; i++){
           var s = squares[i]; // get a square from the array
           if( !(playerX > s.x + s.size ||   playerX + 50 < s.x || 
                 playerY > s.y + s.size || playerY + 50 < s.y){
                playerReset();
                pauseFor(500); 
                break; 
           }     
     } 
}

并绘制它们

  function drawSquares(){
      var i;
      for(i = 0; i < squares.length; i++){
           var s = squares[i]; // get a square from the array
           colorRect(s.x,s.y,s.size,s.size,s.color);
       }
   }

您甚至可以将绘制功能添加到方形对象 squares[i].draw() 但这是当您掌握基本对象时的一些东西。