Javascript 为什么球在任意时间后会粘在地上?

Javascript 为什么球在任意时间后会粘在地上?,javascript,html,css,canvas,physics,Javascript,Html,Css,Canvas,Physics,我有下面的代码,它利用物理原理,将多个球沿着屏幕反弹,并将木星的重力除以10进行测试 var canvas=document.getElementById(“canvas”), ctx=canvas.getContext('2d'); //木星的重力除以10用于测试 g=24.79/10; canvas.width=window.innerWidth-50; canvas.height=window.innerHeight-22.5; 弹性=(1/2) var产卵率=16; var惯性=0.0

我有下面的代码,它利用物理原理,将多个球沿着屏幕反弹,并将木星的重力除以10进行测试

var canvas=document.getElementById(“canvas”),
ctx=canvas.getContext('2d');
//木星的重力除以10用于测试
g=24.79/10;
canvas.width=window.innerWidth-50;
canvas.height=window.innerHeight-22.5;
弹性=(1/2)
var产卵率=16;
var惯性=0.00075;
var重力=g/25;
玩家=[]
然后=新日期()/1000;
移动=假;
函数getPosition(事件){
mouseX=event.clientX;
mouseY=event.clientY;
if(moved==false){
更新();
移动=真;
}
}
函数addCircle(){
推送({x:mouseX,y:mouseY,颜色:'#000000',半径:10,velY:0,velX:2,跳跃:假,跳跃:0.02,最大值:0});
}
第一个=新日期();
函数更新(){
clearRect(0,0,canvas.width,canvas.height);
t=新日期()-第一次;
现在=新日期()/1000;
如果(现在>=1/产卵率){
然后=现在;
addCircle();
}
对于(var c=0;cMath.abs(circle.max)){
circle.max=circle.velY;
}
if(圆y+圆半径/2>画布高度){
circle.velY*=-Math.sqrt(反弹);
}
更新圆(圆);
如果(圆圈.x>画布.width){
接合(c,1);
}
}
设置超时(更新,10);
}
功能抽绳(x1、y1、x2、y2){
ctx.beginPath();
ctx.moveTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.stroke();
}
函数更新循环(播放器){
ctx.fillStyle=player.color;
ctx.beginPath();
ctx.arc(player.x,player.y,player.radius,0,Math.PI*2);
ctx.fill();
}
addEventListener(“mousemove”,getPosition,false);
if(moved==true){
更新();
}
#画布{
显示:块;
}

反弹

您的问题是碰撞检测:

这只是反转速度,但不调整位置。这意味着当你把球从一定高度落下时,它们可能会卡在地面上——它们已经进入了一定的深度,但在下一帧中,它们的减速不再足以将它们带出地面,并且再次向右翻转,使它们在地面上更深一点

你可以很容易地解决这个问题,方法是确保他们的垂直位置永远不会变为“负”,甚至不会将球完全弹离地面:

var inGround = circle.y + circle.radius - canvas.height;
if (inGround >= 0) {
    circle.velY *= -Math.sqrt(bounciness);
    circle.y -= 2*inGround;
}
请尝试更新的代码段演示:

var canvas=document.getElementById(“canvas”),
ctx=canvas.getContext('2d');
//木星的重力除以10用于测试
g=24.79/10;
canvas.width=window.innerWidth-50;
canvas.height=window.innerHeight-22.5;
弹性=(1/2)
var产卵率=16;
var惯性=0.00075;
var重力=g/25;
玩家=[]
然后=新日期()/1000;
移动=假;
函数getPosition(事件){
mouseX=event.clientX;
mouseY=event.clientY;
if(moved==false){
更新();
移动=真;
}
}
函数addCircle(){
推送({x:mouseX,y:mouseY,颜色:'#000000',半径:10,velY:0,velX:2,跳跃:假,跳跃:0.02,最大值:0});
}
第一个=新日期();
函数更新(){
clearRect(0,0,canvas.width,canvas.height);
t=新日期()-第一次;
现在=新日期()/1000;
如果(现在>=1/产卵率){
然后=现在;
addCircle();
}
对于(var c=0;cMath.abs(circle.max)){
circle.max=circle.velY;
}
var inGround=circle.y+circle.radius-canvas.height;
如果(整数>=0){
circle.velY*=-Math.sqrt(弹性);
圆y-=2*内圆;
}
更新圆(圆);
如果(圆圈.x>画布.width){
接合(c,1);
}
}
设置超时(更新,10);
}
功能抽绳(x1、y1、x2、y2){
ctx.beginPath();
ctx.moveTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.stroke();
}
函数更新循环(播放器){
ctx.fillStyle=player.color;
ctx.beginPath();
ctx.arc(player.x,player.y,player.radius,0,Math.PI*2);
ctx.fill();
}
addEventListener(“mousemove”,getPosition,false);
if(moved==true){
更新();
}
#画布{
显示:块;
}

反弹

好吧,你没有完美的弹性弹跳,一段时间后,球的垂直动量就被剥夺了。你不明白的部分是什么?@Asad看看底部的图片,很明显,尽管反弹高度应该只达到之前高度的3/4,但这似乎不正确……我正在firefox中预览你的代码,没有看到你描述的行为。你能指定你使用的浏览器并给我们看一个复制这种行为的片段吗?太好了。我马上会在firefox上试用,知道为什么会出现这种情况吗?不过我注意到了一些事情。检查高度时,为什么要将半径除以2?此外,如果您的球在一个步骤中落在画布边界以下足够远的位置,则其速度有可能在返回到边界上方之前翻转两次,从而导致翻转速度的无限循环。您应该设置绝对向上速度并将高度归零。或者,在碰撞检查分支中添加
circle.y=canvas.height-circle.radius
。@Asad:是的,这是一个简单的解决方案,将球的高度设置为零,忽略它已经进入地面的深度-它可能已经再次向上反弹。甚至可以在碰撞前做
circle.y-=inGround/*碰撞后*/+inGround*Math.sqrt(反弹)/*操作
var inGround = circle.y + circle.radius - canvas.height;
if (inGround >= 0) {
    circle.velY *= -Math.sqrt(bounciness);
    circle.y -= 2*inGround;
}