extends Node2D const PICKUP := preload("res://scripts/items/mineral_pickup.gd") var _elapsed := 0.0 var _dust: Array[Dictionary] = [] func configure(sprite: Sprite2D, count: int = 6, mineral: String = "iron") -> void: transform = sprite.global_transform var source_scale := scale scale = Vector2.ONE var dimensions := sprite.texture.get_size() var offset := randf() var cracks: Array[PackedVector2Array] = [] for index in count: var endpoint := _edge_point(offset + float(index) * 4.0 / count) * dimensions cracks.append(_fracture_edge(endpoint, count)) for index in count: # Neighbours share the same jagged fracture, so the pieces fit together. var start := offset + float(index) * 4.0 / count var finish := offset + float(index + 1) * 4.0 / count var vertices := cracks[index].duplicate() for corner in range(int(floor(start)) + 1, int(ceil(finish))): vertices.append(_edge_point(float(corner)) * dimensions) var next_crack := cracks[(index + 1) % count] for vertex_index in range(next_crack.size() - 1, 0, -1): vertices.append(next_crack[vertex_index]) var center := Vector2.ZERO for vertex in vertices: center += vertex center /= vertices.size() var fragment_points := PackedVector2Array() var fragment_uv := PackedVector2Array() for vertex in vertices: fragment_points.append((vertex - center) * source_scale) fragment_uv.append(vertex / dimensions + Vector2(0.5, 0.5)) var fragment := Node2D.new() fragment.set_script(PICKUP) fragment.set("mineral", mineral) fragment.set("texture", sprite.texture) fragment.set("points", fragment_points) fragment.set("uv", fragment_uv) fragment.position = center * source_scale fragment.set("drift", center.normalized() * randf_range(65.0, 115.0)) fragment.set("spin", randf_range(-2.5, 2.5)) add_child(fragment) for index in 28: _dust.append({"velocity": Vector2.from_angle(randf() * TAU) * randf_range(45.0, 180.0), "size": randf_range(1.0, 3.0)}) light_mask = 4 func _fracture_edge(endpoint: Vector2, count: int) -> PackedVector2Array: var edge := PackedVector2Array([Vector2.ZERO]) var normal := endpoint.orthogonal().normalized() var roughness := endpoint.length() * minf(0.14, 0.65 / count) var side := -1.0 if randf() < 0.5 else 1.0 for index in 5: var along := float(index + 1) / 6.0 var offset := roughness * sin(along * PI) * side * randf_range(0.6, 1.0) edge.append(endpoint * along + normal * offset) side *= -1.0 edge.append(endpoint) return edge func _edge_point(distance: float) -> Vector2: var t := fposmod(distance, 4.0) if t < 1.0: return Vector2(-0.5 + t, -0.5) if t < 2.0: return Vector2(0.5, -0.5 + t - 1.0) if t < 3.0: return Vector2(0.5 - (t - 2.0), 0.5) return Vector2(-0.5, 0.5 - (t - 3.0)) func _process(delta: float) -> void: _elapsed += delta if _elapsed <= 1.0: queue_redraw() elif not _dust.is_empty(): _dust.clear() queue_redraw() if _elapsed > 1.0 and get_child_count() == 0: queue_free() func _draw() -> void: var fade := maxf(0.0, 1.0 - _elapsed) for mote in _dust: draw_circle(mote.velocity * (1.0 - exp(-2.0 * _elapsed)) * 0.5, mote.size, Color(0.7, 0.75, 0.8, fade * 0.65)) if _elapsed < 0.18: draw_circle(Vector2.ZERO, 16.0 * (1.0 - _elapsed / 0.18), Color(0.85, 0.9, 1.0, fade * 0.5))