#130 asked for the hull to break away from the fleet, drift a few metres, and go up further off with something more explosive than a light animation. The wreck is a separate node rather than the Ship staying alive to animate, and that is the load-bearing part. A dying Ship still in the tree is still an Area2D in the player_ships group with live weapon components - it would keep firing, keep being fired at, keep counting as a target, and keep colliding on the way out. So the ship's own lifecycle is untouched: it leaves the fleet, emits destroyed, and is freed on exactly the frame it always was. What is left behind is scenery, and the test pins that. The explosion at the end was also the quieter of the two the game has. Killing an enemy was made deliberately loud by #87 while losing one of your own kept the base class's twelve-particle default - the reward louder than the loss. It is now the bigger of the two. #135 is the same scene from the other end: the prologue's convoy flies its escorts on the corners of the box, which is the exposed part of it, and the debris belt can take all four. With no interceptor left, the only hulls the vortex could spare were holds, and the player flew out of the prologue in a carrier. Two guards now: one interceptor is put back into the convoy at the top of the vortex, where a vessel appearing among ten being thrown around a black hole is not something anyone will catch; and the handover checks the TYPES it hands over rather than only the count - one surviving carrier is also a fleet of one, and it is not the fleet a new game starts with.
This commit is contained in:
parent
397983b611
commit
710dcbf230
8 changed files with 419 additions and 6 deletions
|
|
@ -3,7 +3,20 @@ extends LightBurstVFX
|
|||
|
||||
|
||||
func _init() -> void:
|
||||
# #130: "a rather more explosive explosion than just a light animation".
|
||||
# This used to take the base class's defaults - 12 particles, half a
|
||||
# second, no shockwave - which made losing one of your own vessels a
|
||||
# quieter event on screen than killing an enemy, whose explosion #87
|
||||
# had already been told to be the loudest thing in the frame. Now it is
|
||||
# the louder of the two, which is the right way round: the enemy's is a
|
||||
# reward, this one is a loss.
|
||||
color = Color(0.25, 0.85, 1.0)
|
||||
particle_count = 30
|
||||
lifetime = 0.8
|
||||
min_speed = 150.0
|
||||
max_speed = 540.0
|
||||
shockwave_radius = 120.0
|
||||
shockwave_color = Color(0.6, 0.95, 1.0)
|
||||
|
||||
|
||||
static func spawn(parent: Node, world_position: Vector2) -> void:
|
||||
|
|
|
|||
113
vfx/ShipWreckVFX.gd
Normal file
113
vfx/ShipWreckVFX.gd
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
class_name ShipWreckVFX
|
||||
extends Node2D
|
||||
|
||||
# Forgejo #130: a vessel's death, as a short sequence rather than a moment.
|
||||
#
|
||||
# A ship used to vanish on the frame it was hit and leave a twelve-particle
|
||||
# puff behind - lighter than the one an ENEMY gets (see EnemyExplosionVFX,
|
||||
# which #87 made deliberately loud). Losing a hull is the more expensive
|
||||
# event of the two and it read as the cheaper one.
|
||||
#
|
||||
# So the hull comes off the formation and keeps going: it breaks away from
|
||||
# the fleet, tumbling and venting, for the length of DRIFT_SECONDS, and only
|
||||
# then goes up - out where it has some room, rather than inside the wedge it
|
||||
# was flying in.
|
||||
#
|
||||
# It is a separate node rather than the Ship staying alive a little longer,
|
||||
# and that is the important part. A dying Ship still in the tree is still an
|
||||
# Area2D in the player_ships group with live weapon components: it would keep
|
||||
# shooting, keep being shot at, keep counting as a target, and keep colliding
|
||||
# on its way out. Everything about the ship's own lifecycle - the `destroyed`
|
||||
# signal, leaving Fleet.ships, freeing the node - happens exactly when it did
|
||||
# before. What is left behind is scenery.
|
||||
|
||||
const DRIFT_SECONDS: float = 0.62
|
||||
# How hard it is pushed out of the formation. Enough to clear the wedge in
|
||||
# the time above, not so much that it reads as being thrown.
|
||||
const BREAKAWAY_SPEED: float = 300.0
|
||||
const DRAG: float = 0.72
|
||||
const SPIN_MIN: float = 2.4
|
||||
const SPIN_MAX: float = 7.0
|
||||
const VENT_COUNT: int = 4
|
||||
const VENT_SPEED: float = 90.0
|
||||
# The hull darkens as it goes, so the drift reads as dying rather than as
|
||||
# flying away.
|
||||
const FADE_TO: float = 0.35
|
||||
|
||||
var hull: PackedVector2Array = PackedVector2Array()
|
||||
var glow_color: Color = Color(0.25, 0.85, 1.0)
|
||||
var core_color: Color = Color.WHITE
|
||||
var velocity: Vector2 = Vector2.ZERO
|
||||
var spin: float = 0.0
|
||||
var age: float = 0.0
|
||||
var vents: Array = []
|
||||
var _blown: bool = false
|
||||
|
||||
|
||||
# `away` is the direction out of the formation, so the wreck leaves the fleet
|
||||
# rather than drifting through the middle of it.
|
||||
static func spawn(parent: Node, ship: Node2D, away: Vector2) -> ShipWreckVFX:
|
||||
var wreck := ShipWreckVFX.new()
|
||||
wreck.position = ship.position
|
||||
wreck.rotation = ship.rotation
|
||||
wreck.glow_color = ship.glow_color
|
||||
wreck.core_color = ship.core_color
|
||||
if ship.definition != null:
|
||||
wreck.hull = ship.definition.hull_points
|
||||
var drift: Vector2 = away if away.length() > 0.01 else Vector2.UP.rotated(ship.rotation)
|
||||
# Its own momentum plus the push: a ship hit at speed carries on the way
|
||||
# it was already going.
|
||||
wreck.velocity = ship.velocity + drift.normalized() * BREAKAWAY_SPEED
|
||||
wreck.spin = randf_range(SPIN_MIN, SPIN_MAX) * (1.0 if randf() < 0.5 else -1.0)
|
||||
parent.add_child(wreck)
|
||||
return wreck
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
if hull.is_empty():
|
||||
hull = PackedVector2Array([Vector2(0, -22), Vector2(-14, 16), Vector2(14, 16)])
|
||||
for i in range(VENT_COUNT):
|
||||
var angle: float = TAU * float(i) / float(VENT_COUNT) + randf() * 0.6
|
||||
vents.append({
|
||||
"pos": Vector2.ZERO,
|
||||
"vel": Vector2(cos(angle), sin(angle)) * randf_range(VENT_SPEED * 0.4, VENT_SPEED),
|
||||
"len": randf_range(9.0, 18.0),
|
||||
})
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
age += delta
|
||||
if age >= DRIFT_SECONDS:
|
||||
_blow_up()
|
||||
return
|
||||
position += velocity * delta
|
||||
velocity = velocity.lerp(Vector2.ZERO, clampf(DRAG * delta, 0.0, 1.0))
|
||||
rotation += spin * delta
|
||||
for vent in vents:
|
||||
vent.pos += vent.vel * delta
|
||||
vent.vel *= 0.94
|
||||
queue_redraw()
|
||||
|
||||
|
||||
func _blow_up() -> void:
|
||||
if _blown:
|
||||
return
|
||||
_blown = true
|
||||
# Where it ended up, not where it was hit - the point of the drift.
|
||||
if is_inside_tree():
|
||||
ShipExplosionVFX.spawn(get_tree().root, global_position)
|
||||
queue_free()
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
var t: float = clampf(age / DRIFT_SECONDS, 0.0, 1.0)
|
||||
var fade: float = lerpf(1.0, FADE_TO, t)
|
||||
NeonDraw.draw_glowing_polygon(self, hull, Color(glow_color, fade), 1.0,
|
||||
Color(core_color, fade))
|
||||
# What is coming out of it. Drawn in the wreck's own local space, so the
|
||||
# vents tumble with the hull the way a breach in it would.
|
||||
var vent_colour: Color = Color(1.0, 0.72, 0.35, (1.0 - t) * 0.9)
|
||||
for vent in vents:
|
||||
var dir: Vector2 = Vector2(vent.vel).normalized()
|
||||
NeonDraw.draw_glowing_line(self, vent.pos, vent.pos + dir * float(vent.len),
|
||||
vent_colour, 0.8, 0.4)
|
||||
1
vfx/ShipWreckVFX.gd.uid
Normal file
1
vfx/ShipWreckVFX.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://c30rnnoa6fkcd
|
||||
Loading…
Reference in a new issue