spaceship/ui/BreachOverlay.gd

43 lines
1.6 KiB
GDScript3
Raw Permalink Normal View History

#125: slow the prologue down, and give the breach a real black hole Five things, all of them "this happens too fast or looks too thin". PACING. Every beat had a completion test that could be satisfied while the guide was still mid-sentence, which is why everything landed seconds after the thing before it. Beats now have a FLOOR as well as a deadline - a minimum length - and a beat whose point is the guide talking will not end while a line is still on screen. One rule in one place rather than tuning each condition. The run is 3400px instead of 1500, which at cruise was about four seconds, and a held line is 6.5s instead of 4.5. THE CONVOY. Escorts at the four corners of a box, holds packed in the middle of it, roughly three times the spread of the fleet's own wedge - this is freight under guard, not a fighting formation. CONVOY and CONVOY_FORMATION pair index-for-index, which is all it takes for spawn_ships to seat the guns on the outside, and the test pins that every hold sits further in than the furthest-out escort. THE DIALOG. Cut corners, brackets holding the short edges open, a tick strip along the bottom and a caret in the corner - geometry rather than art, so it scales with the banner and costs nothing. THE BREACH. It was a few lines turning around a point. It is now two halves driven by one number: DimensionalBreach, a growing black hole out in the world built on BlackHoleVisual's idiom - empty core, counter-rotating arc segments hotter toward the centre - with infalling streamers it does not have, because a planet's disc is steady and this one has to say "now"; and breach.gdshader over the top, bending the ACTUAL SCENE around it. Ships, rocks and the starfield all get dragged in, which is most of what makes a hole in space read as a hole rather than as a decal drawn on one. Inside the horizon the shader samples nothing at all - the same decision BlackHoleVisual makes, for the same reason: a black hole with something visible in the middle stops being one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 13:25:10 +02:00
extends ColorRect
# #125: drives breach.gdshader.
#
# Lives in the UI layer because it works in SCREEN space - it bends the
# rendered frame, so it has to be the last thing drawn and it has to cover
# the whole viewport. The world-space half of the breach (the horizon, the
# accretion disc, the infalling matter) is DimensionalBreach, a Node2D out
# in the world; this is only the lens over the top of it.
#
# Inert unless something calls set_breach(): the shader is a no-op at zero
# strength, but a full-screen quad that is never needed is still a full
# screen of fragment work, so it hides itself instead.
const SHADER_PATH: String = "res://shaders/breach.gdshader"
func _ready() -> void:
mouse_filter = Control.MOUSE_FILTER_IGNORE
visible = false
if material == null:
var shader_material := ShaderMaterial.new()
shader_material.shader = load(SHADER_PATH)
material = shader_material
func clear_breach() -> void:
visible = false
if material != null:
material.set_shader_parameter("strength", 0.0)
# `at` is in SCREEN pixels; the director projects the world point through the
# camera before calling, because only it knows where the camera is.
func set_breach(at: Vector2, horizon: float, lens: float, breach_strength: float) -> void:
if material == null:
return
visible = breach_strength > 0.001
material.set_shader_parameter("breach_center", at)
material.set_shader_parameter("viewport_size", size)
material.set_shader_parameter("horizon_radius", horizon)
material.set_shader_parameter("lens_radius", maxf(lens, horizon + 1.0))
material.set_shader_parameter("strength", clampf(breach_strength, 0.0, 1.0))