考虑随时间推移的加速和减速的对象插值



我正在用Javascript构建一个模拟器,并且自从我毕业以来已经有一段时间了,我一直在努力理解物理学和运动学的基础知识。无论如何,我有一个应该模拟时间的循环,循环的每次迭代都等于 1 秒,我有一个对象,我想从第A点 ([150, 50]( 移动到第B点 ([1, 1](。该物体的最大速度为104.9的加速度和-4.9的减速。我在循环的每次迭代(1 秒(时都会重新计算目标位置,但是当我必须减速时它不起作用,因为在某些时候速度是负的。我可以使用任何公式来计算插值,考虑从 A 点移动到 B 点的每 x 秒的加速和减速?

这是我的代码的当前状态:

const math = require('mathjs');
const { distance } = require('mathjs');
let currentPos = [150, 51];
const targetPosition = [1, 1];
const MAX_SPEED = 10;
const BASE_ACCELERATION = 4.9;
let currentVelocity= 0;
let stopping = false;
const interpolate = (pos, velocity, target, acceleration, t) => {
const d = math.distance(target, pos);
const delta = math.subtract(target, pos);
const ratio = math.divide(delta, d);
const v = Math.min(velocity + (acceleration * t), MAX_SPEED);
const newPos = move(pos, ratio, lerp(velocity, v, t));
return { pos: newPos, d , v, ratio };
};
const move = (pos, ratio, velocity) => {
return math.chain(ratio)
.multiply(velocity)
.add(pos)
.done();
};
const lerp = (v0, v1, t) => {
return v0 + t * (v1 - v0);
};
const getStopDistance = (v0, a) => v0 / 2 * a;

// Let's say I'm simulating 15 seconds 
for (let i = 0; i < 15; i++) {
console.log(`####### sec ${i} #######`);
console.log(`currentPos -> `, currentPos);
console.log(`currentVelocity -> `, currentVelocity);
console.log(`stopping -> `, stopping);
const sd = getStopDistance(currentVelocity, BASE_ACCELERATION);
const a = (stopping) ? -BASE_ACCELERATION : BASE_ACCELERATION;
const it = interpolate(currentPos, currentVelocity, targetPosition, a, 1);
if (it.d == 0)
break;
console.log('sd -> ', sd);
console.log('it -> ', it);
if (!stopping && sd >= it.d) {
// Trying to break it down in 2 equations within 1 sec. The first with the current velocity and accelerations and the rest should be the time I should start stopping ?**strong text**
const d1 = sd - it.d;
const t1 = (2 * d1) / (currentVelocity + currentVelocity);
const i1 = interpolate(currentPos, currentVelocity, targetPosition, BASE_ACCELERATION, t1);
const t2 = 1 - t1;
const i2 = interpolate(i1.pos, i1.v, targetPosition, -BASE_ACCELERATION, t2);
console.log('d1 -> ', d1);
console.log('t1 -> ', t1);
console.log('i1 -> ', i1);
console.log('t2 -> ', t2);
console.log('i2 -> ', i2);
stopping = true;
currentPos = i2.pos;
currentVelocity = i2.v;
} else {
currentPos = it.pos;
currentVelocity = it.v;
}
}

让我们将问题背后的数学视为一维问题。让我们沿着连接起点和终点的直线找到物体的运动轮廓。

给定L点之间的距离、最大速度v_max和可用的加速和减速a,运动分为三个状态。下面是总行进距离x的数学运算,以及速度v(给定的是伪代码(

  • 加速度

    t = 0 ... v_max/a
    x = 0.5*a*t^2
    v = a*t
    
  • 滑行

    t = v_max/a ... L/v_max
    x = t*v_max - 0.5*v_max^2/a
    v = v_max
    
  • 减速

    t = L/v_max ... v_max/a+l/v_max
    x = t*v_max - a*(L-t*v_max)^2/(2*v_max^2)-v_max^2/(2*a)
    v = v_max - a*(t - L/v_max) + v_max
    

这些是从标准运动学方程中得出的,受最大速度和总行驶距离的限制。

根据您关于首先找到 A 和 B 之间距离的评论,我将在黑暗中拍摄您可能正在寻找一个缓入"补间"功能。

如果您知道从 A 到 B 的距离,并且知道希望整个动画持续多长时间(即持续时间(,那么您就不需要考虑加速度。您可以根据抛物线、二次曲线、正弦曲线或其他类型的曲线获取任何时间点的速度,该曲线从起始速度 (0( 到结束速度 (0(,最大速度和曲线峰值由曲线的属性决定。

这里显示了大量的输入/输出缓动函数: https://gizma.com/easing/

如果要根据已知的加速度和距离对此类曲线进行逆向工程,则可以分别用位置和距离替换t时间和d持续时间。

最新更新