7. HUD与游戏界面
2026/4/14大约 2 分钟
HUD与游戏界面
皇牌空战的 HUD(平视显示器)是玩家感知战场的窗口。速度、高度、雷达、锁定框、导弹警告——这些信息必须清晰、直观,又不能遮挡太多视野。本章实现完整的战斗机 HUD。
本章你将学到
- 飞行数据显示:速度表、高度表、姿态仪
- 雷达屏:在 2D 小地图上显示敌我位置
- 目标锁定框:追踪并框住目标
- 导弹告警:来袭导弹提示
- 任务目标列表
HUD 布局
┌─────────────────────────────────────────────────────┐
│ [任务目标] [飞机名称/武器] [存活数/得分] │
│ │
│ ┌────────────────────────────┐ │
│ │ 飞行视野区 │ │
│ │ ┌──────────────┐ │ │
│ [速度] │ │ 目标锁定框 │ │ [高度] │
│ 350kts │ └──────────────┘ │ 5000m │
│ │ │ │
│ └────────────────────────────┘ │
│ [导弹警告] [雷达屏] [导弹数量] │
└─────────────────────────────────────────────────────┘实现 HUD 节点结构
在 Godot 中,HUD 用 CanvasLayer + Control 节点实现,确保它永远显示在 3D 场景上方:
HUD (CanvasLayer)
├── SpeedIndicator (Label) ← 速度显示
├── AltitudeIndicator (Label) ← 高度显示
├── ThrottleBar (ProgressBar) ← 油门条
├── TargetLockBox (Control) ← 目标锁定框(跟随3D目标)
│ ├── BoxBorder (Panel)
│ └── TargetInfo (Label)
├── RadarScreen (SubViewport) ← 雷达小地图
│ └── RadarCamera (Camera3D)
├── MissileWarning (Label) ← 导弹告警(红色闪烁)
├── WeaponStatus (HBoxContainer) ← 武器状态
│ ├── WeaponName (Label)
│ └── AmmoCount (Label)
└── ObjectiveList (VBoxContainer) ← 任务目标列表核心HUD控制脚本
GDScript
extends CanvasLayer
## 飞行HUD控制器
class_name FlightHUD
@onready var speed_label: Label = $SpeedIndicator
@onready var altitude_label: Label = $AltitudeIndicator
@onready var throttle_bar: ProgressBar = $ThrottleBar
@onready var target_lock_box: Control = $TargetLockBox
@onready var missile_warning: Label = $MissileWarning
@onready var camera_3d: Camera3D = get_viewport().get_camera_3d()
var aircraft: AircraftController
var radar_system: RadarSystem
var missile_incoming: bool = false
func _process(delta: float) -> void:
if aircraft == null:
return
_update_flight_data()
_update_target_lock()
_update_missile_warning(delta)
func _update_flight_data() -> void:
# 速度:从米/秒转换为节(1节≈0.514m/s)
var knots := aircraft.airspeed / 0.514
speed_label.text = "%d kts" % int(knots)
# 高度:米(保留整数)
altitude_label.text = "%d m" % int(aircraft.altitude)
# 油门条
throttle_bar.value = aircraft.throttle * 100
func _update_target_lock() -> void:
if radar_system == null or radar_system.current_target == null:
target_lock_box.visible = false
return
# 把3D目标位置投影到屏幕2D坐标
var target_3d_pos := radar_system.current_target.global_position
var screen_pos := camera_3d.unproject_position(target_3d_pos)
# 检查目标是否在摄像机前方(不在背后)
if camera_3d.is_position_behind(target_3d_pos):
target_lock_box.visible = false
return
target_lock_box.visible = true
target_lock_box.global_position = screen_pos - target_lock_box.size / 2
# 锁定进度:根据雷达锁定进度改变框的颜色
var lock_color := Color.YELLOW.lerp(Color.RED, radar_system.lock_progress)
# TODO: 应用颜色到锁定框
func _update_missile_warning(delta: float) -> void:
if missile_incoming:
# 红色闪烁警告
missile_warning.visible = fmod(Time.get_ticks_msec() / 1000.0, 0.4) < 0.2
missile_warning.text = "⚠ 导弹来袭 ⚠"
else:
missile_warning.visible = false
func set_missile_warning(active: bool) -> void:
missile_incoming = activeC
using Godot;
public partial class FlightHUD : CanvasLayer
{
private Label _speedLabel;
private Label _altitudeLabel;
private ProgressBar _throttleBar;
private Control _targetLockBox;
private Label _missileWarning;
private Camera3D _camera3D;
public AircraftController Aircraft { get; set; }
public RadarSystem RadarSystem { get; set; }
private bool _missileIncoming = false;
public override void _Ready()
{
_speedLabel = GetNode<Label>("SpeedIndicator");
_altitudeLabel = GetNode<Label>("AltitudeIndicator");
_throttleBar = GetNode<ProgressBar>("ThrottleBar");
_targetLockBox = GetNode<Control>("TargetLockBox");
_missileWarning = GetNode<Label>("MissileWarning");
_camera3D = GetViewport().GetCamera3D();
}
public override void _Process(double delta)
{
if (Aircraft == null) return;
UpdateFlightData();
UpdateTargetLock();
UpdateMissileWarning((float)delta);
}
private void UpdateFlightData()
{
float knots = Aircraft.Airspeed / 0.514f;
_speedLabel.Text = $"{(int)knots} kts";
_altitudeLabel.Text = $"{(int)Aircraft.Altitude} m";
_throttleBar.Value = Aircraft.Throttle * 100;
}
private void UpdateTargetLock()
{
if (RadarSystem?.CurrentTarget == null)
{
_targetLockBox.Visible = false;
return;
}
var targetPos = RadarSystem.CurrentTarget.GlobalPosition;
if (_camera3D.IsPositionBehind(targetPos))
{
_targetLockBox.Visible = false;
return;
}
_targetLockBox.Visible = true;
var screenPos = _camera3D.UnprojectPosition(targetPos);
_targetLockBox.GlobalPosition = screenPos - _targetLockBox.Size / 2;
}
private void UpdateMissileWarning(float delta)
{
if (_missileIncoming)
{
_missileWarning.Visible = Time.GetTicksMsec() % 400 < 200;
_missileWarning.Text = "⚠ 导弹来袭 ⚠";
}
else
{
_missileWarning.Visible = false;
}
}
public void SetMissileWarning(bool active) => _missileIncoming = active;
}下一步
HUD 完成后,制作 音效与视觉特效。
