Javascript 为什么赢了';在我的乒乓球游戏中,球不会完全反弹吗?
我在javascript的画布上有多个省略号,我希望它们都能相互反弹。我尝试使用距离公式,然后在距离小于球半径*2时更改球的x和y方向 这对于一个球来说效果很好,但是对于很多球来说效果不太好,因为它经常会导致可怕的“反弹循环” 为了解决这个问题,我决定根据球相互碰撞的位置改变球反弹的方式,以避免反弹循环,并使游戏更接近现实物理 如果有侧向碰撞,我想反转两个球的x方向,如果有上下碰撞,我想反转两个球的y方向 因此,我计算了所有的点,例如,45度到135度之间与度相关的点(即90点),并将它们与225度到315度之间的所有90点进行比较,反之亦然 如果圆边缘上的任意点与所有其他球中心点之间的距离小于半径,我希望两个球的Y方向都反转 我在135度和225度到315度和405度(相当于45度)重复相同的过程,并反转两个球的X方向 就目前而言,我认为球应该按照我所希望的方式相互反弹,但事实并非如此。它们从彼此的侧面、顶部、底部反弹,偶尔也会以一定角度反弹,但它们倾向于彼此向内倾斜,然后改变方向。这是一个 下面是从上到下比较的代码:Javascript 为什么赢了';在我的乒乓球游戏中,球不会完全反弹吗?,javascript,arrays,object,for-loop,continue,Javascript,Arrays,Object,For Loop,Continue,我在javascript的画布上有多个省略号,我希望它们都能相互反弹。我尝试使用距离公式,然后在距离小于球半径*2时更改球的x和y方向 这对于一个球来说效果很好,但是对于很多球来说效果不太好,因为它经常会导致可怕的“反弹循环” 为了解决这个问题,我决定根据球相互碰撞的位置改变球反弹的方式,以避免反弹循环,并使游戏更接近现实物理 如果有侧向碰撞,我想反转两个球的x方向,如果有上下碰撞,我想反转两个球的y方向 因此,我计算了所有的点,例如,45度到135度之间与度相关的点(即90点),并将它们与2
// radius is the same for all the balls and is at 25.
let ballToBallDistance = (x1, y1, x2, y2) => {
return Math.sqrt((Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)));
}
const ballCollisionY = (start, end) => {
for (let i = start; i <= end; i++) {
return ballObjects[0].ballRadius * Math.sin((i * Math.PI / 180));
}
}
const ballCollisionX = (start, end) => {
for (let i = start; i <= end; i++) {
return ballObjects[0].ballRadius * Math.cos((i * Math.PI / 180));
}
}
const upperYBall = {
bounceTopBottom() {
let n = 0;
for (let i = 0; i < ballObjects.length; i++) {
if (ballObjects.length == 1) {
return;
}
if (n == i) {
continue;
}
let yUpXPoint = ballObjects[n].ballXPos - ballCollisionX(45, 135);
let yUpYPoint = ballObjects[n].ballYPos - ballCollisionY(45, 135);
let centerBallX = ballObjects[i].ballXPos;
let centerBallY = ballObjects[i].ballYPos;
let pointDistance = ballToBallDistance(yUpXPoint, yUpYPoint, centerBallX, centerBallY);
if (pointDistance <= 25) {
ballObjects[n].ballMotionY = ballObjects[n].ballMotionY * -1;
}
if (i == ballObjects.length - 1) {
++n;
i = -1;
continue;
}
}
}
}
const lowerYBall = {
bounceBottomTop() {
let n = 0;
for (let i = 0; i < ballObjects.length; i++) {
if (ballObjects.length == 1) {
return;
}
if (n == i) {
continue;
}
let yDownXPoint = ballObjects[n].ballXPos - ballCollisionX(225, 315);
let yDownYPoint = ballObjects[n].ballYPos - ballCollisionY(225, 315);
let centerBallX = ballObjects[i].ballXPos;
let centerBallY = ballObjects[i].ballYPos;
let pointDistance = ballToBallDistance(yDownXPoint, yDownYPoint, centerBallX, centerBallY);
if (pointDistance <= 25) {
ballObjects[n].ballMotionY = ballObjects[n].ballMotionY * -1;
}
if (i == ballObjects.length - 1) {
++n;
i = -1;
continue;
}
}
}
}
//所有球的半径相同,为25。
设ballToBallDistance=(x1,y1,x2,y2)=>{
返回Math.sqrt((Math.pow(x2-x1,2)+Math.pow(y2-y1,2));
}
const ballCollisionY=(开始、结束)=>{
for(让我=开始;我{
对于(让i=start;i我建议您从特例编码切换到更通用的方法
当两个球碰撞时:
计算碰撞法线(角度)
根据以前的速度和法线计算新速度
重新定位球,使其不再重叠,防止“反弹循环”
您将需要:
计算两个球之间角度的方法:
function ballToBallAngle(ball1,ball2) {
return Math.atan2(ball2.y-ball1.y,ball2.x-ball1.x)
}
从角度导出法向量的方法:
function calcNormalFromAngle(angle){
return [
Math.cos(angle),
Math.sin(angle)
]
}
计算两个向量的点积的方法:
function dotproduct (a, b){
return a.map((x, i) => a[i] * b[i]).reduce((m, n) => m + n)
}
最后给出了一种计算弹跳角的方法,对其进行了完美的描述
因此,要将其放在一起,请参见下面的片段:
let canvas=document.querySelector('canvas')
设ctx=canvas.getContext('2d')
让球=[
{x:40,y:40,半径:25,vx:4,vy:3},
{x:300,y:300,半径:50,vx:-2,vy:-3},
{x:100,y:220,半径:25,vx:4,vy:-3},
{x:400,y:400,半径:50,vx:-1,vy:-3},
{x:200,y:400,半径:32,vx:2,vy:-3}
]
函数tick(){
球。forEach((球,索引)=>{
ball.x+=ball.vx
ball.y+=ball.vy
//检查x边界冲突
if(球x-球半径<0){
弹跳球(球,数学,圆周率)
ball.x=ball.radius
}否则如果(球x+球半径>500){
弹跳球(球,0)
球体x=500-球体半径
}
//检查y边界碰撞
if(球y-球半径<0){
弹跳球(球,Math.PI/2)
ball.y=ball.radius
}否则如果(球y+球半径>500){
弹跳球(球,-Math.PI/2)
球体y=500-球体半径
}
球。forEach((其他球,其他指数)=>{
如果(索引==其他索引)
返回
//球相交多少像素
让交点=球半径+其他球半径-球到球距离(球,其他球)
//如果大于0,则它们必须碰撞
如果(交点>0){
让球角度=球角度(球、其他球)
让法线=calcNormalFromAngle(角度)
弹跳球(球、角度)
弹跳球(其他球,角度+数学PI)
//设置位置,使它们不再重叠
ball.x-=法线[0]*交点/2
ball.y-=法线[1]*交点/2
其他球x+=正常[0]*交点/2
其他球y+=正常[1]*交点/2
}
})
})
render()
requestAnimationFrame(勾选)
}
函数render(){
clearRect(0,0,canvas.width,canvas.height)
balls.forEach(ball=>{
ctx.beginPath();
弧(ball.x,ball.y,ball.radius,0,2*Math.PI);
ctx.stroke();
})
}
功能弹跳球(球、角度){
让法线=calcNormalFromAngle(角度)
让速度=[ball.vx,ball.vy]
设ul=点积(速度,正常)/点积(正常,正常)
设u=[
正常[0]*ul,
正常[1]*ul
]
设w=[
速度[0]-u[0],
速度[1]-u[1]
]
设新的_速度=[
w[0]-u[0],
w[1]-u[1]
]
ball.vx=新的_速度[0]
ball.vy=新的速度[1]
}
功能点积(a,b){
返回a.map((x,i)=>a[i]*b[i])。reduce((m,n)=>m+n)
}
功能球到球距离(球1、球2){
返回Math.sqrt((Math.pow(ball2.x-ball1.x,2)+Math.pow(ball2.y-ball1.y,2));
}
函数ballToBallAngle(ball1、ball2){
返回Math.atan2(ball2.y-ball1.y,ball2.x-ball1.x)
}
函数calcNormalFromAngle(角度){
返回[
数学cos(角度),
数学。sin(角度)
]
}
勾选();
正文{
背景色:#eee;
}
帆布{
背景色:白色;
}