Sharpen upgrades, mark the convoy's destination, and give the world sound
#204 the Beam Collimator widens the beam instead of adding range to one that already crosses the screen; beam width becomes a per-shot vessel stat. #205 the Energy Propulser gains three upgrades - dash recharge, dash reach, and boosted-cruise drain - which turns three constants into vessel stats. #206 three further doctrines carry the fleet from ten to twenty. #207 the prologue's World Ship gets a marker, through the scanner's own guidance arrow rather than a second one. #208 #210 #213 #214 four new synthesised sounds: the breach opening, cargo reaching the hold, a rock breaking, and a gas bomb blooming. #215 building health bars are larger, plated and framed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019AJMdB7iuHuLFZM1aBu3GD
This commit is contained in:
parent
2239235993
commit
78836882af
33 changed files with 716 additions and 52 deletions
|
|
@ -66,6 +66,10 @@ func _advance_flight(delta: float) -> void:
|
|||
|
||||
|
||||
func _explode() -> void:
|
||||
# #214: at the bloom, not at the launch - the throw is silent and the
|
||||
# arrival is the event, the same way the beam's own noise sits at the
|
||||
# muzzle rather than at the button.
|
||||
Sfx.play(get_tree(), Sfx.GAS_BLAST)
|
||||
exploded = true
|
||||
explosion_time = EXPLOSION_DURATION
|
||||
hit_count = 0
|
||||
|
|
|
|||
|
|
@ -22,13 +22,18 @@ const COMBAT_TARGET = preload("res://core/CombatTarget.gd")
|
|||
signal struck(hit_count: int)
|
||||
|
||||
const BEAM_COLOR := Color(0.3, 0.9, 1.0)
|
||||
# The width an unupgraded emitter cuts, and what the definition declares.
|
||||
# #204 made it a vessel stat, so the width in force is `half_width` below;
|
||||
# this is only what a beam fired without one falls back to.
|
||||
const BEAM_HALF_WIDTH := 38.0
|
||||
# The DRAWN beam is scaled from the hit width rather than tuned separately.
|
||||
# The two were independent numbers and had drifted apart: the beam struck
|
||||
# anything within 22 units of the line while its outer glow spanned about 11,
|
||||
# so it killed things it visibly missed. NeonDraw's widest layer is 18px at
|
||||
# scale 1, so this makes the glow span exactly what the beam hits.
|
||||
const BEAM_WIDTH_SCALE := BEAM_HALF_WIDTH * 2.0 / 18.0
|
||||
# NeonDraw's widest layer is 18px at scale 1, so dividing by it makes the
|
||||
# glow span exactly what the beam hits. The DRAWN beam is scaled from the hit
|
||||
# width rather than tuned separately: the two were once independent numbers
|
||||
# and had drifted apart, so the beam struck anything within 22 units of the
|
||||
# line while its outer glow spanned about 11, killing things it visibly
|
||||
# missed. Kept a ratio rather than a constant now that the width can grow -
|
||||
# a wider beam has to LOOK wider, or the drift comes back with every level.
|
||||
const NEON_WIDEST_LAYER := 18.0
|
||||
# #90: the beam was one flat line that blinked on at full length and faded.
|
||||
# It now IGNITES - it runs out of the ship over the first slice of its life,
|
||||
# holds white-hot, and falls away.
|
||||
|
|
@ -40,8 +45,9 @@ const IGNITE_FRACTION := 0.3
|
|||
# missed" complaint back the other way round.
|
||||
const CORE_SCALE := 0.42
|
||||
const CORE_COLOR := Color(0.85, 0.99, 1.0)
|
||||
const TIP_RADIUS := BEAM_HALF_WIDTH * 0.55
|
||||
const MUZZLE_RADIUS := BEAM_HALF_WIDTH * 0.8
|
||||
# Both ends of the beam, as fractions of its own width.
|
||||
const TIP_FRACTION := 0.55
|
||||
const MUZZLE_FRACTION := 0.8
|
||||
# By path, not by class name - see the note at the top of MuzzleSparkVFX.
|
||||
const MUZZLE_SPARK = preload("res://vfx/MuzzleSparkVFX.gd")
|
||||
|
||||
|
|
@ -51,11 +57,15 @@ var time: float = FLASH_DURATION
|
|||
# Per beam, so two lasers firing together do not flicker in lockstep.
|
||||
var phase: float = 0.0
|
||||
var hit_count: int = 0
|
||||
# How far either side of the line this beam strikes, and how wide it is drawn.
|
||||
var half_width: float = BEAM_HALF_WIDTH
|
||||
|
||||
|
||||
static func fire(world: Node, origin: Vector2, direction: Vector2,
|
||||
beam_range: float, damage: int) -> LaserBeamEffect:
|
||||
beam_range: float, damage: int,
|
||||
beam_half_width: float = BEAM_HALF_WIDTH) -> LaserBeamEffect:
|
||||
var effect := LaserBeamEffect.new()
|
||||
effect.half_width = maxf(beam_half_width, 1.0)
|
||||
var heading: Vector2 = direction.normalized() if direction.length() > 0.001 else Vector2.UP
|
||||
effect.from = origin
|
||||
effect.to = origin + heading * beam_range
|
||||
|
|
@ -83,7 +93,7 @@ func _strike(direction: Vector2, damage: int) -> void:
|
|||
if along < 0.0 or along > range_along:
|
||||
continue
|
||||
var perpendicular: float = (to_enemy - direction * along).length()
|
||||
if perpendicular <= BEAM_HALF_WIDTH:
|
||||
if perpendicular <= half_width:
|
||||
enemy.take_damage(damage)
|
||||
hit_count += 1
|
||||
struck.emit(hit_count)
|
||||
|
|
@ -121,19 +131,20 @@ func _draw() -> void:
|
|||
var flicker: float = 1.0 + 0.09 * sin(time * 70.0 + phase)
|
||||
var at: Vector2 = tip()
|
||||
|
||||
var width_scale: float = half_width * 2.0 / NEON_WIDEST_LAYER
|
||||
NeonDraw.draw_glowing_line(self, from, at, BEAM_COLOR, alpha,
|
||||
BEAM_WIDTH_SCALE * flicker * (1.0 - decay * 0.45))
|
||||
width_scale * flicker * (1.0 - decay * 0.45))
|
||||
# The white-hot rod, over the same span at a fraction of the width. This
|
||||
# is where the extra light comes from: brighter through the middle, not
|
||||
# broader across.
|
||||
NeonDraw.draw_glowing_line(self, from, at, CORE_COLOR, alpha,
|
||||
BEAM_WIDTH_SCALE * CORE_SCALE * flicker)
|
||||
width_scale * CORE_SCALE * flicker)
|
||||
# The leading cap, brightest while the blade is still running out.
|
||||
var cap: float = TIP_RADIUS * (0.7 + 0.3 * (1.0 - decay)) * flicker
|
||||
var cap: float = half_width * TIP_FRACTION * (0.7 + 0.3 * (1.0 - decay)) * flicker
|
||||
NeonDraw.draw_glowing_circle(self, at, cap, CORE_COLOR, alpha)
|
||||
# And the flare left at the emitter, which fades faster than the beam so
|
||||
# the hull does not keep glowing after the shot is over.
|
||||
var muzzle: float = MUZZLE_RADIUS * (1.0 - progress)
|
||||
var muzzle: float = half_width * MUZZLE_FRACTION * (1.0 - progress)
|
||||
if muzzle > 1.0:
|
||||
NeonDraw.draw_glowing_circle(self, from, muzzle, CORE_COLOR,
|
||||
alpha * (1.0 - progress))
|
||||
|
|
|
|||
Loading…
Reference in a new issue