extends Control class_name BoltRule ## A lightning bolt struck through a horizontal rule. ## ## The motif the whole UI is built around, in one reusable widget: menus use it ## as a section divider, the HUD uses it to underline a heading. It is drawn ## rather than shipped as an image so it takes the theme's colours and scales to ## any width without a second asset. ## ## The zigzag is deliberately not centred. A bolt centred in its rule reads as an ## ornament; struck a third of the way along, it reads as something that HIT the ## line — which is the difference between decorative and energetic. @export var line_color: Color = Color(1.0, 0.47, 0.10) @export var bolt_color: Color = Color(1.0, 0.93, 0.22) @export var ink: Color = Color(0.045, 0.040, 0.075) ## Where along the rule the bolt strikes, 0..1. @export var strike_at: float = 0.34 @export var thickness: float = 3.0 func _init() -> void: custom_minimum_size = Vector2(0, 22) mouse_filter = Control.MOUSE_FILTER_IGNORE func _draw() -> void: var w := size.x var h := size.y if w <= 1.0: return var mid := h * 0.5 var strike := w * clampf(strike_at, 0.05, 0.95) var half := h * 0.42 # The rule, broken where the bolt lands so the bolt reads as passing # THROUGH it rather than sitting on top. var gap := h * 0.55 draw_line(Vector2(0, mid), Vector2(maxf(0.0, strike - gap), mid), line_color, thickness) draw_line(Vector2(minf(w, strike + gap), mid), Vector2(w, mid), line_color, thickness) # The bolt, as a SIMPLE polygon — six points, no edge crossing another. # `draw_colored_polygon` triangulates, and a self-intersecting outline fails # triangulation outright and draws nothing but a console full of "Invalid # polygon data". The obvious zigzag (down-right, back-left, down-right) # crosses itself; this is the same silhouette walked as a closed loop # instead: down the left edge, out to the tip, back up the right edge. var pts := PackedVector2Array([ Vector2(strike + half * 0.55, mid - half), # top, right of centre Vector2(strike - half * 0.45, mid + half * 0.05), # down-left to the notch Vector2(strike + half * 0.00, mid + half * 0.05), # step right Vector2(strike - half * 0.35, mid + half), # down-left to the tip Vector2(strike + half * 0.55, mid - half * 0.15), # back up the right edge Vector2(strike + half * 0.10, mid - half * 0.15), # step left ]) draw_colored_polygon(pts, bolt_color) # Ink edge ON TOP as a closed polyline, not as a second, larger polygon — # growing a concave shape from its centroid can push a point past its # neighbour and produce exactly the self-intersection above. var loop := pts.duplicate() loop.append(pts[0]) draw_polyline(loop, ink, 2.5)