引言
运动学 (Kinematics) 关注的是物体如何移动,而不关心为什么移动(那是动力学的事)。 在游戏中,这通常意味着根据速度和加速度更新物体的位置。
1. 基础公式
最简单的物理更新循环: \[ Position_{new} = Position_{old} + Velocity \times \Delta t \] \[ Velocity_{new} = Velocity_{old} + Acceleration \times \Delta t \]
这对应了物理学中的匀加速直线运动公式: \[ s = v_0 t + \frac{1}{2} a t^2 \]
2. 积分器 (Integrators)
在计算机中,时间不是连续的,而是离散的帧 (\(\Delta t\))。我们需要用数值积分来近似计算位置。
显式欧拉积分 (Explicit Euler)
这是最简单也是最常用的方法(如 Unity 的
Rigidbody 默认行为)。
void Update(float dt) {
velocity += acceleration * dt;
position += velocity * dt;
}- 优点: 极易实现。
- 缺点: 精度低,能量不守恒。随着时间推移,误差会累积(例如:绕地球卫星会逐渐飞离轨道)。
韦尔莱积分 (Verlet Integration)
这种方法不显式存储速度,而是通过当前位置和上一帧位置来推导速度。 \[ x_{new} = 2x_{current} - x_{old} + a \cdot \Delta t^2 \]
void Update(float dt) {
Vector3 temp = position;
position = 2 * position - oldPosition + acceleration * dt * dt;
oldPosition = temp;
}- 优点: 非常稳定,特别适合模拟布料、绳索和布娃娃系统 (Ragdolls)。它能自动保持约束条件。
- 缺点: 处理变长帧率 (Variable Time Step)
比较麻烦,通常需要固定的
FixedUpdate。
3. 抛物线运动 (Projectile Motion)
在射击游戏中,我们经常需要预测炮弹的落点。 如果不考虑空气阻力,水平方向是匀速运动,垂直方向是匀加速运动(重力)。
\[ x(t) = x_0 + v_{x0} t \] \[ y(t) = y_0 + v_{y0} t - \frac{1}{2} g t^2 \]
瞄准算法
已知起点 \(P\) 和目标 \(T\),以及炮弹速度 \(v\),求发射角度 \(\theta\)。 这是一个经典的物理问题。通过消除时间变量 \(t\),我们可以得到一个关于 \(\tan \theta\) 的一元二次方程。
代码实现:
float? CalculateLaunchAngle(Vector3 start, Vector3 target, float v, float g = 9.81f) {
float x = Vector3.Distance(new Vector3(start.x, 0, start.z), new Vector3(target.x, 0, target.z));
float y = target.y - start.y;
float v2 = v * v;
float v4 = v2 * v2;
float term = v4 - g * (g * x * x + 2 * y * v2);
if (term < 0) return null; // 目标太远,打不到
// 通常有两个解:高抛和低抛。这里返回低抛角度(直射)。
float tanTheta = (v2 - Mathf.Sqrt(term)) / (g * x);
return Mathf.Atan(tanTheta) * Mathf.Rad2Deg;
}总结
- 对于简单的角色移动,欧拉积分足够了。
- 对于绳索、布料或高精度物理,考虑使用韦尔莱积分。
- 永远使用
Time.fixedDeltaTime进行物理模拟,以保证确定性。