【问题标题】:Ball stops bouncing after 4-5 seconds球在 4-5 秒后停止弹跳
【发布时间】:2016-10-02 23:12:23
【问题描述】:

这里是javascript:

var canvas = document.getElementById('canvas'),
  ctx = canvas.getContext('2d'),
  ax = 50,
  ay = 50,
  avx = 5,
  avy = 2,
  radius = 50;

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

function drawArc() {
  ctx.beginPath();
  ctx.fillStyle = "white";
  ctx.arc(ax, ay, radius, 0, 2 * Math.PI);
  ctx.fill();
  ctx.closePath();
};

function update() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawArc();
  ax += avx;
  ay -= avy;
  avy -= 0.2;

  if (ay + radius >= canvas.height) {
    avy *= -0.8;
    avx *= 0.9;
  };

  if (ax + radius >= canvas.width) {
    avx = -avx;
  };

  if (ax - radius <= 0) {
    avx = -avx;
  };
}
setInterval(update, 10);
body, html {
  margin: 0;
  padding: 0;
}
#canvas {
  background-color: black;
}
&lt;canvas id="canvas"&gt;&lt;/canvas&gt;

在 Jsfiddle:https://jsfiddle.net/milosdacic/qh1ha085/

我不知道为什么会这样,代码看起来不错。

我以前做过这件事,但现在不行了。

任何帮助将不胜感激。

【问题讨论】:

  • 你想让它永远反弹吗?
  • 您预计会发生什么?您已经编写了代码,每次击球时,球的速度都会降低(摩擦)。因此,一段时间后球停止移动是正常的。
  • 如果您不想降低高度,您需要跟踪每次反弹时的所有动能。这个答案stackoverflow.com/a/34187884/3877726 演示了如何做一个简单的弹跳球,随着时间的推移不会失去能量。 stackoverflow.com/a/34187884/3877726
  • 我不想让球永远弹跳,我只想自然地停止弹跳,而不是一瞬间冻结。
  • 通过每次将 avy 减少 0.8,您试图模拟一种能量损失,其中损失的能量实际上不是线性的。但是,您可以将其更改为 0.9 或更高以获得更长的动画。

标签: javascript html css canvas


【解决方案1】:

简短的回答是你得到了很多安打,因为你没有把球从地面上移开。下一帧它仍然在撞击地面,当你降低它的速度时它就会陷入困境..

在你的小提琴第 29 行之后添加这个。

ay = canvas.height - radius;

For more on bouncing a ball

【讨论】:

  • 非常感谢。你们这里真棒:)
【解决方案2】:

我猜你想要这个:

var canvas = document.getElementById('canvas'),
  ctx = canvas.getContext('2d'),
  ax = 50,
  ay = 50,
  avx = 5,
  avy = 2,
  radius = 50;

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

function drawArc() {
  ctx.beginPath();
  ctx.fillStyle = "white";
  ctx.arc(ax, ay, radius, 0, 2 * Math.PI);
  ctx.fill();
  ctx.closePath();
};

var hitTheGround = 0;
function update() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawArc();
  ax += avx;
  ay -= avy;
  avy -= 0.2;

  if (ay + radius >= canvas.height) {
    avy *= -0.8;
    avx *= 0.9;
  }
  
  if (ax + radius >= canvas.width) {
    avx = -avx;
  }

  if (ax - radius <= 0) {
    avx = -avx;
  }
  
  if(ay + radius >= canvas.height - 3) {
    hitTheGround++;
  }
  else {
    hitTheGround = 0;  
  }
  
  if(hitTheGround == 100) { // if it jumps near the ground too frequently
    return setTimeout(function() {clearInterval(interval)}, 1000);
  }
}
var interval = setInterval(update, 10);
body, html {
  margin: 0;
  padding: 0;
}
#canvas {
  background-color: black;
}
&lt;canvas id="canvas"&gt;&lt;/canvas&gt;

在它在地面附近跳跃(振动)N 次之后停止调用 update 的小脏修复。

【讨论】:

  • 我不想要无限弹跳我只想正常弹跳而不是在几次落地后冻结。只需观看球弹跳 5-6 秒,您就会发现球在某一时刻只是冻结在地板上。
  • @MilosDacic 现在检查 :)
  • 嗯,不工作。我会上传一个视频,让你看看是什么问题。也许它只是在我的电脑上:(
  • @MilosDacic 没有耐心,我会在 1 秒后停止动画,而不是在地面上振动,随意更改 setTimeout
【解决方案3】:

好的,首先,工作的代码。

<html>
  <head>
    <style>
body, html {
  margin: 0;
  padding: 0;
}
#canvas {
  background-color: black;
}
    </style>
    <script>
function drawArc() {
  ctx.beginPath();
  ctx.fillStyle = "white";
  ctx.arc(ax, ay, radius, 0, 2 * Math.PI);
  ctx.fill();
  ctx.closePath();
};

function update() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawArc();
  ax += avx;
  ay -= avy;
  avy -= 0.2;

  if (ay + radius >= canvas.height) {
    avy *= -0.8;
    avx *= 0.9;
  };

  if (ax + radius >= canvas.width) {
    avx = -avx;
  };

  if (ax - radius <= 0) {
    avx = -avx;
  };
}

function onload()
{
canvas = document.getElementById('canvas');
ctx = canvas.getContext('2d');
ax = 50;
ay = 50;
avx = 5;
avy = 2;
radius = 50;

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
setInterval(update, 10);
}
    </script>
    <style>
    </style>
  </head>
  <body onload="onload()">
    <canvas id="canvas"></canvas>
  </body>
</html>

第二,问题是什么。我认为我遇到的最大问题是您提供的代码在全局上下文中具有变量和操作,这些变量和操作依赖于尚未创建的页面元素。这意味着canvas和cxt的变量不能被创建,因为canvas标签还没有被创建。我把所有这些都放到了一个函数中,当页面加载完毕并且一切正常时,我可以调用它。现在,当调用该函数时,画布已经存在,您可以使用它来创建上下文并执行其他所有操作。

第三基于你想知道它为什么停止弹跳的问题标题。我认为你已经正确地创建了一个弹跳球,它从墙壁和地板上反弹,但由于重力和与地面的非弹性碰撞而损失了能量。就个人而言,我没有完成代码,但它看起来很棒。你为什么要改变它。如果你想让它永远弹跳,那么与墙壁和地板的碰撞需要 100% 弹性——这意味着你不会失去任何能量,并且你的球弹跳得和以前一样高。在与 FLOOR 的交互中,您使用下面的代码。这具有阻尼效果,并最终将您的球降至零能量。

avy *= -0.8;//could be -1
avx *= 0.9;//could be 1

然而,这又产生了另一个问题。您正在使用的代码需要阻尼,否则每次弹跳时球只会弹得更高。这是因为你在这条线上加速并获得能量。

avy -= 0.2;

您的其他答案之一建议您减少阻尼,但不要通过更改这一行来完全消除它。您必须对其进行调整以使其具有您想要的行为。

avy *= -0.8;//-0.8 is too little? -1 is too much

最后一次编辑,我保证。我实际上玩得很开心。这个问题并不是微不足道的,您可以只输入伪物理并获得一个很好的球弹跳模拟。即使你输入了所有正确的方程,你仍然会得到一个小的永久反弹,因为这就是现实生活中发生的事情。当球移动得足够慢并且离地面足够近时,其他力(不是重力,而是强、弱和电磁吸引力)占主导地位并导致球停止移动。所以,我又刷了一遍,物理性能有了很大的提高。它并不完美,但在某些时候你不得不问模拟的保真度是否比平滑行为以匹配我想要看到的更重要。希望这会有所帮助。

<html>
  <head>
    <style>
body, html {
  margin: 0;
  padding: 0;
}
#canvas {
  background-color: black;
}
    </style>
    <script>
function drawArc() {
  ctx.beginPath();
  ctx.fillStyle = "white";
  ctx.arc(xPos, yPos, radius, 0, 2 * Math.PI);
  ctx.fill();
  ctx.closePath();
};

function update() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawArc();
  var dx = xVel*timeStep;
  var dy = yVel*timeStep;

  if(yVel<radius && yVel>-radius && canvas.height-(yPos+radius) < .1)
  {
    yVel = 0;
    yPos = canvas.height-radius;
    dy=0;

    //friction affects xVel
    xVel *= fFloor;
  }
  else if (yPos + dy + radius >= canvas.height) {
    //you will be below the floor; there is a bounce

    //find the rest of the falling interval
    var remainingY = canvas.height-(yPos+radius);

    //find the rest of the time step    
    var remainingTime = remainingY / yVel;

    //add acceleration for that time
    yVel += gravity * remainingTime

    //friction affects xVel
    xVel *= fFloor;

    //elasticity affects yVel
    yVel *= eFloor;

    //now you are bouncing up
    //what is time up
    remainingTime = timeStep - remainingTime;

    //set final position
    yPos = canvas.height + (yVel*remainingTime) - radius;

    //add acceleration for that time
    yVel += gravity * remainingTime;
  }

  else
  {
    //do not hit the floor, falling the whole time
    yPos += dy;
    yVel += gravity * timeStep;
  }

  if (xPos + dx + radius >= canvas.width)
  {
    //hit a wall; there is a bounce

    //find the rest of the interval
    var remainingX = canvas.width-(xPos+radius);

    //find the rest of the time step    
    var remainingTime = remainingX / xVel;

    //no horizontal acceleration

    //friction affects yVel
    yVel *= fWall;

    //elasticity affects xVel
    xVel *= eWall;

    //now you are bouncing back
    //what is time up
    remainingTime = timeStep - remainingTime;

    //set final position
    xPos = canvas.width + (xVel*remainingTime) - radius;

    //no horizontal acceleration
  }
  else if (xPos + dx - radius <= 0) {
    //hit a wall; there is a bounce

    //find the rest of the interval
    var remainingX = (xPos - radius);

    //find the rest of the time step    
    var remainingTime = remainingX / xVel;

    //no horizontal acceleration

    //friction affects yVel
    yVel *= fWall;

    //elasticity affects xVel
    xVel *= eWall;

    //now you are bouncing back
    //what is time up
    remainingTime = timeStep - remainingTime;

    //set final position
    xPos = xVel*remainingTime+radius;

    //no horizontal acceleration
  }
  else {
    //never hit a wall; flying the whole time
    xPos += dx;   
  }
}

function onload()
{
canvas = document.getElementById('canvas');
ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
radius = 15;
xPos = Math.random()*(canvas.width-(2*radius))+radius;
yPos = Math.random()*(canvas.height-(2*radius))+radius;
xVel = Math.random()*100-50;
yVel = Math.random()*100-50;
gravity = 9.8;
eWall = -1;
eFloor = -.8;
fFloor = .9;
fWall = .9;
interval = 10;
timeStep = .1;//apparent time step

setInterval(update, interval);
}
    </script>
    <style>
    </style>
  </head>
  <body onload="onload()">
    <canvas id="canvas"></canvas>
  </body>
</html>

【讨论】:

    猜你喜欢
    • 2013-05-23
    • 1970-01-01
    • 1970-01-01
    • 2016-07-24
    • 1970-01-01
    • 1970-01-01
    • 2020-01-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多