为什么乒乓球会卡在底部?

时间:2016-11-02 15:48:31

标签: javascript html html5 canvas html5-canvas

我最近做了一个JS Pong游戏。它运作良好,但球很少卡在底部或顶部。它看起来像在墙的中间并不断弹跳。 Video of the issue happening.您可以尝试游戏here。我不知道为什么会出现这个问题,因为逻辑似乎是正确的,并且90%的时间正确地工作。以下是我的程序的两个主要功能:

function moveAll() {
  if (showingWinScreen) {
    return;
  }
  computerMovement();
  ballX += ballSpeedX;
  ballY += ballSpeedY;
  if (ballY <= 10) {
    ballSpeedY = -ballSpeedY;
  } else if (ballY >= HEIGHT - 10) {
    ballSpeedY = -ballSpeedY;
  }
  if (ballX >= WIDTH - 10) {
    if ((ballY > paddleY) && (ballY < paddleY + 100)) {
      ballSpeedX = -ballSpeedX;
      var deltaY = ballY - paddleY - 50;
      ballSpeedY = deltaY / 5;
    } else {
      player1Score++;
      ballReset();
    }
  } else if (ballX <= 10) {
    if ((ballY > mouseY - 50) && (ballY < mouseY + 50)) {
      ballSpeedX = -ballSpeedX;
      deltaY = ballY - mouseY;
      ballSpeedY = deltaY / 6;
    } else {
      player2Score++;
      ballReset();
    }
  }
}

function drawAll() {
  if (showingWinScreen) {
    colorRect(0, 0, WIDTH, HEIGHT, "black");
    canvas.fillStyle = "yellow";
    canvas.fillText("Click to continue!", 300, 300);
    if (player1Score == WINNING_SCORE) {
      canvas.fillText("You won!", 360, 500);
    } else if (player2Score == WINNING_SCORE) {
      canvas.fillText("The computer beat you!", 280, 500);
    }
    return;
  }
  colorRect(0, 0, WIDTH, HEIGHT, "black");
  drawNet();
  makeCircle(ballX, ballY, 10, 0, Math.PI * 2, "red");
  colorRect(790, paddleY, 10, 100, "cyan");
  colorRect(0, mouseY - 50, 10, 100, "yellow");
  canvas.fillStyle = "white";
  canvas.fillText(player1Score + "    " + player2Score, 360, 100);
}

感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

我认为只有一种情况可能发生:在碰撞框架中,当你降低速度时。

当速度保持不变时,无论如何,你的球总会反弹回到之前的状态。帧位置:

&#13;
&#13;
var cvs = document.querySelector("canvas");
var ctx = cvs.getContext("2d");
var balls = [
  Ball(50, 50, 0, 5, 5, "red"),
  Ball(100, 50, 0, 5, 10, "blue"),
  Ball(150, 50, 0, 5, 15, "green"),
  Ball(200, 50, 0, 5, 20, "yellow")
];

var next = () => {
  updateFrame(balls);
  drawFrame(balls);
}

var loop = () => {
  requestAnimationFrame(() => {
    next();
    loop();
  });
}

next();

function Ball(x, y, vx, vy, r, color) {
  return {
    x: x,
    y: y,
    vx: vx,
    vy: vy,
    r: r,
    color: color
  }
};

function updateBall(b) {
  b.x += b.vx;
  b.y += b.vy;
  
  if (b.y <= b.r ||
      b.y >= cvs.height - b.r) {
     b.vy *= -1; 
  }
};

function drawBall(b) {
  ctx.beginPath();
  ctx.fillStyle = b.color;
  ctx.arc(b.x, b.y, b.r, 0, 2 * Math.PI, false);
  ctx.fill();
}

function updateFrame(balls) {
   balls.forEach(updateBall); 
}

function drawFrame(balls) {
  ctx.clearRect(0, 0, cvs.width, cvs.height);
  balls.forEach(drawBall);
};
&#13;
<canvas width="300" height="150" style="background: #454545"></canvas>
<button onclick="next()">next</button>
<button onclick="loop()">run</button>
&#13;
&#13;
&#13;

但是当速度发生变化时,事情就会陷入困境:

&#13;
&#13;
var cvs = document.querySelector("canvas");
var ctx = cvs.getContext("2d");
var balls = [
  Ball(50, 50, 0, 10, 5, "red"),
  Ball(100, 50, 0, 10, 10, "blue"),
  Ball(150, 50, 0, 10, 15, "green"),
  Ball(200, 50, 0, 10, 20, "yellow")
];

var next = () => {
  updateFrame(balls);
  drawFrame(balls);
}

var loop = () => {
  requestAnimationFrame(() => {
    next();
    loop();
  });
}

next();

function Ball(x, y, vx, vy, r, color) {
  return {
    x: x,
    y: y,
    vx: vx,
    vy: vy,
    r: r,
    color: color
  }
};

function updateBall(b) {
  b.x += b.vx;
  b.y += b.vy;
  
  if (b.y <= b.r ||
      b.y >= cvs.height - b.r) {
     b.vy *= -0.5; 
  }
};

function drawBall(b) {
  ctx.beginPath();
  ctx.fillStyle = b.color;
  ctx.arc(b.x, b.y, b.r, 0, 2 * Math.PI, false);
  ctx.fill();
}

function updateFrame(balls) {
   balls.forEach(updateBall); 
}

function drawFrame(balls) {
  ctx.clearRect(0, 0, cvs.width, cvs.height);
  balls.forEach(drawBall);
};
&#13;
<canvas width="300" height="150" style="background: #454545"></canvas>
<button onclick="next()">next</button>
<button onclick="loop()">run</button>
&#13;
&#13;
&#13;

在您的情况下,我认为只有当桨碰撞和墙碰撞同时发生时才会发生这种情况。

快速实施的解决方案是在平移球位置之前检查新位置是否有效。如果您不想要精确的位置,可以将球放在碰撞点。请注意,这将产生略微偏离的帧。

E.g:

var newY = ballY + ballSpeedY;

// Top wall
if(newY <= 10) {
  ballY = 10;
  ballSpeedY = -ballSpeedY;  
}
// Bottom wall
else if(newY >= HEIGHT-10){
  ballY = HEIGHT - 10;
  ballSpeedY = -ballSpeedY;   
}
// No collision
else {
  ballY = newY;
}

更新:可能发生的更详细的描述

让我们说你的球与你的画布的顶部边框碰撞,你的划桨在同一个框架中

首先,你将球移动到碰撞位置:ballY += ballSpeedY;说你的ballY是4,你的ballSpeedY是-5,你将球定位到{ {1}},在墙内。

如果这是唯一的碰撞,你应该没问题。你翻转速度(-1),所以在下一帧中,你的球应该回到ballSpeedY = -ballSpeedY,所以-1 + 5 = 4将再次ballY,你的球会移动在下一帧中向4

现在出现问题,当在4 + 5 = 9定位的框架中,你也会碰撞桨!当球拍击球时,您可以修改空速:-1。如果结果是ballSpeedY = deltaY / 5;,那么你的球就无法在下一帧中退出。例如,您的球将移至< 1。而不是-1 + 5 = 4

现在,你的球无法重新开始比赛,因为下一帧将再次计算碰撞并翻转速度。 这会导致球在卡住时看到的弹性,颤抖效果

一个天真但相当不错的解决方案,就是只将球的位置更新为有效的位置。即:永远不要碰撞坐标。

答案 1 :(得分:0)

class App extends React.Component {
  constructor(props){
    super(props)
    this.state = { //initial empty details
      details : []  // use array
    }
  }
  componentDidMount(){
    //place the ajax call where ever you need
    $.ajax() //call ajax
    .done((data) => {
      let array = this.state.details;
      array = [...array, {
          id: data.id, 
          trackInfo: {
            title: data.title,
            artist: data.artist,
            album: data.album,
          },
          trackUrl: data.trackUrl,
          albumArt: data.albumArt,
      }];
      this.setState({
        details: array
      })
    })
  }
    render() {
      if(!this.state.details.id) return false //renders nothing when no details available
        return (
            <div id="app">
                {
                    this.state.details.map((detail) => {
                        return <MusicPlayer
                    id={detail.id}
                    visualizerType="RIPPLES"
                    theme={darkTheme}
                    trackInfo={detail.trackInfo}
                    trackUrl={detail.trackUrl}
                    albumArt={detail.albumArt}
                    utilities={true}>
                </MusicPlayer>
                    });
                }
                
            </div>
        )
    }
}

ReactDOM.render(
    <App />,
    document.getElementById("app")
);

http://jsfiddle.net/kHJr6/2/