2025-11-30 · game_math
【游戏中的数学】游戏中的数学 (9) - 碰撞响应
碰撞响应完全指南:从反射向量到动量守恒,推导双体碰撞冲量公式,实现库仑摩擦模型,并用台球碰撞实例贯穿全部知识点。
引擎语境:本文主要以 Unity / C# 视角讲解,物理更新建议放在
FixedUpdate中。
运动学 (Kinematics) 关注的是物体如何移动,而不关心为什么移动(那是动力学的事)。 在游戏中,这通常意味着根据速度和加速度更新物体的位置。 换句话说,本篇就是把“速度、加速度”这些物理课里的概念,翻译成一帧一帧更新角色位置的代码。
在经典力学中,如果加速度 \(a\) 近似恒定,则在时间 \(t\) 内: \[ v = v_0 + a t \] \[ s = v_0 t + \frac{1}{2} a t^2 \]
在离散时间步长 \(\Delta t\) 的游戏循环中,我们用近似公式来更新: \[ Velocity_{new} = Velocity_{old} + Acceleration \times \Delta t \] \[ Position_{new} = Position_{old} + Velocity \times \Delta t \]
这里: - \(Velocity\)
表示当前速度向量(位置每秒变化量)。 - \(Acceleration\)
表示每秒速度的变化量(如重力、推力)。 - \(\Delta t\) 通常使用
Time.fixedDeltaTime,保证物理更新稳定。
在计算机中,时间不是连续的,而是离散的帧 (\(\Delta t\))。我们需要用数值积分来近似计算位置。
这是最简单也是最常用的方法(如 Unity 的
Rigidbody 默认行为)。
void Update(float dt) {
velocity += acceleration * dt;
position += velocity * dt;
}这种方法不显式存储速度,而是通过当前位置和上一帧位置来推导速度。 \[ 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;
}FixedUpdate。| 方法 | 精度 | 性能 | 典型应用 |
|---|---|---|---|
| 显式欧拉 | 一阶 | 极快 | 简单角色移动 |
| 半隐式欧拉 | 一阶(更稳定) | 极快 | Unity Rigidbody 默认 |
| 中点法 (Midpoint) | 二阶 | 快 | 需要更高精度的物理 |
| RK4 (Runge-Kutta 4) | 四阶 | 较慢(每步4次求值) | 航天模拟、精密轨道 |
| Verlet | 二阶 | 快 | 布料、绳索、粒子 |
半隐式欧拉 (Symplectic Euler) 是游戏中最常用的积分器——它只是把”先更新速度再更新位置”的顺序换了一下,但稳定性比显式欧拉好很多:
// 半隐式欧拉(推荐)
velocity += acceleration * dt; // 先更新速度
position += velocity * dt; // 再用新速度更新位置对于绝大多数游戏来说,半隐式欧拉 + 固定时间步长就足够了。只有当你需要长时间高精度模拟(如行星轨道)时,才需要考虑 RK4。
在射击游戏中,我们经常需要预测炮弹的落点。 如果不考虑空气阻力,水平方向是匀速运动,垂直方向是匀加速运动(重力)。
\[ 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
进行物理模拟,以保证确定性。< 上一篇: 相交检测 | 回到目录 | 下一篇: 碰撞响应 >
把当前热点继续串成多页阅读,而不是停在单篇消费。
2025-11-30 · game_math
碰撞响应完全指南:从反射向量到动量守恒,推导双体碰撞冲量公式,实现库仑摩擦模型,并用台球碰撞实例贯穿全部知识点。
2025-11-30 · game_math
详解游戏引擎中常用的标量数学函数:Lerp, InverseLerp, Remap, Clamp, SmoothStep 等。不仅有公式,更有实际应用场景。
2025-11-30 · game_math
深入浅出地讲解游戏开发中的三角函数:Sin, Cos, Atan2。从单位圆原理到圆周运动、波浪动画和朝向计算的实际应用。
2025-11-30 · game_math
深入理解游戏开发中的矩阵:TRS 变换与代码实践、矩阵乘法与组合变换、MVP 管线详解、逆矩阵、法线变换,以及旋转表示方式对比。
引擎语境:本文主要以 Unity / C# 视角讲解,物理更新建议放在
FixedUpdate中。
运动学 (Kinematics) 关注的是物体如何移动,而不关心为什么移动(那是动力学的事)。 在游戏中,这通常意味着根据速度和加速度更新物体的位置。 换句话说,本篇就是把“速度、加速度”这些物理课里的概念,翻译成一帧一帧更新角色位置的代码。
在经典力学中,如果加速度 \(a\) 近似恒定,则在时间 \(t\) 内: \[ v = v_0 + a t \] \[ s = v_0 t + \frac{1}{2} a t^2 \]
在离散时间步长 \(\Delta t\) 的游戏循环中,我们用近似公式来更新: \[ Velocity_{new} = Velocity_{old} + Acceleration \times \Delta t \] \[ Position_{new} = Position_{old} + Velocity \times \Delta t \]
这里: - \(Velocity\)
表示当前速度向量(位置每秒变化量)。 - \(Acceleration\)
表示每秒速度的变化量(如重力、推力)。 - \(\Delta t\) 通常使用
Time.fixedDeltaTime,保证物理更新稳定。
在计算机中,时间不是连续的,而是离散的帧 (\(\Delta t\))。我们需要用数值积分来近似计算位置。
这是最简单也是最常用的方法(如 Unity 的
Rigidbody 默认行为)。
void Update(float dt) {
velocity += acceleration * dt;
position += velocity * dt;
}这种方法不显式存储速度,而是通过当前位置和上一帧位置来推导速度。 \[ 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;
}FixedUpdate。| 方法 | 精度 | 性能 | 典型应用 |
|---|---|---|---|
| 显式欧拉 | 一阶 | 极快 | 简单角色移动 |
| 半隐式欧拉 | 一阶(更稳定) | 极快 | Unity Rigidbody 默认 |
| 中点法 (Midpoint) | 二阶 | 快 | 需要更高精度的物理 |
| RK4 (Runge-Kutta 4) | 四阶 | 较慢(每步4次求值) | 航天模拟、精密轨道 |
| Verlet | 二阶 | 快 | 布料、绳索、粒子 |
半隐式欧拉 (Symplectic Euler) 是游戏中最常用的积分器——它只是把”先更新速度再更新位置”的顺序换了一下,但稳定性比显式欧拉好很多:
// 半隐式欧拉(推荐)
velocity += acceleration * dt; // 先更新速度
position += velocity * dt; // 再用新速度更新位置对于绝大多数游戏来说,半隐式欧拉 + 固定时间步长就足够了。只有当你需要长时间高精度模拟(如行星轨道)时,才需要考虑 RK4。
在射击游戏中,我们经常需要预测炮弹的落点。 如果不考虑空气阻力,水平方向是匀速运动,垂直方向是匀加速运动(重力)。
\[ 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
进行物理模拟,以保证确定性。< 上一篇: 相交检测 | 回到目录 | 下一篇: 碰撞响应 >
把当前热点继续串成多页阅读,而不是停在单篇消费。
2025-11-30 · game_math
碰撞响应完全指南:从反射向量到动量守恒,推导双体碰撞冲量公式,实现库仑摩擦模型,并用台球碰撞实例贯穿全部知识点。
2025-11-30 · game_math
详解游戏引擎中常用的标量数学函数:Lerp, InverseLerp, Remap, Clamp, SmoothStep 等。不仅有公式,更有实际应用场景。
2025-11-30 · game_math
深入浅出地讲解游戏开发中的三角函数:Sin, Cos, Atan2。从单位圆原理到圆周运动、波浪动画和朝向计算的实际应用。
2025-11-30 · game_math
深入理解游戏开发中的矩阵:TRS 变换与代码实践、矩阵乘法与组合变换、MVP 管线详解、逆矩阵、法线变换,以及旋转表示方式对比。