Javascript 考虑加速和减速的物体插值

Javascript 考虑加速和减速的物体插值,javascript,interpolation,game-physics,physics,kinematics,Javascript,Interpolation,Game Physics,Physics,Kinematics,我正在用Javascript构建一个模拟器,并努力理解物理学和运动学的基础知识,因为我毕业已经有一段时间了。无论如何,我有一个循环,它应该模拟时间,循环的每次迭代都等于1秒,我有一个对象,我想从点a([150,50])移动到点B([1,1])。物体的最大速度为10,加速度为4.9,减速为-4.9。每次循环(1秒)我都会重新计算目标位置,但当我必须减速时,它不起作用,因为在某个点上,速度是负数考虑到从A点到B点每x秒的加速度和减速度,是否有任何公式可用于计算插值? 以下是我的代码的当前状态: co

我正在用Javascript构建一个模拟器,并努力理解物理学和运动学的基础知识,因为我毕业已经有一段时间了。无论如何,我有一个循环,它应该模拟时间,循环的每次迭代都等于1秒,我有一个对象,我想从点
a
[150,50]
)移动到点
B
[1,1]
)。物体的最大速度为
10
,加速度为
4.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;
    }
}
const math=require('mathjs');
const{distance}=require('mathjs');
设currentPos=[150,51];
常量targetPosition=[1,1];
const MAX_SPEED=10;
常数基准加速度=4.9;
设流速=0;
让停止=错误;
常量插值=(位置、速度、目标、加速度、t)=>{
常数d=数学距离(目标位置);
常数增量=数学减法(目标,位置);
常数比=数学除法(δ,d);
常数v=数学最小值(速度+(加速度*t),最大速度);
const newPos=移动(位置,比率,lerp(速度,v,t));
返回{pos:newPos,d,v,ratio};
};
常量移动=(位置、比率、速度)=>{
返回数学链(比率)
.乘(速度)
.添加(pos)
.完成();
};
常数lerp=(v0,v1,t)=>{
返回v0+t*(v1-v0);
};
常数getStopDistance=(v0,a)=>v0/2*a;
//假设我在模拟15秒
for(设i=0;i<15;i++){
console.log(``##########################`);
console.log(`currentPos->`,currentPos);
log(`currentVelocity->`,currentVelocity);
log(`stopping->`,stopping);
const sd=getStopDistance(当前速度、基本加速度);
常数a=(停止)?-基本加速度:基本加速度;
常数it=插值(currentPos,currentVelocity,targetPosition,a,1);
如果(it.d==0)
打破
console.log('sd->',sd);
log('it->',it);
如果(!stopping&&sd>=it.d){
//试图在1秒内将其分解为两个方程式。第一个方程式是当前速度和加速度,其余的应该是我开始停止的时间?**强文本**
常数d1=sd-it.d;
常数t1=(2*d1)/(流速+流速);
常数i1=插值(currentPos,currentVelocity,targetPosition,BASE_加速度,t1);
常数t2=1-t1;
常数i2=插值(i1.pos,i1.v,targetPosition,-基准加速度,t2);
console.log('d1->',d1);
console.log('t1->',t1);
console.log('i1->',i1);
console.log('t2->',t2);
console.log('i2->',i2);
停止=真;
currentPos=i2.pos;
电流速度=i2.v;
}否则{
currentPos=it.pos;
电流速度=it.v;
}
}

让我们考虑问题背后的数学,作为一维问题。让我们沿着连接起点和终点的直线查找对象的运动轮廓

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

  • 加速

     t = 0 ... v_max/a
     x = 0.5*a*t^2
     v = a*t
    
     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
    
  • 滑行

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

     t = 0 ... v_max/a
     x = 0.5*a*t^2
     v = a*t
    
     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))获取任意时间点的速度,曲线的最大速度和峰值由曲线的属性确定

这里显示了大量的输入/输出缓解功能:


如果你想根据已知的加速度和距离对这样的曲线进行反向工程,你可以用位置和距离分别代替
t
时间和
d
持续时间。

你是说粒子将加速到最大速度,然后开始减速?还是加速和减速同时适用?@QurakNerd我希望粒子加速,直到达到最大速度(除非已经达到最大速度),然后在到达B点之前减速。在达到最大速度之前,你的加速度是恒定的?如果是这样的话,因为你的加速度取决于你是否已经达到了最大速度,我不认为有一个简单的公式可以满足你的需要。相反,您需要将函数分为加速和减速两部分,任何计算都需要检查它需要使用哪一部分。我能问一下你在模拟什么样的物理过程吗,因为基于速度的加速度突然变化不是一件常见的事情是的,加速度和减速度都是常数。因为我每秒都在计算速度,所以我不知道如何使用公式,以防在同一秒内粒子必须加速和减速