小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
效果图
2D 弹跳模拟,使用发射角度,初始速度,重力,弹性和摩擦
应用于位置、旋转和缩放属性的反弹表达式
反弹(Bounce)总览
我们的最终目标是在关键帧运动结束时使用一个模拟反弹的表达式。为了理解弹跳模拟是如何工作的,从一个可能更熟悉的场景开始是很有用的 —— 一个弹射物在击中地面/地板时弹跳。为了简单起见,我们将它限制在二维空间内。当你发射一个 2D 弹丸时,有很多因素会起作用: 重力、物体的弹性、发射角度、初始速度,有时还有摩擦。模拟这个运动的表达式基本上必须将初始速度分解成 x 和 y 分量。重力作用于 y 方向。在每次弹跳时,物体基于弹性失去 y 方向的速度,基于摩擦失去 x 方向的速度。将所有这些因素考虑在内,你便能够获得如下的 2D 反弹表达式:
elev = degreesToRadians(75);
v = 1900;
e = .7;
f = .5;
g = 5000;
nMax = 9;
tLaunch = 1;
vy = v * Math.sin(elev);
vx = v * Math.cos(elev);
if (time >= tLaunch) {
t = time - tLaunch;
tCur = 0;
segDur = 2 * vy / g;
tNext = segDur;
d = 0; // x distance traveled
nb = 0; // number of bounces
while (tNext < t && nb <= nMax) {
d += vx * segDur;
vy *= e;
vx *= f;
segDur *= e;
tCur = tNext;
tNext += segDur;
nb++
}
if (nb <= nMax) {
delta = t - tCur;
x = d + delta * vx;
y = delta * (vy - g * delta / 2);
} else {
x = d;
y = 0;
}
value + [x, -y]
} else
value
关于这个表达,有几件事需要注意。弹跳参数——发射角(elev)、初速度(v)、弹性(e)、摩擦力(f)和重力(g)——都在表达式的顶部定义。注意,您还必须定义最大弹跳数(nMax),以防止表达式消失在越来越小弹跳的无休止计算中。该表达式的这个版本还包含一个变量来控制启动时间(tLaunch)。
关键帧反弹
现在我们来看看这个表达式,这才是这部分的重点。这个表达式使用属性进入关键帧的速度来计算一个反弹(与进入动画相反的方向),该速度带有一系列递减的反弹。该表达式使用了基本 2D 反弹表达式中的大部分逻辑,除了无需担心发射角度和初始速度(这些是从关键帧中获取的)或摩擦。这个表达式可以用于大多数属性。请参阅上方(第二个)动图,以了解应用于缩放、位置(2D 和 3D)和旋转属性的示例。表达式:
e = .7;
g = 5000;
nMax = 9;
n = 0;
if (numKeys > 0) {
n = nearestKey(time).index;
if (key(n).time > time) n--;
}
if (n > 0) {
t = time - key(n).time;
v = -velocityAtTime(key(n).time - .001) * e;
vl = length(v);
if (value instanceof Array) {
vu = (vl > 0) ? normalize(v) : [0, 0, 0];
} else {
vu = (v < 0) ? -1 : 1;
}
tCur = 0;
segDur = 2 * vl / g;
tNext = segDur;
nb = 1; // number of bounces
while (tNext < t && nb <= nMax) {
vl *= e;
segDur *= e;
tCur = tNext;
tNext += segDur;
nb++
}
if (nb <= nMax) {
delta = t - tCur;
value + vu * delta * (vl - g * delta / 2);
} else {
value
}
} else
value
和之前一样,您可以通过调整弹性(e)和重力(g)变量来控制弹跳特性。