#108: the prologue - the convoy, the ambush, and the breach
Landed as one piece across #122, #123 and #124: the frame is useless without
a script, and the script has nowhere to run without the frame.
The director drives the REAL scene rather than being a scene of its own. It
wants the real fleet, the real enemies and the real asteroid field, and it
makes "then the game starts" cost nothing - the director stops steering,
clears the flag, and what is left running is the ordinary game.
The script is a list of beats, each with a deadline as well as its own
completion test, so a beat whose condition is never met - a player who
refuses to fly at the ambush - runs out rather than wedging the prologue.
skip() ends the whole thing at any point and lands in exactly the state
playing it through does, so the game has one way to start rather than two
that have to be kept in step. The test pins that equivalence.
"No action button available, only movements" is enforced where the buttons
are decided, not by the director reaching in: the ability controllers set
their own visibility every frame and would have put them straight back, and
the map button belongs to the map. The joystick, the pivot and the fader
stay.
The convoy is ten hulls where a new game's fleet is one, so it needs an
explicit fleet-size override - a plain number rather than a fake doctrine,
because nothing about the player's own progression should be bent to fit a
cutscene. It is carriers rather than transporters: transporters belong to
hubs and are not fleet-eligible, so a convoy of them would be silently
filtered down to its escorts.
The ambush is chasers and only chasers. "Easy enough" is the requirement,
and a sniper against a convoy the player cannot yet fight properly is
neither easy nor a good first impression.
The breach takes the wheel through one check in GameController, covering the
stick, the keyboard and the released-again path together - three separate
gates would be three chances for one of them to keep steering. The shake is
written to camera.offset, never to its position, because GameController owns
where the camera is and would smooth a shake away.
The vessel that survives is chosen as the interceptor rather than whichever
happened to be first in the list, and the prologue ends on exactly a new
game's opening position.
Also: PlanetAtmosphereController no longer spawns the opening fleet while
the prologue is arming, and the tests that are about what the GAME starts
from now say so by turning the prologue off.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 20:59:12 +02:00
|
|
|
extends Control
|
|
|
|
|
|
|
|
|
|
# #122: what the guide says during the prologue.
|
|
|
|
|
#
|
|
|
|
|
# A banner rather than a dialogue box: the player is flying while they read
|
|
|
|
|
# it, so it sits across the top out of the way of the fleet and never takes
|
|
|
|
|
# a press to dismiss. The SCRIPT decides when a line is done, not the player
|
|
|
|
|
# - a prologue that waits for a tap is a prologue that can be sat in.
|
|
|
|
|
#
|
|
|
|
|
# Lines queue rather than replacing each other, so a beat that fires while
|
|
|
|
|
# the previous line is still up does not silently eat it.
|
|
|
|
|
|
#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
|
|
|
# #125: lines were gone before they had been read. A held line is the
|
|
|
|
|
# cheapest possible pacing control and the prologue leans on it heavily.
|
|
|
|
|
const HOLD_SECONDS: float = 6.5
|
#108: the prologue - the convoy, the ambush, and the breach
Landed as one piece across #122, #123 and #124: the frame is useless without
a script, and the script has nowhere to run without the frame.
The director drives the REAL scene rather than being a scene of its own. It
wants the real fleet, the real enemies and the real asteroid field, and it
makes "then the game starts" cost nothing - the director stops steering,
clears the flag, and what is left running is the ordinary game.
The script is a list of beats, each with a deadline as well as its own
completion test, so a beat whose condition is never met - a player who
refuses to fly at the ambush - runs out rather than wedging the prologue.
skip() ends the whole thing at any point and lands in exactly the state
playing it through does, so the game has one way to start rather than two
that have to be kept in step. The test pins that equivalence.
"No action button available, only movements" is enforced where the buttons
are decided, not by the director reaching in: the ability controllers set
their own visibility every frame and would have put them straight back, and
the map button belongs to the map. The joystick, the pivot and the fader
stay.
The convoy is ten hulls where a new game's fleet is one, so it needs an
explicit fleet-size override - a plain number rather than a fake doctrine,
because nothing about the player's own progression should be bent to fit a
cutscene. It is carriers rather than transporters: transporters belong to
hubs and are not fleet-eligible, so a convoy of them would be silently
filtered down to its escorts.
The ambush is chasers and only chasers. "Easy enough" is the requirement,
and a sniper against a convoy the player cannot yet fight properly is
neither easy nor a good first impression.
The breach takes the wheel through one check in GameController, covering the
stick, the keyboard and the released-again path together - three separate
gates would be three chances for one of them to keep steering. The shake is
written to camera.offset, never to its position, because GameController owns
where the camera is and would smooth a shake away.
The vessel that survives is chosen as the interceptor rather than whichever
happened to be first in the list, and the prologue ends on exactly a new
game's opening position.
Also: PlanetAtmosphereController no longer spawns the opening fleet while
the prologue is arming, and the tests that are about what the GAME starts
from now say so by turning the prologue off.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 20:59:12 +02:00
|
|
|
const FADE_SECONDS: float = 0.5
|
|
|
|
|
const TEXT_COLOR: Color = Color(0.82, 0.92, 1.0)
|
|
|
|
|
const FRAME_COLOR: Color = Color(0.45, 0.68, 0.95)
|
#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
|
|
|
# #125: the panel was a plain rectangle with a line under it. These are the
|
|
|
|
|
# pieces that make it read as a transmission window instead - the corners
|
|
|
|
|
# are cut, the short edges are brackets rather than sides, and there is a
|
|
|
|
|
# tick strip along the bottom. All of it is geometry rather than art, so it
|
|
|
|
|
# scales with the banner and costs nothing.
|
|
|
|
|
const CUT: float = 26.0
|
|
|
|
|
const BRACKET: float = 34.0
|
|
|
|
|
const INSET: float = 7.0
|
|
|
|
|
const TICK_COUNT: int = 24
|
|
|
|
|
const TICK_HEIGHT: float = 5.0
|
#108: the prologue - the convoy, the ambush, and the breach
Landed as one piece across #122, #123 and #124: the frame is useless without
a script, and the script has nowhere to run without the frame.
The director drives the REAL scene rather than being a scene of its own. It
wants the real fleet, the real enemies and the real asteroid field, and it
makes "then the game starts" cost nothing - the director stops steering,
clears the flag, and what is left running is the ordinary game.
The script is a list of beats, each with a deadline as well as its own
completion test, so a beat whose condition is never met - a player who
refuses to fly at the ambush - runs out rather than wedging the prologue.
skip() ends the whole thing at any point and lands in exactly the state
playing it through does, so the game has one way to start rather than two
that have to be kept in step. The test pins that equivalence.
"No action button available, only movements" is enforced where the buttons
are decided, not by the director reaching in: the ability controllers set
their own visibility every frame and would have put them straight back, and
the map button belongs to the map. The joystick, the pivot and the fader
stay.
The convoy is ten hulls where a new game's fleet is one, so it needs an
explicit fleet-size override - a plain number rather than a fake doctrine,
because nothing about the player's own progression should be bent to fit a
cutscene. It is carriers rather than transporters: transporters belong to
hubs and are not fleet-eligible, so a convoy of them would be silently
filtered down to its escorts.
The ambush is chasers and only chasers. "Easy enough" is the requirement,
and a sniper against a convoy the player cannot yet fight properly is
neither easy nor a good first impression.
The breach takes the wheel through one check in GameController, covering the
stick, the keyboard and the released-again path together - three separate
gates would be three chances for one of them to keep steering. The shake is
written to camera.offset, never to its position, because GameController owns
where the camera is and would smooth a shake away.
The vessel that survives is chosen as the interceptor rather than whichever
happened to be first in the list, and the prologue ends on exactly a new
game's opening position.
Also: PlanetAtmosphereController no longer spawns the opening fleet while
the prologue is arming, and the tests that are about what the GAME starts
from now say so by turning the prologue off.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 20:59:12 +02:00
|
|
|
|
|
|
|
|
var label: Label
|
|
|
|
|
var queued: Array = []
|
|
|
|
|
var current: String = ""
|
|
|
|
|
var time_left: float = 0.0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _ready() -> void:
|
|
|
|
|
_ensure_label()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# The director is a world node and this banner lives under the UI layer,
|
|
|
|
|
# which readies afterwards - so the first line can arrive before _ready().
|
|
|
|
|
# Building on demand is simpler than making the director wait a frame, and
|
|
|
|
|
# it cannot be got wrong twice.
|
|
|
|
|
func _ensure_label() -> void:
|
|
|
|
|
if label != null:
|
|
|
|
|
return
|
|
|
|
|
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
|
|
|
visible = false
|
|
|
|
|
label = Label.new()
|
|
|
|
|
label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
|
|
|
label.add_theme_font_size_override("font_size", 30)
|
|
|
|
|
label.add_theme_color_override("font_color", TEXT_COLOR)
|
|
|
|
|
label.add_theme_color_override("font_outline_color", Color(0.01, 0.02, 0.06, 0.95))
|
|
|
|
|
label.add_theme_constant_override("outline_size", 4)
|
|
|
|
|
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
|
|
|
|
label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
|
|
|
|
label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
|
|
|
|
add_child(label)
|
|
|
|
|
resized.connect(_layout)
|
|
|
|
|
_layout()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _layout() -> void:
|
|
|
|
|
if label == null:
|
|
|
|
|
return
|
|
|
|
|
label.position = Vector2(24.0, 0.0)
|
|
|
|
|
label.size = Vector2(maxf(size.x - 48.0, 0.0), size.y)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Says one line. Held for `hold` seconds, then the next in the queue.
|
|
|
|
|
func say(line: String, hold: float = HOLD_SECONDS) -> void:
|
|
|
|
|
_ensure_label()
|
|
|
|
|
queued.append({"line": line, "hold": maxf(hold, 0.1)})
|
|
|
|
|
if current == "":
|
|
|
|
|
_advance()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func clear() -> void:
|
|
|
|
|
queued.clear()
|
|
|
|
|
current = ""
|
|
|
|
|
time_left = 0.0
|
|
|
|
|
visible = false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func is_speaking() -> bool:
|
|
|
|
|
return current != "" or not queued.is_empty()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _advance() -> void:
|
|
|
|
|
if queued.is_empty():
|
|
|
|
|
current = ""
|
|
|
|
|
time_left = 0.0
|
|
|
|
|
visible = false
|
|
|
|
|
return
|
|
|
|
|
var next: Dictionary = queued.pop_front()
|
|
|
|
|
current = String(next.line)
|
|
|
|
|
time_left = float(next.hold)
|
|
|
|
|
label.text = current
|
|
|
|
|
visible = true
|
|
|
|
|
queue_redraw()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _process(delta: float) -> void:
|
|
|
|
|
if current == "":
|
|
|
|
|
return
|
|
|
|
|
time_left -= delta
|
|
|
|
|
queue_redraw()
|
|
|
|
|
if time_left <= 0.0:
|
|
|
|
|
_advance()
|
|
|
|
|
|
|
|
|
|
|
#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
|
|
|
# The panel's outline: a rectangle with its corners cut off. Returned rather
|
|
|
|
|
# than drawn so the fill and the stroke are guaranteed to be the same shape.
|
|
|
|
|
func _frame() -> PackedVector2Array:
|
|
|
|
|
var w: float = size.x
|
|
|
|
|
var h: float = size.y
|
|
|
|
|
return PackedVector2Array([
|
|
|
|
|
Vector2(CUT, 0.0), Vector2(w - CUT, 0.0), Vector2(w, CUT),
|
|
|
|
|
Vector2(w, h - CUT), Vector2(w - CUT, h), Vector2(CUT, h),
|
|
|
|
|
Vector2(0.0, h - CUT), Vector2(0.0, CUT),
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
|
#108: the prologue - the convoy, the ambush, and the breach
Landed as one piece across #122, #123 and #124: the frame is useless without
a script, and the script has nowhere to run without the frame.
The director drives the REAL scene rather than being a scene of its own. It
wants the real fleet, the real enemies and the real asteroid field, and it
makes "then the game starts" cost nothing - the director stops steering,
clears the flag, and what is left running is the ordinary game.
The script is a list of beats, each with a deadline as well as its own
completion test, so a beat whose condition is never met - a player who
refuses to fly at the ambush - runs out rather than wedging the prologue.
skip() ends the whole thing at any point and lands in exactly the state
playing it through does, so the game has one way to start rather than two
that have to be kept in step. The test pins that equivalence.
"No action button available, only movements" is enforced where the buttons
are decided, not by the director reaching in: the ability controllers set
their own visibility every frame and would have put them straight back, and
the map button belongs to the map. The joystick, the pivot and the fader
stay.
The convoy is ten hulls where a new game's fleet is one, so it needs an
explicit fleet-size override - a plain number rather than a fake doctrine,
because nothing about the player's own progression should be bent to fit a
cutscene. It is carriers rather than transporters: transporters belong to
hubs and are not fleet-eligible, so a convoy of them would be silently
filtered down to its escorts.
The ambush is chasers and only chasers. "Easy enough" is the requirement,
and a sniper against a convoy the player cannot yet fight properly is
neither easy nor a good first impression.
The breach takes the wheel through one check in GameController, covering the
stick, the keyboard and the released-again path together - three separate
gates would be three chances for one of them to keep steering. The shake is
written to camera.offset, never to its position, because GameController owns
where the camera is and would smooth a shake away.
The vessel that survives is chosen as the interceptor rather than whichever
happened to be first in the list, and the prologue ends on exactly a new
game's opening position.
Also: PlanetAtmosphereController no longer spawns the opening fleet while
the prologue is arming, and the tests that are about what the GAME starts
from now say so by turning the prologue off.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 20:59:12 +02:00
|
|
|
func _draw() -> void:
|
|
|
|
|
if current == "":
|
|
|
|
|
return
|
|
|
|
|
# Fades out over its last moments so lines hand over rather than cutting.
|
|
|
|
|
var alpha: float = clampf(time_left / FADE_SECONDS, 0.0, 1.0)
|
|
|
|
|
label.modulate.a = alpha
|
#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
|
|
|
var frame: PackedVector2Array = _frame()
|
|
|
|
|
|
|
|
|
|
draw_colored_polygon(frame, Color(0.02, 0.05, 0.12, 0.78 * alpha))
|
|
|
|
|
NeonDraw.draw_glowing_polygon(self, frame, Color(FRAME_COLOR, alpha), 0.8)
|
|
|
|
|
|
|
|
|
|
# Brackets at the short edges: a doubled inner line that stops well short
|
|
|
|
|
# of the corners, so the panel reads as held open rather than closed.
|
|
|
|
|
for side in [0.0, 1.0]:
|
|
|
|
|
var x: float = lerpf(INSET, size.x - INSET, side)
|
|
|
|
|
NeonDraw.draw_glowing_line(self, Vector2(x, CUT + INSET),
|
|
|
|
|
Vector2(x, size.y - CUT - INSET), Color(FRAME_COLOR, alpha * 0.75), 0.6, 0.3)
|
|
|
|
|
var arm: float = BRACKET * (1.0 if side < 0.5 else -1.0)
|
|
|
|
|
for y in [CUT + INSET, size.y - CUT - INSET]:
|
|
|
|
|
NeonDraw.draw_glowing_line(self, Vector2(x, y), Vector2(x + arm, y),
|
|
|
|
|
Color(FRAME_COLOR, alpha * 0.75), 0.6, 0.3)
|
|
|
|
|
|
|
|
|
|
# A tick strip along the bottom, dimming toward the ends. It is the one
|
|
|
|
|
# piece that is pure texture, and it is what stops the lower edge from
|
|
|
|
|
# reading as a plain underline.
|
|
|
|
|
var span: float = size.x - CUT * 2.0
|
|
|
|
|
for i in range(TICK_COUNT):
|
|
|
|
|
var t: float = float(i) / float(TICK_COUNT - 1)
|
|
|
|
|
var tx: float = CUT + span * t
|
|
|
|
|
var lit: float = 0.25 + 0.55 * sin(t * PI)
|
|
|
|
|
draw_line(Vector2(tx, size.y - INSET), Vector2(tx, size.y - INSET - TICK_HEIGHT),
|
|
|
|
|
Color(FRAME_COLOR, alpha * lit), 2.0, true)
|
|
|
|
|
|
|
|
|
|
# And a caret in the top-left corner, so a line reads as being SAID by
|
|
|
|
|
# someone rather than printed on the glass.
|
|
|
|
|
NeonDraw.draw_glowing_path(self, PackedVector2Array([
|
|
|
|
|
Vector2(CUT + 4.0, INSET + 8.0), Vector2(CUT + 16.0, INSET + 15.0),
|
|
|
|
|
Vector2(CUT + 4.0, INSET + 22.0),
|
|
|
|
|
]), Color(0.72, 0.92, 1.0, alpha * 0.9), 0.9, 0.4)
|