3. 飞行物理系统
2026/4/14大约 4 分钟
飞行物理系统
飞机不是汽车——它在三维空间里运动,有升力、阻力、推力、重力四个力同时作用。本章用简化但感觉真实的物理模型,让你的战斗机能在空中做出俯冲、爬升、横滚、转弯等基本动作。
本章你将学到
- 飞机飞行的四力模型(升力/阻力/推力/重力)
- 三轴控制:俯仰、偏航、横滚
- 速度与高度的能量关系
- 超音速飞行的视觉与音效表现
- 失速保护(防止飞机突然掉下去)
飞行四力模型
不需要掌握真正的航空工程,用这个简化版就够:
升力↑
|
阻力← ←飞机→ →推力(发动机)
|
重力↓
飞机水平飞行时:升力 = 重力,推力 > 阻力
飞机爬升时:升力 > 重力,推力克服阻力 + 爬升分量
飞机俯冲时:重力帮忙加速,阻力需要限制最高速度飞行控制器代码
GDScript
extends RigidBody3D
## 战斗机飞行控制器
## 这是游戏里最重要的脚本——它决定了飞机"开起来"的感觉
class_name AircraftController
# ====== 飞行参数(可在编辑器中调整)======
@export_group("推力设置")
@export var max_thrust: float = 120000.0 ## 最大推力(牛顿)
@export var min_thrust_ratio: float = 0.1 ## 最小油门比例(慢车状态)
@export var afterburner_multiplier: float = 1.5 ## 加力燃烧室倍率
@export_group("气动参数")
@export var lift_coefficient: float = 2.5 ## 升力系数
@export var drag_coefficient: float = 0.05 ## 阻力系数
@export var max_speed: float = 600.0 ## 最大速度(米/秒,约2160km/h)
@export var stall_speed: float = 80.0 ## 失速速度(低于此速度升力不足)
@export_group("操控灵敏度")
@export var pitch_rate: float = 60.0 ## 俯仰速率(度/秒)
@export var roll_rate: float = 120.0 ## 横滚速率(度/秒)
@export var yaw_rate: float = 30.0 ## 偏航速率(度/秒)
# ====== 内部状态 ======
var throttle: float = 0.5 ## 当前油门(0.0 ~ 1.0)
var is_afterburner: bool = false
var airspeed: float = 0.0 ## 当前空速(米/秒)
var altitude: float = 0.0 ## 当前海拔高度(米)
func _physics_process(delta: float) -> void:
_read_player_input(delta)
_apply_thrust(delta)
_apply_aerodynamics(delta)
_update_flight_data()
func _read_player_input(delta: float) -> void:
# 油门控制
if Input.is_action_pressed("throttle_up"):
throttle = minf(throttle + delta * 0.5, 1.0)
if Input.is_action_pressed("throttle_down"):
throttle = maxf(throttle - delta * 0.5, 0.0)
# 姿态控制(直接施加扭矩)
var pitch := Input.get_action_strength("pitch_up") - Input.get_action_strength("pitch_down")
var roll := Input.get_action_strength("roll_left") - Input.get_action_strength("roll_right")
var yaw := Input.get_action_strength("yaw_left") - Input.get_action_strength("yaw_right")
# 把输入转换为本地坐标系的扭矩
# 注意:这里乘以 linear_velocity.length() 是因为速度越快,舵面越灵敏
var responsiveness := clampf(airspeed / 200.0, 0.2, 1.0)
var torque := Vector3(
pitch * deg_to_rad(pitch_rate),
yaw * deg_to_rad(yaw_rate),
roll * deg_to_rad(roll_rate)
) * responsiveness
apply_torque(global_transform.basis * torque)
func _apply_thrust(delta: float) -> void:
# 推力方向:飞机头部朝向(本地 -Z 轴)
var forward := -global_transform.basis.z
var thrust_force := max_thrust * throttle
if is_afterburner:
thrust_force *= afterburner_multiplier
apply_central_force(forward * thrust_force * delta)
func _apply_aerodynamics(delta: float) -> void:
airspeed = linear_velocity.length()
# —— 升力 ——
# 升力方向:飞机上方(本地 +Y 轴)
# 升力大小:与速度的平方成正比(空速越快升力越大)
var up := global_transform.basis.y
var lift := lift_coefficient * airspeed * airspeed * 0.01
# 失速保护:速度太低时升力不足,飞机开始下坠
if airspeed < stall_speed:
lift *= (airspeed / stall_speed) ## 线性衰减
apply_central_force(up * lift * delta)
# —— 阻力 ——
# 阻力与速度相反,大小与速度平方成正比
var drag := -linear_velocity.normalized() * drag_coefficient * airspeed * airspeed
apply_central_force(drag * delta)
# —— 速度限制 ——
if airspeed > max_speed:
linear_velocity = linear_velocity.normalized() * max_speed
func _update_flight_data() -> void:
altitude = global_position.y
airspeed = linear_velocity.length()C
using Godot;
/// <summary>
/// 战斗机飞行控制器 - 决定飞机"开起来"的感觉
/// </summary>
public partial class AircraftController : RigidBody3D
{
[ExportGroup("推力设置")]
[Export] public float MaxThrust = 120000f;
[Export] public float MinThrustRatio = 0.1f;
[Export] public float AfterburnerMultiplier = 1.5f;
[ExportGroup("气动参数")]
[Export] public float LiftCoefficient = 2.5f;
[Export] public float DragCoefficient = 0.05f;
[Export] public float MaxSpeed = 600f;
[Export] public float StallSpeed = 80f;
[ExportGroup("操控灵敏度")]
[Export] public float PitchRate = 60f;
[Export] public float RollRate = 120f;
[Export] public float YawRate = 30f;
public float Throttle { get; private set; } = 0.5f;
public bool IsAfterburner { get; private set; } = false;
public float Airspeed { get; private set; } = 0f;
public float Altitude { get; private set; } = 0f;
public override void _PhysicsProcess(double delta)
{
float dt = (float)delta;
ReadPlayerInput(dt);
ApplyThrust(dt);
ApplyAerodynamics(dt);
UpdateFlightData();
}
private void ReadPlayerInput(float delta)
{
if (Input.IsActionPressed("throttle_up"))
Throttle = Mathf.Min(Throttle + delta * 0.5f, 1f);
if (Input.IsActionPressed("throttle_down"))
Throttle = Mathf.Max(Throttle - delta * 0.5f, 0f);
float pitch = Input.GetActionStrength("pitch_up") - Input.GetActionStrength("pitch_down");
float roll = Input.GetActionStrength("roll_left") - Input.GetActionStrength("roll_right");
float yaw = Input.GetActionStrength("yaw_left") - Input.GetActionStrength("yaw_right");
float responsiveness = Mathf.Clamp(Airspeed / 200f, 0.2f, 1f);
var torque = new Vector3(
pitch * Mathf.DegToRad(PitchRate),
yaw * Mathf.DegToRad(YawRate),
roll * Mathf.DegToRad(RollRate)
) * responsiveness;
ApplyTorque(GlobalTransform.Basis * torque);
}
private void ApplyThrust(float delta)
{
var forward = -GlobalTransform.Basis.Z;
float thrustForce = MaxThrust * Throttle;
if (IsAfterburner) thrustForce *= AfterburnerMultiplier;
ApplyCentralForce(forward * thrustForce * delta);
}
private void ApplyAerodynamics(float delta)
{
Airspeed = LinearVelocity.Length();
var up = GlobalTransform.Basis.Y;
float lift = LiftCoefficient * Airspeed * Airspeed * 0.01f;
if (Airspeed < StallSpeed)
lift *= Airspeed / StallSpeed;
ApplyCentralForce(up * lift * delta);
var drag = -LinearVelocity.Normalized() * DragCoefficient * Airspeed * Airspeed;
ApplyCentralForce(drag * delta);
if (Airspeed > MaxSpeed)
LinearVelocity = LinearVelocity.Normalized() * MaxSpeed;
}
private void UpdateFlightData()
{
Altitude = GlobalPosition.Y;
Airspeed = LinearVelocity.Length();
}
}摄像机系统
空战游戏的摄像机需要跟随飞机,同时有一定的"惰性"(Lag),让画面看起来有重量感:
GDScript
extends Node3D
## 空战追踪摄像机
class_name CombatCamera
@export var target: RigidBody3D ## 要跟踪的飞机
@export var follow_distance: float = 15.0 ## 跟踪距离
@export var follow_height: float = 4.0 ## 跟踪高度
@export var lag_factor: float = 5.0 ## 惰性系数(越小越"懒")
func _process(delta: float) -> void:
if target == null:
return
# 目标位置:飞机后方+上方
var desired_pos := target.global_position \
+ target.global_transform.basis.z * follow_distance \
+ Vector3.UP * follow_height
# 平滑插值到目标位置(产生"惰性"效果)
global_position = global_position.lerp(desired_pos, lag_factor * delta)
# 始终看向飞机(稍微偏上,看起来更有气势)
look_at(target.global_position + Vector3.UP * 1.5, Vector3.UP)C
using Godot;
public partial class CombatCamera : Node3D
{
[Export] public RigidBody3D Target;
[Export] public float FollowDistance = 15f;
[Export] public float FollowHeight = 4f;
[Export] public float LagFactor = 5f;
public override void _Process(double delta)
{
if (Target == null) return;
var desiredPos = Target.GlobalPosition
+ Target.GlobalTransform.Basis.Z * FollowDistance
+ Vector3.Up * FollowHeight;
GlobalPosition = GlobalPosition.Lerp(desiredPos, LagFactor * (float)delta);
LookAt(Target.GlobalPosition + Vector3.Up * 1.5f, Vector3.Up);
}
}下一步
飞行物理做好了,接下来制作 武器与导弹系统。
