如何在JavaScript中将重力应用于弹跳球

5

我希望将球在画布上来回弹跳转变为有重力并最终掉落。

我知道当球到达底部时需要改变速度,但我不知道应该如何处理和编码。

我是一个没有物理背景的全新JS学生,这会有多难?我很愿意学习。我尝试让球碰撞并以正确的角度弹开,但那似乎对我来说太复杂了。

var canvas,
    ctx,
    cx = 100,
    cy = 150,
    vx = 0,
    vy = 5,
    radius = 30;

function init() {

    canvas = document.getElementById("gameCanvas");
    ctx = canvas.getContext("2d");

    circle();
}

function circle() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    requestAnimationFrame(circle);

    if (cx + radius > canvas.width || cx - radius < 0)
    vx = -vx;
    if (cy + radius > canvas.height || cy - radius < 0)
    vy = -vy;

    cx += vx;  
    cy += vy;
}

我已经把cx运动移除了,只保留了上下动画和空间中的圆形绘制代码。接下来应该怎么做?

在碰撞时,我应该将当前速度乘以0.8这样的数字吗?在哪里/如何实现?

请原谅我的菜鸟水平和糟糕的代码 - 每个人都是从这里开始!

1个回答

26
你很接近了,把重力看作一个恒定的向下速度增量,所以在每一步中你需要将它添加到你的vy计算中。 “我知道当它到达底部时需要改变速度” 这不是真的,因为重力始终影响物体。当你触及底部时,会发生类似材料阻尼和表面摩擦之类的事情。

var canvas,
  ctx,
  cx = 100,
  cy = 100,
  vx = 2,
  vy = 5,
  radius = 5,
  gravity = 0.2,
  damping = 0.9,
  traction = 0.8,
  paused = false;
  ;

function init() {

  canvas = document.getElementById("gameCanvas");
  ctx = canvas.getContext("2d");
  
  canvas.width = 300;
  canvas.height = 150;

  circle();
}

function circle() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  if (!paused)
    requestAnimationFrame(circle);

  if (cx + radius >= canvas.width) {
    vx = -vx * damping;
    cx = canvas.width - radius;
  } else if (cx - radius <= 0) {
    vx = -vx * damping;
    cx = radius;
  }
  if (cy + radius >= canvas.height) {
    vy = -vy * damping;
    cy = canvas.height - radius;
    // traction here
    vx *= traction;
  } else if (cy - radius <= 0) {
    vy = -vy * damping;
    cy = radius;
  }

  vy += gravity; // <--- this is it

  cx += vx;
  cy += vy;

  ctx.beginPath();
  ctx.arc(cx, cy, radius, 0, 2 * Math.PI, false);
  ctx.fillStyle = 'green';
  ctx.fill();
}

init();

// fancy/irrelevant mouse grab'n'throw stuff below
canvas.addEventListener('mousedown', handleMouseDown);
canvas.addEventListener('mouseup', handleMouseUp);

function handleMouseDown(e) {
  cx = e.pageX - canvas.offsetLeft;
  cy = e.pageY - canvas.offsetTop;
  vx = vy = 0;
  paused = true;
}

function handleMouseUp(e) {
  vx = e.pageX - canvas.offsetLeft - cx;
  vy = e.pageY - canvas.offsetTop - cy;
  paused = false;
  circle();
}
canvas {border: 1px solid black; cursor: crosshair;}
p {margin: 0;}
<canvas id="gameCanvas"></canvas>
<p>Throw the ball by holding and releasing the left mouse button on the canvas (reverse slingshot)</p>


不客气。为了使它更加逼真,您可能需要接下来添加墙的阻尼。关于底部的行为 - 这取决于您想要做什么。故障发生的原因是球在某些时候仍然成功掉落到边缘以下。要修复它,您可以始终在碰撞发生时将球恢复到场内。 - Shomz
再次感谢,@Shomz,我有点理解了。阻尼只是在球与边缘接触时发生,并将速度X/Y减少0.9吗?我不太确定vx *= traction的含义,除了它增加了牵引力。这是否意味着每次反弹时vx运动都会减少牵引力? - joshuaaron
1
不客气。它们非常相似 - 当它碰到墙壁时会发生阻尼,你是正确的。它将适当的速度乘以阻尼因子,因此它在触及左/右边缘时影响水平速度,在触及顶部/底部边缘时影响垂直速度;而牵引力仅在球触及底部边缘时影响水平速度(这也可以适用于其他3个边缘,但我想让您看到区别)。vx *= tractionvx = vx * traction相同,只是一种简写方式。 - Shomz
1
非常有帮助!@Shomz 再次感谢你。我还有一个最后的问题,然后就不再打扰你了,但是你添加的额外部分(非常棒)中的 cx = e.pageX - canvasoffsetLeft; 是什么意思?尤其是 pageX 和 canvasoffsetLeft(以及 canvasoffsetTop)? - joshuaaron
没问题,我很高兴能帮忙!啊,你现在应该忽略那些。这是在画布元素上获取鼠标坐标的方式,这样当你释放鼠标按钮时,我可以重新定位球并重新计算其速度。这只是我添加的一点小东西,让示例更好看,让你可以更多地玩 - 它完全与问题无关。 - Shomz
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接