fix(presentation): simplify camera and engine effects

This commit is contained in:
Josh Creek
2026-08-08 08:44:26 +01:00
parent b7f646ba48
commit e0a1cbaf6d
14 changed files with 56 additions and 241 deletions
-93
View File
@@ -1,93 +0,0 @@
Copyright 2018 The Orbitron Project Authors (https://github.com/theleagueof/orbitron), with Reserved Font Name: "Orbitron"
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
Binary file not shown.
@@ -1,36 +0,0 @@
[remap]
importer="font_data_dynamic"
type="FontFile"
uid="uid://bhbpb712ouagv"
path="res://.godot/imported/Orbitron-Medium.ttf-0d3cd88166f12a3096066c2eef570744.fontdata"
[deps]
source_file="res://assets/fonts/Orbitron-Medium.ttf"
dest_files=["res://.godot/imported/Orbitron-Medium.ttf-0d3cd88166f12a3096066c2eef570744.fontdata"]
[params]
Rendering=null
antialiasing=1
generate_mipmaps=false
disable_embedded_bitmaps=true
multichannel_signed_distance_field=false
msdf_pixel_range=8
msdf_size=48
allow_system_fallback=true
force_autohinter=false
modulate_color_glyphs=false
hinting=3
subpixel_positioning=4
keep_rounding_remainders=true
oversampling=0.0
Fallbacks=null
fallbacks=[]
Compress=null
compress=true
preload=[]
language_support={}
script_support={}
opentype_features={}
+1 -3
View File
@@ -1,10 +1,9 @@
[gd_scene load_steps=10 format=3 uid="uid://c8kak2l3m4n5"]
[gd_scene load_steps=9 format=3 uid="uid://c8kak2l3m4n5"]
[ext_resource type="Script" uid="uid://du7y176h5aaq4" path="res://scripts/HUDController.gd" id="1_hud_controller"]
[ext_resource type="Script" path="res://scripts/hud_attitude_indicator.gd" id="2_adi"]
[ext_resource type="Script" path="res://scripts/hud_heading_tape.gd" id="3_tape"]
[ext_resource type="Script" path="res://scripts/hud_gauge.gd" id="4_gauge"]
[ext_resource type="Theme" path="res://themes/hud_theme.tres" id="5_theme"]
[sub_resource type="LabelSettings" id="LabelSettings_hud"]
font_size = 32
@@ -51,7 +50,6 @@ anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
theme = ExtResource("5_theme")
[node name="ScoreboardPanel" type="PanelContainer" parent="Control"]
layout_mode = 1
+1 -11
View File
@@ -1,17 +1,8 @@
[gd_scene load_steps=5 format=3]
[gd_scene load_steps=4 format=3]
[ext_resource type="Script" path="res://scripts/ship_camera.gd" id="1_rig"]
[ext_resource type="Shader" path="res://shaders/post_process.gdshader" id="2_post"]
[sub_resource type="CameraAttributesPractical" id="CameraAttributes_gameplay"]
dof_blur_far_enabled = true
dof_blur_far_distance = 24.0
dof_blur_far_transition = 14.0
dof_blur_near_enabled = true
dof_blur_near_distance = 1.25
dof_blur_near_transition = 0.75
dof_blur_amount = 0.08
[sub_resource type="ShaderMaterial" id="ShaderMaterial_post"]
shader = ExtResource("2_post")
@@ -20,7 +11,6 @@ script = ExtResource("1_rig")
[node name="Camera3D" type="Camera3D" parent="."]
current = true
attributes = SubResource("CameraAttributes_gameplay")
[node name="PostProcess" type="CanvasLayer" parent="."]
layer = 0
+1 -1
View File
@@ -73,7 +73,7 @@ func _draw() -> void:
draw_line(Vector2(-half_chord, horizon_y), Vector2(half_chord, horizon_y), LINE_COLOR, 2.0)
# Pitch ladder: rungs every 10 degrees, labelled, scrolling with pitch.
var font := hud_font()
var font := ThemeDB.fallback_font
for ladder_deg: int in [-30, -20, -10, 10, 20, 30]:
var y := horizon_y - ladder_deg * px_per_deg
if absf(y) > radius - 12.0:
+1 -1
View File
@@ -37,7 +37,7 @@ func _process(delta: float) -> void:
func _draw() -> void:
var font := hud_font()
var font := ThemeDB.fallback_font
var fraction := clampf(_value / max_value, 0.0, 1.0)
var reading := value_format % _value
+1 -1
View File
@@ -39,7 +39,7 @@ func _process(delta: float) -> void:
func _draw() -> void:
var font := hud_font()
var font := ThemeDB.fallback_font
var center_x := size.x / 2.0
var px_per_deg := size.x / VISIBLE_RANGE
-8
View File
@@ -23,11 +23,3 @@ static func angle_delta_deg(from: float, to: float) -> float:
func _smoothing_weight(delta: float) -> float:
return 1.0 - exp(-SMOOTHING * delta) # frame-rate independent
# Procedural draw calls do not automatically consume a Control's theme font;
# resolve it explicitly so every instrument uses the same packaged typeface
# as ordinary Labels instead of ThemeDB's debug-looking fallback.
func hud_font() -> Font:
var font := get_theme_default_font()
return font if font else ThemeDB.fallback_font
+42 -28
View File
@@ -117,8 +117,7 @@ const ATTITUDE_THRESHOLD = 1.0 # degrees
const THRUST_THRESHOLD = 1.0 # percent
var _engine_cores: Array[MeshInstance3D] = []
var _engine_plumes: Array[GPUParticles3D] = []
var _turbo_flames: Array[GPUParticles3D] = []
var _engine_flames: Array[MeshInstance3D] = []
var _engine_lights: Array[OmniLight3D] = []
var _impact_sparks: GPUParticles3D
@@ -215,7 +214,7 @@ func _build_movement_vfx() -> void:
for x in [-0.42, 0.42]:
var engine_pos := Vector3(x, -0.05, 1.42)
var core_mat := _vfx_material(Color(0.35, 0.85, 1.0, 1.0), 1.0)
var core_mat := _vfx_material(Color(1.0, 0.48, 0.1, 1.0), 1.0)
var core_mesh := SphereMesh.new()
core_mesh.radius = 0.11
core_mesh.height = 0.22
@@ -228,28 +227,37 @@ func _build_movement_vfx() -> void:
add_child(core)
_engine_cores.append(core)
var plume := _make_particles(
"EnginePlumeL" if x < 0.0 else "EnginePlumeR",
Color(0.3, 0.82, 1.0, 0.72), Vector2(0.16, 0.42), 36, 0.24,
Vector3(0, 0, 1), 12.0, 2.0, 5.0
)
plume.position = engine_pos + Vector3(0, 0, 0.08)
add_child(plume)
_engine_plumes.append(plume)
var turbo := _make_particles(
"TurboFlameL" if x < 0.0 else "TurboFlameR",
Color(0.78, 0.34, 1.0, 0.9), Vector2(0.22, 0.72), 48, 0.18,
Vector3(0, 0, 1), 7.0, 6.0, 10.0
)
turbo.position = engine_pos + Vector3(0, 0, 0.12)
add_child(turbo)
_turbo_flames.append(turbo)
# A single conventional orange flame replaces the layered particle plume
# and separate purple turbo effect. Turbo only lengthens and brightens the
# same flame, keeping the engine silhouette simple and readable.
var flame_mat := StandardMaterial3D.new()
flame_mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
flame_mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
flame_mat.cull_mode = BaseMaterial3D.CULL_DISABLED
flame_mat.albedo_color = Color(1.0, 0.34, 0.04, 0.92)
flame_mat.emission_enabled = true
flame_mat.emission = Color(1.0, 0.16, 0.015)
flame_mat.emission_energy_multiplier = 2.0
var flame_mesh := CylinderMesh.new()
flame_mesh.top_radius = 0.015
flame_mesh.bottom_radius = 0.14
flame_mesh.height = 1.0
flame_mesh.radial_segments = 12
flame_mesh.material = flame_mat
var flame := MeshInstance3D.new()
flame.name = "EngineFlameL" if x < 0.0 else "EngineFlameR"
flame.position = engine_pos + Vector3(0, 0, 0.3)
flame.rotation_degrees.x = 90.0
flame.mesh = flame_mesh
flame.visible = false
flame.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
add_child(flame)
_engine_flames.append(flame)
var light := OmniLight3D.new()
light.name = "EngineLightL" if x < 0.0 else "EngineLightR"
light.position = engine_pos
light.light_color = Color(0.3, 0.75, 1.0)
light.light_color = Color(1.0, 0.32, 0.08)
light.omni_range = 3.5
light.omni_attenuation = 2.0
light.shadow_enabled = false
@@ -308,18 +316,24 @@ func _make_particles(
func _update_movement_vfx() -> void:
if _engine_plumes.is_empty():
if _engine_flames.is_empty():
return
# These are the two rear main engines, so lateral/vertical maneuvering jets
# must not make them flare. Reverse thrust also comes from separate attitude
# jets conceptually; only positive Z drives this rear-facing plume.
# jets conceptually; only positive Z drives this rear-facing flame.
var thrust := clampf(maxf(_current_action.thrust.z, 0.0), 0.0, 1.0)
var turbo := _current_action.turbo and thrust > 0.05
for i in _engine_plumes.size():
_engine_plumes[i].emitting = thrust > 0.02
_engine_plumes[i].amount_ratio = 0.25 + thrust * 0.75
_engine_plumes[i].speed_scale = 0.65 + thrust * 0.75
_turbo_flames[i].emitting = turbo
for i in _engine_flames.size():
var flame := _engine_flames[i]
var flame_length := 0.28 + thrust * 0.82 + (0.62 if turbo else 0.0)
var flame_width := 0.72 + thrust * 0.32 + (0.12 if turbo else 0.0)
flame.visible = thrust > 0.02
flame.scale = Vector3(flame_width, flame_length, flame_width)
# CylinderMesh is centred on local Y (rotated to ship +Z), so moving its
# centre by half the length keeps the flame root fixed at the engine bell.
flame.position.z = 1.48 + flame_length * 0.5
var flame_mat := flame.mesh.material as StandardMaterial3D
flame_mat.emission_energy_multiplier = 1.8 + thrust * 2.2 + (1.8 if turbo else 0.0)
_engine_lights[i].light_energy = 0.35 + thrust * 2.1 + (2.3 if turbo else 0.0)
var core_mat := _engine_cores[i].mesh.material as StandardMaterial3D
core_mat.emission_energy_multiplier = 0.65 + thrust * 2.0 + (2.0 if turbo else 0.0)
+1 -6
View File
@@ -183,9 +183,6 @@ func _update_speed_feel(delta: float) -> void:
_effective_distance = lerpf(
_effective_distance, camera_distance + _turbo_blend * turbo_distance_kick, feel_t
)
post_material.set_shader_parameter(
"motion_blur_amount", _speed_blend * _speed_blend * 0.006 + _turbo_blend * 0.006
)
post_material.set_shader_parameter("chromatic_aberration", _turbo_blend * 0.007)
post_material.set_shader_parameter("vignette_strength", 0.22 + _turbo_blend * 0.16)
@@ -233,8 +230,7 @@ func begin_goal_cut(goal_position: Vector3) -> void:
camera.fov = 58.0
camera.look_at(_goal_cut_look_at, Vector3.UP)
# A hard, stationary cinematic camera must not inherit the scoring frame's
# ship-speed smear or turbo chroma. Keep only a deliberate cinematic edge.
post_material.set_shader_parameter("motion_blur_amount", 0.0)
# turbo chroma; keep only a deliberate cinematic edge.
post_material.set_shader_parameter("chromatic_aberration", 0.0)
post_material.set_shader_parameter("vignette_strength", 0.3)
@@ -243,6 +239,5 @@ func end_goal_cut() -> void:
_goal_cut_active = false
_speed_blend = 0.0
_turbo_blend = 0.0
post_material.set_shader_parameter("motion_blur_amount", 0.0)
post_material.set_shader_parameter("chromatic_aberration", 0.0)
post_material.set_shader_parameter("vignette_strength", 0.22)
+5 -21
View File
@@ -1,37 +1,21 @@
shader_type canvas_item;
render_mode unshaded;
uniform sampler2D screen_texture : hint_screen_texture, filter_linear_mipmap;
uniform float motion_blur_amount : hint_range(0.0, 0.03) = 0.0;
uniform sampler2D screen_texture : hint_screen_texture, filter_linear;
uniform float chromatic_aberration : hint_range(0.0, 0.02) = 0.0;
uniform float vignette_strength : hint_range(0.0, 1.0) = 0.22;
vec4 motion_sample(vec2 uv) {
// A restrained centre-directed velocity smear. The camera script scales it
// with ship speed/turbo; mipmapped screen reads soften the outer samples.
if (motion_blur_amount < 0.0001) {
return textureLod(screen_texture, uv, 0.0);
}
vec2 step_uv = (uv - vec2(0.5)) * motion_blur_amount;
vec4 color = textureLod(screen_texture, uv, 0.0) * 0.36;
color += textureLod(screen_texture, uv - step_uv * 0.35, 0.5) * 0.25;
color += textureLod(screen_texture, uv - step_uv * 0.7, 1.0) * 0.21;
color += textureLod(screen_texture, uv - step_uv, 1.5) * 0.18;
return color;
}
void fragment() {
vec2 radial = UV - vec2(0.5);
vec2 chroma = radial * chromatic_aberration;
vec4 center = motion_sample(UV);
vec4 center = texture(screen_texture, UV);
vec3 color = center.rgb;
// The branch is driven by one uniform for the whole draw, so non-turbo
// frames avoid eight redundant screen taps without causing warp divergence.
// frames avoid two redundant screen taps without causing warp divergence.
if (chromatic_aberration > 0.0001) {
color.r = motion_sample(UV + chroma).r;
color.b = motion_sample(UV - chroma).b;
color.r = texture(screen_texture, UV + chroma).r;
color.b = texture(screen_texture, UV - chroma).b;
}
// Aspect-correct vignette, always subtle and tightened slightly on turbo.
-29
View File
@@ -1,29 +0,0 @@
[gd_resource type="Theme" load_steps=3 format=3]
[ext_resource type="FontFile" path="res://assets/fonts/Orbitron-Medium.ttf" id="1_font"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_panel"]
bg_color = Color(0.035, 0.05, 0.085, 0.76)
border_width_left = 1
border_width_top = 1
border_width_right = 1
border_width_bottom = 1
border_color = Color(0.3, 0.7, 1, 0.38)
corner_radius_top_left = 8
corner_radius_top_right = 8
corner_radius_bottom_right = 8
corner_radius_bottom_left = 8
content_margin_left = 12.0
content_margin_top = 8.0
content_margin_right = 12.0
content_margin_bottom = 8.0
[resource]
default_font = ExtResource("1_font")
default_font_size = 14
Label/colors/font_color = Color(0.86, 0.94, 1, 1)
Label/colors/font_shadow_color = Color(0, 0, 0, 0.72)
Label/constants/outline_size = 1
Label/constants/shadow_offset_x = 2
Label/constants/shadow_offset_y = 2
PanelContainer/styles/panel = SubResource("StyleBoxFlat_panel")
+3 -3
View File
@@ -16,14 +16,14 @@ The largest gap between this and a AAA-feeling product is presentation, not code
- [ ] **Audio — there is none.** Zero sound files, zero `AudioStreamPlayer` nodes, no bus layout. Needs: engine hum pitched to throttle, turbo whoosh, ball impacts scaled by collision impulse, wall scrapes, goal explosion, crowd bed, UI clicks, countdown beeps, music. Can be driven off `Ship`'s existing telemetry signals.
- [x] SSAO/SSIL in the arena Environments — cheapest single perceived-quality win available; grounds the ships against the deck and gives the fillets and goal recesses real depth.
- [x] VFX on anything that moves: throttle-reactive engine cores and plumes, distinct turbo flames, a speed-scaled ball trail, contact sparks and team-tinted goal bursts.
- [x] VFX on anything that moves: throttle-reactive engine cores and simple rear flames, a speed-scaled ball trail, contact sparks and team-tinted goal bursts.
- [x] Impact feedback — intensity-scaled screen shake, unscaled hit-stop, HUD flash and controller rumble on ball contact.
- [x] Camera feel in `ship_camera.gd` — speed-based FOV widening, turbo kick-back and decaying impact shake.
- [x] Goal celebration sequence: goal burst, team-tinted flash/title card, dedicated camera cut and slow-motion beat after authoritative score registration and before reset/kickoff.
- [x] Local lighting / dynamic GI — four local pitch lights plus SDFGI provide bounce and contact lighting for the runtime-generated arena shell; the shader's `hull_fill` stand-in is retired. (The shell is generated in `_ready`, so it cannot participate in an editor LightmapGI bake.)
- [x] Dress `arena_03` — its asteroid field now has mining stations, debris clusters and a distant planet.
- [x] Custom font + a real `Theme` resource for the HUD. Packaged Orbitron typography, shared label styling and themed procedural-instrument text replace `ThemeDB.fallback_font`.
- [x] Post-processing beyond glow: camera DoF plus speed-scaled motion blur, a cinematic vignette and turbo-driven chromatic aberration.
- [ ] Custom font + a real `Theme` resource for the HUD. `ThemeDB.fallback_font` at 10-13 px reads as a debug overlay.
- [x] Post-processing beyond glow: a cinematic vignette and turbo-driven chromatic aberration. DoF and motion blur were intentionally omitted after playtesting.
## Multiplayer (long term)