extends Node2D var gas_phase: float = 0.0 var _rim: NeonPiece func configure(_shape_seed: int) -> void: queue_redraw() func extractor_anchor() -> Vector2: return Vector2(0.0, -118.0) func _process(delta: float) -> void: gas_phase += delta queue_redraw() # The bands genuinely deform - each point moves along its own sine - so they # are the one thing here that has to be re-tessellated to animate. The rim # does not move at all, so it is a NeonPiece child rasterised once rather # than a thirty-two point polygon rebuilt every frame alongside them # (issues #6/#10). func _ensure_rim() -> void: if _rim != null: return var points := PackedVector2Array() for i in range(32): var angle := TAU * float(i) / 32.0 points.append(Vector2(cos(angle) * 118.0, sin(angle) * 118.0)) _rim = NeonPiece.create(self, Vector2.ZERO, Color(0.4, 0.78, 1.0)) _rim.add_polygon(points, 0.9) func _draw() -> void: _ensure_rim() for row in [-62.0, -28.0, 8.0, 43.0, 73.0]: var band := PackedVector2Array() var half_width: float = sqrt(maxf(0.0, 118.0 * 118.0 - row * row)) for i in range(15): var x := lerpf(-half_width, half_width, float(i) / 14.0) band.append(Vector2(x, row + sin(x * 0.045 + gas_phase * 1.6 + row) * 7.0)) NeonDraw.draw_glowing_path(self, band, Color(0.85, 0.52, 1.0), 0.75, 0.65)