1
0
Fork 0
space-capture/scenes/line_trail/line_trail_2d.gd
2024-09-01 14:45:22 +02:00

105 lines
3.2 KiB
GDScript

class_name LineTrail2D
extends Line2D
## Leave a trail behind this node.
@export var tracking: Node2D
## Minimum distance before adding a new point to the trail line.
## 0 = always add a new point on each frame.
@export var min_distance: float = 1.
## Maximum length of the trail before starting to trim.
## 0 = no length limit.
@export var max_length: float = 0.
## Maximum lifetime of the trail (in seconds) before starting to trim.
## 0 = no lifetime limit.
@export var max_lifetime: float = 3.
# Each index represents the remaining time in seconds before each point is
# removed from the line, starting to count after the previous point is removed.
# As an example: [1, 2, 2] means that the first point will be removed in 1
# second; the second point 2 seconds after the first (so 3 seconds from now);
# and the third point 2 seconds after the second (so 5 seconds from now).
var _points_life := PackedFloat32Array()
func _ready() -> void:
clear_points()
func _process(delta: float) -> void:
global_transform = Transform2D.IDENTITY
var new_position := tracking.global_position
# Add new points.
var maybe_exceeds_max_length := false
if _points_life.size() == 0:
_add_point(new_position)
else:
var last_point := get_point_position(_points_life.size() - 1)
var distance_sqr := (new_position - last_point).length_squared()
if distance_sqr >= min_distance * min_distance:
_add_point(new_position)
maybe_exceeds_max_length = true
# Reduce life and remove expired points.
var remove_count := 0
if max_lifetime != 0.:
_decrease_life(delta)
remove_count += _count_expired_points(remove_count)
# Check if line length exceeds max length.
if maybe_exceeds_max_length and max_length != 0.:
remove_count += _count_overlength_points(remove_count)
# Remove expired or overlength points.
if remove_count > 0:
_remove_oldest_points(remove_count)
func _add_point(point_position: Vector2) -> void:
add_point(point_position)
var last_point_points_life := 0.
for time in _points_life:
last_point_points_life += time
_points_life.append(max_lifetime - last_point_points_life)
func _remove_oldest_points(remove_count: int) -> void:
if remove_count > 0:
points = points.slice(remove_count)
_points_life = _points_life.slice(remove_count)
func _decrease_life(delta: float, start_at := 0) -> void:
var i := start_at
while _points_life.size() > i and delta > 0.:
var sub = minf(delta, _points_life[i])
_points_life[i] -= sub
delta -= sub
i += 1
func _count_expired_points(start_at := 0) -> int:
var i := start_at
while i < _points_life.size() and _points_life[i] <= 0.:
i += 1
return i - start_at
func _count_overlength_points(start_at := 0) -> int:
var length := 0.
var all_points := points
var previous_point := all_points[start_at]
for i in range(start_at + 1, all_points.size()):
var point := all_points[i]
length += (point - previous_point).length()
previous_point = point
var overlength_count := 0
while length > max_length and overlength_count < all_points.size() - 1:
var removed_point = all_points[overlength_count]
var next_point = all_points[overlength_count + 1]
length -= (removed_point - next_point).length()
overlength_count += 1
return overlength_count