89 lines
3.2 KiB
GDScript
89 lines
3.2 KiB
GDScript
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))
|