首页 > 解决方案 > 如何使球与画布上的三角形电源碰撞?

问题描述

我正在尝试为我的游戏创造能量。我已经让形状出现了,但是当球与形状碰撞时,它并没有像它应该做的那样加速。

    <html>
    <title>Level Selector</title>
    <canvas id="myCanvas" width="750" height="400"></canvas>

    <style type="text/css">
        canvas { background: #eee; }
    </style>

    <script>
    var canvas = document.getElementById("myCanvas");
    var ctx = canvas.getContext("2d");
    var x = canvas.width/2;
    var y = canvas.height-30;
    var dx = 2;//Ball is moving in x direction at a constant rate
    var dy = -2;//Ball is moving in y direction at a constant rate
    var ballRadius = 10;//To see if ball is colliding with brick/canvas
    var paddleHeight = 10;
    var paddleWidth = 75;
    var paddleX = (canvas.width-paddleWidth)/2;
    var rightPressed = false;//This variable is false because the 'right arrow' key is not pressed.
    var leftPressed = false;//This variable is false because the 'left arrow' key is not pressed.
    var brickRowCount = 5;
    var brickColumnCount = 8;
    var brickWidth = 75;
    var brickHeight = 20;
    var brickPadding = 10;
    var brickOffsetTop = 30;
    var brickOffsetLeft = 30;
    var score = 0;
    var lives = 3;
    var paused = false;

    var ballstartx = 10;
    var ballstarty = 10;
    var balllefttrix = 20;
    var balllefttriy = 30;
    var ballrighttrix = 30;
    var ballrighttriy = 10;

    var paddlestartx = 300;
    var paddlestarty = 10;
    var paddlelefttrix = 310;
    var paddlelefttriy = 30;
    var paddlerighttrix = 320;
    var paddlerighttriy = 10;

    var bricks = [];//this is an array holding all the bricks
    for(var c=0; c<brickColumnCount; c++) {
        bricks[c] = [];
        for(var r=0; r<brickRowCount; r++) {
            bricks[c][r] = { x: 0, y: 0, status: 1 };//If status is '1' then draw it. However, is status is '0', fill in with background
        }
    }

    document.addEventListener("keydown", keyDownHandler, false);//Functions only when key is pressed
    document.addEventListener("keyup", keyUpHandler, false);//Functions only when key is not pressed
    document.addEventListener("mousemove", mouseMoveHandler, false);//Functions only when mouse curcor moves


    //keyCode(39) is the code for the 'right arrow' key and keyCode(37) is the code for the 'left arrow' key
        function keyDownHandler(e) {
            if(e.keyCode == 39) {
                rightPressed = true;
            }
            else if(e.keyCode == 37) {
                leftPressed = true;
            }
        }

        function keyUpHandler(e) {
            if(e.keyCode == 39) {
                rightPressed = false;
            }
            else if(e.keyCode == 37) {
                leftPressed = false;
            }
        }


        function mouseMoveHandler(e) {
            var relativeX = e.clientX - canvas.offsetLeft;//This represents the hoizontal mouse movement.
                if(relativeX > 0 && relativeX < canvas.width) {
                paddleX = relativeX - paddleWidth/2;
            }
        }

        window.addEventListener('keydown', pauseGameKeyHandler, false);

        function pauseGameKeyHandler(e) {
            var keyCode = e.keyCode;
            switch(keyCode){
                case 80: //p
                togglePause();
                break;
            }

        }

        function togglePause() {
            paused = !paused;
            draw();
        }


        //Collisions only true when:
        //  -The x position of the ball is greater than the x position of the brick.
        //  -The x position of the ball is less than the x position of the brick plus its width.
        //  -The y position of the ball is greater than the y position of the brick.
        //  -The y position of the ball is less than the y position of the brick plus its height.
        function collisionDetection() {
        for(var c=0; c<brickColumnCount; c++) {
            for(var r=0; r<brickRowCount; r++) {
                var b = bricks[c][r];
                if(b.status == 1) {
                    if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) {
                        dy = -dy;
                        b.status = 0;
                        score++;
                    if(score == brickRowCount*brickColumnCount) {
                        alert("YOU WIN, CONGRATULATIONS!");
                        document.location.reload();
                        }
                    }
                }
            }
        }
    }

        //this is the score variable of the game
        function drawScore() {
        ctx.font = "16px Arial";
        ctx.fillStyle = "#0095DD";
        ctx.fillText("Score: "+score, 8, 20);
    }

        //this is the lives variable of the game
        function drawLives() {
        ctx.font = "16px Arial";
        ctx.fillStyle = "#0095DD";
        ctx.fillText("Lives: "+lives, canvas.width-65, 20);
    }

        //this is the ball power up
        function drawBallpowerup() {
            ctx.beginPath();
            ctx.moveTo(ballstartx, ballstarty);
            ctx.lineTo(balllefttrix, balllefttriy);
            ctx.lineTo(ballrighttrix, ballrighttriy);
            ctx.fillStyle = "#42f445";
            ctx.fill();
            ctx.closePath();
        }


    //ball power up collision
    function ballpowerupDetection() {
        if(ballstartx == x && ballstarty == y && balllefttrix == x && balllefttriy == y && ballrighttrix == x && ballrighttriy == y ) {
            dy == -5;
            dx == 5;
            }
        }


        //this is the paddle power up
        function drawPaddlepowerup() {
            ctx.beginPath();
            ctx.moveTo(paddlestartx, paddlestarty);
            ctx.lineTo(paddlelefttrix, paddlelefttriy);
            ctx.lineTo(paddlerighttrix, paddlerighttriy);
            ctx.fillStyle = "#ce6210";
            ctx.fill();
            ctx.closePath();
        }

        //paddle power up collision
        function paddlepowerupDetection() {
                for(var c=0; c<brickColumnCount; c++) {
                    for(var r=0; r<brickRowCount; r++) {
                        var b = bricks[c][r];
                        if(b.status == 1) {
                            if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) {
                                dy = -dy;
                                b.status = 0;
                                score++;
                            if(score == brickRowCount*brickColumnCount) {
                                alert("YOU WIN, CONGRATULATIONS!");
                                document.location.reload();
                                }
                            }
                        }
                    }
                }
            }

        //this creates the ball
        function drawBall() {
            ctx.beginPath();
            ctx.arc(x, y, ballRadius, 0, Math.PI*2);
            ctx.fillStyle = "#0095DD";
            ctx.fill();
            ctx.closePath();
        }

        //this creates the paddle
        function drawPaddle() {
            ctx.beginPath();
            ctx.rect(paddleX, canvas.height-paddleHeight, paddleWidth, paddleHeight);
            ctx.fillStyle = "#0095DD";
            ctx.fill();
            ctx.closePath();
        }

        //this creates the bricks
        function drawBricks() {
        for(var c=0; c<brickColumnCount; c++) {
            for(var r=0; r<brickRowCount; r++) {
                if(bricks[c][r].status == 1) {
                    var brickX = (c*(brickWidth+brickPadding))+brickOffsetLeft;
                    var brickY = (r*(brickHeight+brickPadding))+brickOffsetTop;
                    bricks[c][r].x = brickX;
                    bricks[c][r].y = brickY;
                    ctx.beginPath();
                    ctx.rect(brickX, brickY, brickWidth, brickHeight);
                    ctx.fillStyle = "#0095DD";
                    ctx.fill();
                    ctx.closePath();
                }
            }
        }
    }

        function draw() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);//clears canvas content from previous frame
            drawBall();//this code draws the ball onto the canvas
            drawPaddle();//this code draws the paddle onto the canvas
            collisionDetection();//this codes enables the collision detection for the ball and bricks
            drawBricks();//this code draws the bricks onto the canvas
            drawScore();//this code draws the score variable onto the canvas
            drawLives();//this code draws the lives variable onto the canvas
            drawBallpowerup();
            drawPaddlepowerup();
            ballpowerupDetection();

            //Reverse Ball movement when the ball collides with wall in 'x' direction (Left/Right wall)
            if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
            dx = -dx;
        }

            //Reverse Ball movement when the ball collides with wall in 'y' direction (Top/Bottom wall)
        if(y + dy < ballRadius) {
            dy = -dy;
        }   else if(y + dy > canvas.height-ballRadius) {
        if(x > paddleX && x < paddleX + paddleWidth) {
            dy = -dy;//If the ball collides with the paddle,  the ball is rebounded in the opposite direction.
        }
            else {
                lives--;
        if(!lives) {
            alert("GAME OVER");
            document.location.reload();
            }
            else {
                x = canvas.width/2;
                y = canvas.height-30;
                dx = 2;
                dy = -2;
                paddleX = (canvas.width-paddleWidth)/2;
            }
        }
    }

        if(rightPressed && paddleX < canvas.width-paddleWidth) {//limits paddle movement in between the canvas width
            paddleX += 7;//Paddle shifts 7 pixels in the positive x direction
        }
        else if(leftPressed && paddleX > 0) {//limits paddle movement in between the canvas width
                paddleX -= 7;//Paddle shifts 7 pixels in the negative x direction
            }

        x += dx;//Ball is updated by painting it over each position it moves in
        y += dy;//Ball is updated by painting it over each position it moves in

        if(!paused) {
            requestAnimationFrame(draw);
        }
    }

    draw();

    </script>

    <body onload="draw();>


    </body>

</html>

加电功能不起作用,我不知道为什么。我希望球在基本接触三角形时加快速度。提前谢谢。

标签: javascripthtmlcanvashtml5-canvas

解决方案


jsfiddle

我确实帮助了您遇到的大部分问题:

  • 通电具有矩形碰撞边界,比三角形更容易数学
  • 在画布内随机放置通电
  • 评论在哪里以及如何添加效果以及如何在 X 秒后结束它

代码仍然有点混乱,但这是你的工作:将重复逻辑移动到单个函数,就像我对碰撞逻辑所做的那样,更好地查看和维护。

document.addEventListener('load', draw);
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var x = canvas.width/2;
var y = canvas.height-30;
var dx = 2;//Ball is moving in x direction at a constant rate
var dy = -2;//Ball is moving in y direction at a constant rate
var ballRadius = 10;//To see if ball is colliding with brick/canvas
var paddleHeight = 10;
var paddleWidth = 75;
var paddleX = (canvas.width-paddleWidth)/2;
var rightPressed = false;//This variable is false because the 'right arrow' key is not pressed.
var leftPressed = false;//This variable is false because the 'left arrow' key is not pressed.
var brickRowCount = 5;
var brickColumnCount = 8;
var brickWidth = 75;
var brickHeight = 20;
var brickPadding = 10;
var brickOffsetTop = 30;
var brickOffsetLeft = 30;
var score = 0;
var lives = 3;
var paused = false;

var ballstartx = 10;
var ballstarty = 10;
var balllefttrix = 20;
var balllefttriy = 30;
var ballrighttrix = 30;
var ballrighttriy = 10;

var paddlestartx = 300;
var paddlestarty = 10;
var paddlelefttrix = 310;
var paddlelefttriy = 30;
var paddlerighttrix = 320;
var paddlerighttriy = 10;

var bricks = [];//this is an array holding all the bricks
for(var c=0; c<brickColumnCount; c++) {
  bricks[c] = [];
  for(var r=0; r<brickRowCount; r++) {
    bricks[c][r] = { x: 0, y: 0, status: 1 };//If status is '1' then draw it. However, is status is '0', fill in with background
  }
}

document.addEventListener("keydown", keyDownHandler, false);//Functions only when key is pressed
document.addEventListener("keyup", keyUpHandler, false);//Functions only when key is not pressed
document.addEventListener("mousemove", mouseMoveHandler, false);//Functions only when mouse curcor moves


//keyCode(39) is the code for the 'right arrow' key and keyCode(37) is the code for the 'left arrow' key
function keyDownHandler(e) {
  if(e.keyCode == 39) {
    rightPressed = true;
  }
  else if(e.keyCode == 37) {
    leftPressed = true;
  }
}

function keyUpHandler(e) {
  if(e.keyCode == 39) {
    rightPressed = false;
  }
  else if(e.keyCode == 37) {
    leftPressed = false;
  }
}


function mouseMoveHandler(e) {
  var relativeX = e.clientX - canvas.offsetLeft;//This represents the hoizontal mouse movement.
  if(relativeX > 0 && relativeX < canvas.width) {
    paddleX = relativeX - paddleWidth/2;
  }
}

window.addEventListener('keydown', pauseGameKeyHandler, false);

function pauseGameKeyHandler(e) {
  var keyCode = e.keyCode;
  switch(keyCode){
    case 80: //p
      togglePause();
      break;
  }

}

function togglePause() {
  paused = !paused;
  draw();
}






/*************************************************************/

// my big changes start here

// PS! I commented out some annoying code
// from other places like game over alerts etc
// try to find a better way to debug
// your work, waiting all the time is bad


// NEW
const ballPowerupHalfWidth = 30;
const paddlePowerupHalfWidth = 30;


let ballPowerups = [];
let paddlePowerups = [];


// NEW: add powerup to random position
function addPowerups() {
  // I check only if none exist, you could
  // add more than 1 powerup if you want
  if (ballPowerups.length < 1) {
   	// otherwise half the triangle could be outside canvas
  	const padding = 50;
    const xMin = 0 + padding;
    const xMax = canvas.width - padding;
    const yMin = 0 + padding;
    const yMax = canvas.height - padding;
  
  	ballPowerups.push({
    	x: Math.floor(Math.random()*(xMax-xMin+1)+xMin),
      y: Math.floor(Math.random()*(yMax-yMin+1)+yMin),
    });
  }
  
  // I check only if none exist, you could
  // add more than 1 powerup if you want
  if (paddlePowerups.length < 1) {
  	// otherwise half the triangle could be outside canvas
  	const padding = 50;
    const xMin = 0 + padding;
    const xMax = canvas.width - padding;
    const yMin = 0 + padding;
    const yMax = canvas.height - padding;
  
  	paddlePowerups.push({
    	x: Math.floor(Math.random()*(xMax-xMin+1)+xMin),
      y: Math.floor(Math.random()*(yMax-yMin+1)+yMin),
    });
  }
}


// NEW: do all collision detections
function doCollisionDetection() {
	// ball powerups
  ballPowerups.forEach((powerup, i) => {
    rectangleCollisionDetection(
    	{x: powerup.x, y: powerup.y}, 
      {w: ballPowerupHalfWidth, h: ballPowerupHalfWidth}, 
      () => {
        console.log('BALL POWERUP COLLISION');
        // remove powerup
        ballPowerups.splice(i, 1);
        // add your effect here
        
        // to make effect last 10 seconds:
        // 1. add effect
        // 2. and setTimeout(() => { /* code that removes effect */ }, 10000);
    });
  });
  
  // paddle powerups
  paddlePowerups.forEach((powerup, i) => {
    rectangleCollisionDetection(
    	{x: powerup.x, y: powerup.y}, 
      {w: ballPowerupHalfWidth, h: ballPowerupHalfWidth}, 
      () => {
        console.log('PADDLE POWERUP COLLISION');
        // remove powerup
        paddlePowerups.splice(i, 1);
        // add your effect here
    });
  });

	// bricks
  for(var c=0; c<brickColumnCount; c++) {
    for(var r=0; r<brickRowCount; r++) {
      var b = bricks[c][r];
      if(b.status == 1) {
        rectangleCollisionDetection(b, {w: brickWidth, h: brickHeight}, () => {
        	console.log('BRICK COLLISION');
        	dy = -dy;
          b.status = 0;
          score++;
          if(score == brickRowCount*brickColumnCount) {
            //alert("YOU WIN, CONGRATULATIONS!");
            //document.location.reload();
          }
        });
      }
    }
  }
}


// NEW: collision detection between ball and rectangle shaped
// collision boundary (only need center(x, y) and half width)
function rectangleCollisionDetection(center, size, callback) {
	if(
  	x > center.x && 
    x < center.x+size.w && 
    y > center.y && 
    y < center.y+size.h
  ) {
    callback && callback();
  }
}



function drawBallpowerup() {
	ballPowerups.forEach(powerup => {
    ctx.beginPath();
    ctx.moveTo(powerup.x, powerup.y);
    ctx.lineTo(powerup.x+ballPowerupHalfWidth, powerup.y+ballPowerupHalfWidth);
    ctx.lineTo(powerup.x+ballPowerupHalfWidth*2, powerup.y);
    ctx.fillStyle = "#42f445";
    ctx.fill();
    ctx.closePath();
  });
}

function drawPaddlepowerup() {
	paddlePowerups.forEach(powerup => {
    ctx.beginPath();
    ctx.moveTo(powerup.x, powerup.y);
    ctx.lineTo(powerup.x+paddlePowerupHalfWidth, powerup.y+paddlePowerupHalfWidth);
    ctx.lineTo(powerup.x+paddlePowerupHalfWidth*2, powerup.y);
    ctx.fillStyle = "#ce6210";
    ctx.fill();
    ctx.closePath();
  });
}


// my big changes end here

/*************************************************************/











//this is the score variable of the game
function drawScore() {
  ctx.font = "16px Arial";
  ctx.fillStyle = "#0095DD";
  ctx.fillText("Score: "+score, 8, 20);
}

//this is the lives variable of the game
function drawLives() {
  ctx.font = "16px Arial";
  ctx.fillStyle = "#0095DD";
  ctx.fillText("Lives: "+lives, canvas.width-65, 20);
}

//this creates the ball
function drawBall() {
  ctx.beginPath();
  ctx.arc(x, y, ballRadius, 0, Math.PI*2);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
}

//this creates the paddle
function drawPaddle() {
  ctx.beginPath();
  ctx.rect(paddleX, canvas.height-paddleHeight, paddleWidth, paddleHeight);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
}

//this creates the bricks
function drawBricks() {
  for(var c=0; c<brickColumnCount; c++) {
    for(var r=0; r<brickRowCount; r++) {
      if(bricks[c][r].status == 1) {
        var brickX = (c*(brickWidth+brickPadding))+brickOffsetLeft;
        var brickY = (r*(brickHeight+brickPadding))+brickOffsetTop;
        bricks[c][r].x = brickX;
        bricks[c][r].y = brickY;
        ctx.beginPath();
        ctx.rect(brickX, brickY, brickWidth, brickHeight);
        ctx.fillStyle = "#0095DD";
        ctx.fill();
        ctx.closePath();
      }
    }
  }
}

function draw() {
	// clears canvas content from previous frame
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  
  drawBall();//this code draws the ball onto the canvas
  drawPaddle();//this code draws the paddle onto the canvas
  drawBricks();//this code draws the bricks onto the canvas
  
  addPowerups();
  doCollisionDetection();
  
  drawScore();//this code draws the score variable onto the canvas
  drawLives();//this code draws the lives variable onto the canvas
  
  drawBallpowerup();
  drawPaddlepowerup();

  //Reverse Ball movement when the ball collides with wall in 'x' direction (Left/Right wall)
  if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
    dx = -dx;
  }

  //Reverse Ball movement when the ball collides with wall in 'y' direction (Top/Bottom wall)
  if(y + dy < ballRadius) {
    dy = -dy;
  }   else if(y + dy > canvas.height-ballRadius) {
    if(x > paddleX && x < paddleX + paddleWidth) {
      dy = -dy;//If the ball collides with the paddle,  the ball is rebounded in the opposite direction.
    }
    else {
      lives--;
      if(!lives) {
        //alert("GAME OVER");
        //document.location.reload();
      }
      else {
        x = canvas.width/2;
        y = canvas.height-30;
        dx = 2;
        dy = -2;
        paddleX = (canvas.width-paddleWidth)/2;
      }
    }
  }

  if(rightPressed && paddleX < canvas.width-paddleWidth) {//limits paddle movement in between the canvas width
    paddleX += 7;//Paddle shifts 7 pixels in the positive x direction
  }
  else if(leftPressed && paddleX > 0) {//limits paddle movement in between the canvas width
    paddleX -= 7;//Paddle shifts 7 pixels in the negative x direction
  }

  x += dx;//Ball is updated by painting it over each position it moves in
  y += dy;//Ball is updated by painting it over each position it moves in

  if(!paused) {
    requestAnimationFrame(draw);
  }
}

draw();
canvas { 
     background: #eee; 
}
<canvas id="myCanvas" width="750" height="400"></canvas>


推荐阅读