我制作了一个带有二次拖动的最小水平运动模拟器,可以在here中找到它(由左右箭头键控制)。作为练习,我尝试除了施加力和阻力之外还实施制动。在按住空格键的同时它可以工作,但是释放后,盒子又开始以低速向看似随机的方向移动。我认为这是相关的代码:

let vt = 500 // terminal velocity
let amag = 1000 // magnitude of applied acceleration
let bmag = 1000 // magnitude of brake's acceleration
let drag = amag / (vt*vt) // coeffcient of quadratic drag

let x  = 0 // horizontal position
let vx = 0 // horizontal velocity

function update(timestamp) {
  let dt = ... // compute time delta from timestamp

  // current acceleration
  let ax = (keyStates.ArrowRight * amag) + (keyStates.ArrowLeft * -amag) - (keyStates[' '] * bmag * Math.sign(vx))

  // forward euler method; solves (x'(t), vx'(t)) = (vx(t), ax(t) - drag * vx(t)^2)
  x  += dt * vx
  vx += dt * (ax - Math.sign(vx) * drag * vx * vx)
}

最佳答案

缓慢移动时,制动幅度大于vx。此外,您的制动力与您移动的方向相反。因此,制动不是将vx从0输出,而是在0附近反弹vx

例如。想象bmag = 1dt = 1vx = 2.6。而不是vx转到2.6 -> 1.6 -> 0.6 -> 0,而是转到2.6 -> 1.6 -> 0.6 -> -0.4 -> 0.6 -> -0.4...

制动时这并不明显,因为运动不断地相互抵消,因此它们相互抵消。但是一旦松开制动器,制动器就会根据时间在0.6-0.4处继续,因此观察到的“看似随机的方向”。

要解决此问题,只需在vx时将bmag * dt > vx归零即可。

  // current acceleration
  let ax = (keyStates.ArrowRight * amag) + (keyStates.ArrowLeft * -amag);

  // forward euler method; solves (x'(t), vx'(t)) = (vx(t), ax(t) - drag * vx(t))
  x  += dt * vx
  vx += dt * (ax - Math.sign(vx) * drag * vx * vx)

  if (keyStates[' '])
     if (Math.abs(vx) > dt * bmag)
       vx -= dt * bmag * Math.sign(vx);
     else
       vx = 0;


顺便说一句,感谢您提供了可复制的示例和相关的一小部分。它可以帮助潜在的回复者和将来的读者。

关于javascript - 完全踩下制动器后,为什么箱子仍在移动?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58630530/

10-11 06:48