计算球到达目的地所需时间的公式,球的 x y 在时间循环中更新
Formula to calculate time needed for a ball to reach destination where the ball's x y is updated in a time loop
我正在编写球运动的模拟代码。我有一个 updateBall 函数,它每 100 毫秒运行一次以更新球的位置。
计算到达给定目标坐标所需时间(以毫秒为单位)的公式如何计算?例如,给定目标 x=100 y=200 达到目标所需的时间约为 5300 毫秒。
下面是相关的代码片段,
function calcDirection(a, b, c, d)
{ return 180 * Math.atan2(d - b, c - a) / Math.PI };
let ball = {x: 0, y: 0}
let targetX = 100;
let targetY = 200;
let velocity = 0.05;
let friction = 0.0003;
let direction = calcDirection(ball.x,ball.y,targetX,targetY); //63.43494882292201
let dx = targetX - ball.x;
let dy = targetY - ball.y;
let distance = Math.sqrt(dx*dx + dy*dy); //223.60679774997897
// runs every 100ms
function updateBall(){
if (velocity > 0) {
let pixelsPerLoop = velocity * 100;
ball.x += pixelsPerLoop * Math.cos(Math.PI/180 * direction);
ball.y += pixelsPerLoop * Math.sin(Math.PI/180 * direction);
velocity -= friction;
}
}
//answer: ( v0 (+/-) sqrt( v0^2 - 2.0*friction*dist ) )/(friction)
let v0 = velocity * 100;
let fric = friction * 100;
let p = Math.pow(v0, 2);
let q = 2.0 * fric * distance;
let r = p - q;
let s = Math.sqrt(r);
let t = ( v0 - s )/(fric);
// test run for loop times
let loop = Math.floor(t);
for (let i = 0; i < loop; i++)
updateBall();
document.getElementById('result').innerHTML = 'loop ' + loop + ', ball.x = ' + ball.x + ' ball.y = ' + ball.y;
<p id="result"></p>
我的数学有点生疏,所以如果我没记错的话应该是这样的:
v(t) = v0 - friction*t // speed
s(t) = Integral(v(t)) // position or signed traveled distance if start position is zero
-------------------------------
s(t) = v0*t - 0.5*friction*t^2 // s(t) = dist (distance to target)
dist = v0*t - 0.5*friction*t^2
0.5*friction*t^2 - v0*t + dist = 0
-----------------------------------
t = ( v0 (+/-) sqrt( v0^2 - 2.0*friction*dist ) )/(friction)
其中 t
是时间,dist
是从起点到目标的距离。
所以你得到了 t
的 2 个解决方案,所以使用一个有意义的(非负面的)。如果没有这样的一个,就意味着你的球永远不会到达你的目标。
顺便说一句,一旦你想添加重力和其他力场或障碍物,那么你应该将 math/physics 更改为 Newton D'Alembert integration 而不是使用方向向量将你的问题转换为一维相当有限。
[编辑2]
不要忘记使用兼容的单位,因为您使用 0.1 秒的更新间隔,并且您将速度乘以 100,所以:
friction = 0.0003/0.1 = 0.003 m/s^2
v0 = 0.05*100/0.1 = 50.0 m/s
dist = sqrt(100^2 + 200^2) = 223.6068 m
t = ( v0 (+/-) sqrt( v0^2 - 2.0*friction*dist ) )/(friction)
t = ( 50 (+/-) sqrt( 2500 - 2.0*0.003*223.6068 ) )/(0.003)
t = ( 50 (+/-) sqrt( 2500 - 1.3416408 ) )/(0.003)
t = ( 50 (+/-) sqrt( 2498.6583592 ) )/(0.003)
t = ( 50 (+/-) 49.9566 )/(0.003)
t1 = 33328.8603075022
t2 = 4.47273608634165
因此您在 4.47 秒内达到了目标...这里是移植到 C++ 的模拟值:
t v x y
0.0 5.000 2.236 4.472
0.1 4.999 4.472 8.944
0.2 4.999 6.708 13.416
0.3 4.999 8.943 17.887
0.4 4.999 11.179 22.358
0.5 4.998 13.414 26.829
0.6 4.998 15.650 31.299
0.7 4.998 17.885 35.770
0.8 4.997 20.120 40.240
0.9 4.997 22.355 44.709
1.0 4.997 24.589 49.179
1.1 4.996 26.824 53.648
1.2 4.996 29.058 58.117
1.3 4.996 31.293 62.585
1.4 4.996 33.527 67.054
1.5 4.995 35.761 71.522
1.6 4.995 37.995 75.990
1.7 4.995 40.229 80.457
1.8 4.994 42.462 84.925
1.9 4.994 44.696 89.392
2.0 4.994 46.929 93.859
2.1 4.993 49.163 98.325
2.2 4.993 51.396 102.791
2.3 4.993 53.629 107.257
2.4 4.993 55.861 111.723
2.5 4.992 58.094 116.188
2.6 4.992 60.327 120.654
2.7 4.992 62.559 125.118
2.8 4.991 64.792 129.583
2.9 4.991 67.024 134.047
3.0 4.991 69.256 138.511
3.1 4.990 71.488 142.975
3.2 4.990 73.719 147.439
3.3 4.990 75.951 151.902
3.4 4.990 78.183 156.365
3.5 4.989 80.414 160.828
3.6 4.989 82.645 165.290
3.7 4.989 84.876 169.753
3.8 4.988 87.107 174.215
3.9 4.988 89.338 178.676
4.0 4.988 91.569 183.138
4.1 4.987 93.799 187.599
4.2 4.987 96.030 192.060
4.3 4.987 98.260 196.520
4.4 4.987 100.490 200.981
正如您所看到的,您的模拟在 4.5 秒之前就达到了目标,但是您的 5.3 秒结果太远了,因此仍然存在可疑之处。
此外,真实摩擦的行为也不同,它会按比例增加实际速度,因此它会像这样应用:
v *= 1.0-friction*dt*v^2;
其中 dt
是您使用 dt=0.1
更新的间隔,但是上面的等式将不再有效,因为它也改变了 v(t)
函数。
我正在编写球运动的模拟代码。我有一个 updateBall 函数,它每 100 毫秒运行一次以更新球的位置。
计算到达给定目标坐标所需时间(以毫秒为单位)的公式如何计算?例如,给定目标 x=100 y=200 达到目标所需的时间约为 5300 毫秒。
下面是相关的代码片段,
function calcDirection(a, b, c, d)
{ return 180 * Math.atan2(d - b, c - a) / Math.PI };
let ball = {x: 0, y: 0}
let targetX = 100;
let targetY = 200;
let velocity = 0.05;
let friction = 0.0003;
let direction = calcDirection(ball.x,ball.y,targetX,targetY); //63.43494882292201
let dx = targetX - ball.x;
let dy = targetY - ball.y;
let distance = Math.sqrt(dx*dx + dy*dy); //223.60679774997897
// runs every 100ms
function updateBall(){
if (velocity > 0) {
let pixelsPerLoop = velocity * 100;
ball.x += pixelsPerLoop * Math.cos(Math.PI/180 * direction);
ball.y += pixelsPerLoop * Math.sin(Math.PI/180 * direction);
velocity -= friction;
}
}
//answer: ( v0 (+/-) sqrt( v0^2 - 2.0*friction*dist ) )/(friction)
let v0 = velocity * 100;
let fric = friction * 100;
let p = Math.pow(v0, 2);
let q = 2.0 * fric * distance;
let r = p - q;
let s = Math.sqrt(r);
let t = ( v0 - s )/(fric);
// test run for loop times
let loop = Math.floor(t);
for (let i = 0; i < loop; i++)
updateBall();
document.getElementById('result').innerHTML = 'loop ' + loop + ', ball.x = ' + ball.x + ' ball.y = ' + ball.y;
<p id="result"></p>
我的数学有点生疏,所以如果我没记错的话应该是这样的:
v(t) = v0 - friction*t // speed
s(t) = Integral(v(t)) // position or signed traveled distance if start position is zero
-------------------------------
s(t) = v0*t - 0.5*friction*t^2 // s(t) = dist (distance to target)
dist = v0*t - 0.5*friction*t^2
0.5*friction*t^2 - v0*t + dist = 0
-----------------------------------
t = ( v0 (+/-) sqrt( v0^2 - 2.0*friction*dist ) )/(friction)
其中 t
是时间,dist
是从起点到目标的距离。
所以你得到了 t
的 2 个解决方案,所以使用一个有意义的(非负面的)。如果没有这样的一个,就意味着你的球永远不会到达你的目标。
顺便说一句,一旦你想添加重力和其他力场或障碍物,那么你应该将 math/physics 更改为 Newton D'Alembert integration 而不是使用方向向量将你的问题转换为一维相当有限。
[编辑2]
不要忘记使用兼容的单位,因为您使用 0.1 秒的更新间隔,并且您将速度乘以 100,所以:
friction = 0.0003/0.1 = 0.003 m/s^2
v0 = 0.05*100/0.1 = 50.0 m/s
dist = sqrt(100^2 + 200^2) = 223.6068 m
t = ( v0 (+/-) sqrt( v0^2 - 2.0*friction*dist ) )/(friction)
t = ( 50 (+/-) sqrt( 2500 - 2.0*0.003*223.6068 ) )/(0.003)
t = ( 50 (+/-) sqrt( 2500 - 1.3416408 ) )/(0.003)
t = ( 50 (+/-) sqrt( 2498.6583592 ) )/(0.003)
t = ( 50 (+/-) 49.9566 )/(0.003)
t1 = 33328.8603075022
t2 = 4.47273608634165
因此您在 4.47 秒内达到了目标...这里是移植到 C++ 的模拟值:
t v x y
0.0 5.000 2.236 4.472
0.1 4.999 4.472 8.944
0.2 4.999 6.708 13.416
0.3 4.999 8.943 17.887
0.4 4.999 11.179 22.358
0.5 4.998 13.414 26.829
0.6 4.998 15.650 31.299
0.7 4.998 17.885 35.770
0.8 4.997 20.120 40.240
0.9 4.997 22.355 44.709
1.0 4.997 24.589 49.179
1.1 4.996 26.824 53.648
1.2 4.996 29.058 58.117
1.3 4.996 31.293 62.585
1.4 4.996 33.527 67.054
1.5 4.995 35.761 71.522
1.6 4.995 37.995 75.990
1.7 4.995 40.229 80.457
1.8 4.994 42.462 84.925
1.9 4.994 44.696 89.392
2.0 4.994 46.929 93.859
2.1 4.993 49.163 98.325
2.2 4.993 51.396 102.791
2.3 4.993 53.629 107.257
2.4 4.993 55.861 111.723
2.5 4.992 58.094 116.188
2.6 4.992 60.327 120.654
2.7 4.992 62.559 125.118
2.8 4.991 64.792 129.583
2.9 4.991 67.024 134.047
3.0 4.991 69.256 138.511
3.1 4.990 71.488 142.975
3.2 4.990 73.719 147.439
3.3 4.990 75.951 151.902
3.4 4.990 78.183 156.365
3.5 4.989 80.414 160.828
3.6 4.989 82.645 165.290
3.7 4.989 84.876 169.753
3.8 4.988 87.107 174.215
3.9 4.988 89.338 178.676
4.0 4.988 91.569 183.138
4.1 4.987 93.799 187.599
4.2 4.987 96.030 192.060
4.3 4.987 98.260 196.520
4.4 4.987 100.490 200.981
正如您所看到的,您的模拟在 4.5 秒之前就达到了目标,但是您的 5.3 秒结果太远了,因此仍然存在可疑之处。
此外,真实摩擦的行为也不同,它会按比例增加实际速度,因此它会像这样应用:
v *= 1.0-friction*dt*v^2;
其中 dt
是您使用 dt=0.1
更新的间隔,但是上面的等式将不再有效,因为它也改变了 v(t)
函数。