canvas 的乒乓球比赛中球与球拍发生碰撞

Collision between ball and paddle in pong game on canvas

球似乎从球拍的一侧弹回,但当它从球拍的一侧飞来时,它会滑过球拍。我只是找不到背后的方法,这真的让我很困扰。我正在使用一些逻辑门来定义需要反转球方向的位置

function startGame() {
    GameArea.start();
 Ball1 = new CircleComp('white' , window.innerWidth - 200 , window.innerHeight - 20);
 Ball1.ySpeed = 13.5;
 Ball1.xSpeed = 6;
 Paddle1 = new PaddleComp( 87, 83, 0, window.innerHeight / 2.5, 10, 70);
 Paddle2 = new PaddleComp( 38, 40, window.innerWidth - 10, window.innerHeight / 2.5, 10 , 70);
}
var GameArea = {
 canvas : canvas = document.querySelector("canvas"),
 start : function (){
  this.canvas.width = window.innerWidth;
  this.canvas.height = window.innerHeight;
  this.ctx = this.canvas.getContext('2d');
  this.interval = setInterval(updateGameArea, 20);
        window.addEventListener('keydown', function (e) {
            GameArea.keys = (GameArea.keys || []);
            GameArea.keys[e.keyCode] = true;
        })
        window.addEventListener('keyup', function (e) {
            GameArea.keys[e.keyCode] = false; 
        })
    }, 
 clear : function() {
        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
    }
}
function CircleComp(color, x , y){
 this.x = x;
 this.y = y;
 this.width = 8;
    this.height = 8;
 var context1 = GameArea.ctx;
 this.update = function(){
  context1.beginPath();
  context1.fillStyle = color;
  context1.fillRect(this.x, this.y, this.width, this.height);
  context1.fill();
  context1.stroke();
  this.updatePosition();
 }
 this.updatePosition = function(){
  this.y += this.ySpeed; 
  this.x += this.xSpeed;
  if(this.x + this.width > GameArea.canvas.width){
   this.xSpeed = -this.xSpeed;
  }
  if(this.y + this.height > GameArea.canvas.height){
   this.ySpeed = -this.ySpeed;; 
  }
  if(this.x - this.width < 0){
   this.xSpeed = -this.xSpeed;
  } 
  if(this.y - this.height < 0){
   this.ySpeed = -this.ySpeed;
  }
  if(this.y + this.height > Paddle2.y && this.y - this.width < (Paddle2.y + 130) && this.x + this.width > Paddle2.x ){
   this.xSpeed = -this.xSpeed;
  } 
  if(this.y + this.height > Paddle1.y && this.y - this.width < (Paddle1.y + 70) && this.x - this.height < Paddle1.x + 10){
   this.xSpeed = -this.xSpeed;
  }
 }
}
function PaddleComp(Upkey, Downkey, x, y, width, height){
 this.x = x;
 this.y = y;
 this.width = width;
 this.height = height;
 this.ySpeed = 0;
 var context2 = GameArea.ctx;
 this.update = function(){
 context2.fillStyle = 'white';
 context2.fillRect(x,this.y,this.width,this.height); 
 this.updatePosition();
 }
 this.updatePosition = function() {
  this.ySpeed = 0; 
  if (GameArea.keys && GameArea.keys[Upkey]) {
   this.ySpeed = -15; //console.log('Up');
  }
  if (GameArea.keys && GameArea.keys[Downkey]) {
   this.ySpeed = 15; //console.log('Down');
  }
  if ((GameArea.keys && GameArea.keys[Downkey]) && this.y + 130 > window.innerHeight){
   this.ySpeed = this.ySpeed -15 ; 
  }
  if ((GameArea.keys && GameArea.keys[Upkey]) && this.y < 0 ){
   this.ySpeed = this.ySpeed +15 ; 
  }
  this.y += this.ySpeed;   
 }
}
function updateGameArea(){
 GameArea.clear();
 Paddle1.update();
 Paddle2.update();
 Ball1.update();
}
<html>
 <head>
  <meta charset='urf-8'>
  <style>
   canvas{
    border: 0px solid black;
    background-color: black;
   }
   body{
    margin: 0;
    overflow: hidden;
   }
  </style>
 </head>
 <body onload='startGame()'>
  <canvas></canvas>
  <script src='Pong.js'></script>
 </body>
</html>

无法直接看出您的代码有什么问题,所以我只是用球重写了代码,球对象中的球拍(球拍)测试函数并从球员对象中调用。 ball.checkPad(玩家);测试球是否击中了玩家的球棒。为了帮助描绘正在发生的事情,我放慢了速度并让蝙蝠变得真实。当球击中球棒时它会变黄,球棒会变红一秒钟左右。

你问的部分评论很多,

希望对您有所帮助

从 OP 问题复制的演示。

const setting = {
    speed : 2, // of ball
    left : 0,
    width : 400,
    height : 200,
    padWidth : 50,
    padHeight : 80,
    padSpeed : 4, // double balls
    hitPauseCount : 30,  // nuber of frames to hold when there is a collisiotn so you
                          // can check all is good
}
const keys = {
    ArrowUp : false,
    ArrowDown : false,
    ArrowLeft : false,
    ArrowRight : false,
    keyEvent(e) { // dont use keyCode it has depreciated
        if (keys[e.code] !== undefined) {
            keys[e.code] = e.type === "keydown";
            e.preventDefault();
        }
    }
}
var ctx;
var ball1, paddle1, paddle2;
var gameArea = {
    start() {
        canvas.width = setting.width;
        canvas.height = setting.height;
        ctx = canvas.getContext('2d');
        requestAnimationFrame(updateGameArea);
    },
    clear() {
        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    }
}
gameArea.start();
ball = new CircleComp('white', window.innerWidth - 200, window.innerHeight - 20);
ball.ySpeed = setting.speed;
ball.xSpeed = setting.speed;
paddle1 = new PaddleComp("ArrowUp", "ArrowDown", setting.left, setting.height / 2, setting.padWidth, setting.padHeight);
paddle2 = new PaddleComp("ArrowLeft", "ArrowRight", setting.width - setting.padWidth, setting.height / 2, setting.padWidth, setting.padHeight);
window.addEventListener('keydown', keys.keyEvent);
window.addEventListener('keyup', keys.keyEvent);


function CircleComp(color, x, y) {
    this.x = x;
    this.y = y;
    this.width = 8;
    this.height = 8;
    this.xSpeed = setting.speed;
    var hit = 0;
    var restartCount;
    var serveDirection;

    this.reset = function(){
        this.x = ctx.canvas.width /2;
        this.y = ctx.canvas.height / 2;
        this.xSpeed = -this.xSpeed
        this.ySpeed = setting.speed * Math.sign(Math.random() - 0.5);
        restartCount = 60;
    }
    this.draw = function () {
        if(hit > 0){ 
            hit -= 1;
            ctx.fillStyle = "yellow";
        }else{
            ctx.fillStyle = color;
        }
        ctx.fillRect(this.x, this.y, this.width, this.height);
    }
    // next funtion is called by the player objects
    this.checkPad = function (player) {
        if (player.x > canvas.width / 2) { // is player on left or right
            if (this.xSpeed > 0) { // player on right only check if ball moving rigth
                if (this.x + this.width > player.x) { // ball is in paddles zone
                    //if not  bottom of ball above top of bat or top of ball bellow bottom of bat
                    if (!(this.y + this.height <= player.y || this.y >= player.y + player.height)) {
                        // ball and bat in contact
                        // is ball moving down and the balls top edge above the player
                        // then ball has hit the top side of the bat
                        if(this.ySpeed > 0 && this.y <= player.y){ 
                            this.y = player.y - this.width;
                            this.ySpeed =  -setting.speed;
                        }else if(this.ySpeed < 0 && this.y + this.height >= player.y + player.height){ // do bottom check
                            this.y = player.y + player.height;
                            this.ySpeed =  setting.speed;
                        }else{  // ball hit front of bat
                            this.x = player.x - this.width;
                            this.xSpeed =  - setting.speed;
                        }
                        player.hit = setting.hitPauseCount;  // counters to show FX when a hit happens
                        hit = setting.hitPauseCount;
                    }
                }
            }

        } else { // player must be left
            if (this.xSpeed < 0) { // ball must move left
                if (this.x < player.x + player.width) { // ball is in paddles zone
                    if (!(this.y + this.height <= player.y || this.y >= player.y + player.height)) {
                        // ball and bat in contact
                        // ball and bat in contact
                        // is ball moving down and the balls top edge above the player
                        // then ball has hit the top side of the bat
                        if(this.ySpeed > 0 && this.y <= player.y){ 
                            this.y = player.y - this.width;
                            this.ySpeed =  -setting.speed;
                        }else if(this.ySpeed < 0 && this.y + this.height >= player.y + player.height){ // do bottom check
                            this.y = player.y + player.height;
                            this.ySpeed =  setting.speed;
                        }else{  // ball hit front of bat
                            this.x = player.x + player.width;
                            this.xSpeed = setting.speed;
                        }
                        player.hit = setting.hitPauseCount;  // counters to show FX when a hit happens
                        hit = setting.hitPauseCount;
                    }
                }
            }
        }
    }
    this.update = function () {
        if(restartCount > 0){ // wait for restart pause
            restartCount -= 1;
        }else{
            if(hit > 0){  // do nothing if paused
                return;
            }
            this.y += this.ySpeed;
            this.x += this.xSpeed;
            if (this.x + this.width >= canvas.width) {
                this.reset();  // point
            } else if (this.x < 0) {
                this.reset(); // point
            }
            if (this.y + this.height >= canvas.height) {
                this.y = canvas.height - this.height;
                this.ySpeed = -setting.speed;
            } else if (this.y < 0) {
                this.y = 0;
                this.ySpeed = setting.speed;
            }
        }
    }
    this.reset();
}
function PaddleComp(upKey, downKey, x, y, width, height) {
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;
    this.hit = 0;
    this.draw = function () {
        if(this.hit > 0){ 
            this.hit -= 1;
            ctx.fillStyle = "red";
        }else{
            ctx.fillStyle = '#9CF';
        }
        ctx.fillRect(this.x, this.y, this.width, this.height);
    }
    this.update = function () {
        if (keys[upKey]) {
            this.y -= setting.padSpeed;
        };
        if (keys[downKey]) {
            this.y += setting.padSpeed;
        };
        if (this.y < 0) {
            this.y = 0;
        }
        if (this.y + this.height >= canvas.height) {
            this.y = canvas.height - this.height;
        }
        ball.checkPad(this);
    }
}
function updateGameArea() {
    gameArea.clear();
    paddle1.update();
    paddle2.update();
    ball.update();
    paddle1.draw();
    paddle2.draw();
    ball.draw();
    requestAnimationFrame(updateGameArea);
}
<canvas id=canvas style='background:#69C;border:2px blue solid'></canvas>