我制作了一个带有二次拖动的最小水平运动模拟器,可以在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 = 1
,dt = 1
和vx = 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/