extends Node2D # Forgejo #79: a small "+N" with the resource's own mark, rising and fading # where the fleet picked something up. # # Collecting used to be entirely silent - a rock vanished and a number in the # corner of the screen changed. Which number, and by how much, was left for # the player to notice on their own. This says it at the point it happened, # in the resource's own colour, and gets out of the way. # # Built from the SAME glyph scene the resource tables and transfer rows use # (ResourceDefinition.glyph_scene), so a new material added to the catalog # gets a correct pickup mark with no work here - and can never end up with # one mark in the HUD and a different one in the world. const RESOURCE_DEFINITIONS = preload("res://ResourceDefinitions.gd") # Deliberately NO class_name, and the constructor below loads this file by # path rather than naming the class. A global class-name identifier - even a # script's own, inside its own static function - needs the class cache already # warm, and it is not when this is reached indirectly through a preview scene # loading Main.tscn. That failed to compile outright, taking Rock and the gas # vents down with it. Callers preload the path too; see Rock.gd. const SELF_PATH: String = "res://ResourcePickupVFX.gd" const RISE_DISTANCE: float = 46.0 const DURATION: float = 0.85 const GLYPH_SIZE: float = 22.0 const DIGIT_HEIGHT: float = 20.0 # Held fully opaque for the first part of its life, so the eye has time to # catch it before it starts going. const FADE_START: float = 0.45 var age: float = 0.0 var colour: Color = Color.WHITE var start_y: float = 0.0 static func spawn(parent: Node, world_position: Vector2, resource_type: String, amount: int) -> void: if amount <= 0: return var vfx: Node2D = (load(SELF_PATH) as GDScript).new() vfx.position = world_position vfx.build(resource_type, amount) parent.add_child(vfx) func build(resource_type: String, amount: int) -> void: var definition: Resource = RESOURCE_DEFINITIONS.get_definition(resource_type) colour = definition.color if definition != null else Color.WHITE if definition != null and definition.glyph_scene != null: var glyph: Control = definition.glyph_scene.instantiate() glyph.colour = definition.color # Anchors first. The glyph scenes are authored as full-rect Controls # for the panels that host them, and Godot recomputes the size of any # Control with non-equal opposite anchors right after _ready() - so # assigning size without this is overwritten, with a warning, the # moment it enters the tree. glyph.set_anchors_preset(Control.PRESET_TOP_LEFT) glyph.size = Vector2(GLYPH_SIZE, GLYPH_SIZE) glyph.position = Vector2(-2.0, -GLYPH_SIZE * 0.5) add_child(glyph) # show_icon off: the resource's own glyph is already beside it, and # NeonNumber's built-in mark is the ore hexagon whatever the amount is. var number := NeonNumber.new() number.show_icon = false number.amount = amount number.digit_height = DIGIT_HEIGHT number.glow_color = colour number.core_color = colour.darkened(0.8) number.size = Vector2(60.0, DIGIT_HEIGHT) number.position = Vector2(GLYPH_SIZE + 4.0, -DIGIT_HEIGHT * 0.5) add_child(number) start_y = position.y z_index = 40 func _process(delta: float) -> void: age += delta var t: float = age / DURATION if t >= 1.0: queue_free() return # Eases out: quick off the mark, drifting by the end. position.y = start_y - RISE_DISTANCE * (1.0 - pow(1.0 - t, 2.0)) modulate.a = 1.0 if t < FADE_START else 1.0 - (t - FADE_START) / (1.0 - FADE_START) queue_redraw() func _draw() -> void: # The plus sign, drawn here rather than as a third child - it is two # strokes and giving it its own node would cost more than it saves. var centre := Vector2(-12.0, 0.0) var arm: float = 5.0 NeonDraw.draw_glowing_line(self, centre - Vector2(arm, 0.0), centre + Vector2(arm, 0.0), colour, 1.0, 0.5, colour.darkened(0.8)) NeonDraw.draw_glowing_line(self, centre - Vector2(0.0, arm), centre + Vector2(0.0, arm), colour, 1.0, 0.5, colour.darkened(0.8))