forked from godot-extended-libraries/godot-next
-
Notifications
You must be signed in to change notification settings - Fork 11
/
trail_2d.gd
127 lines (108 loc) · 4.4 KB
/
trail_2d.gd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
class_name Trail2D, "../icons/icon_trail_2d.svg"
extends Line2D
# author: willnationsdev
# brief description: Creates a variable-length trail that tracks the "target" node.
# API details:
# - Use CanvasItem.show_behind_parent or Node2D.z_index (Inspector) to control its layer visibility
# - 'target' and 'target_path' (the 'target vars') will update each other as they are modified
# - If you assign an empty 'target var', the value will automatically update to grab the parent.
# - To completely turn off the Trail2D, set its `trail_length` to 0
# - The node will automatically update its target vars when it is moved around in the tree
# - You can set the "persistence" mode to have it...
# - vanish the trail over time (Off)
# - persist the trail forever, unless modified directly (Always)
# - persist conditionally:
# - persist automatically during movement and then shrink over time when you stop
# - persist according to your own custom logic:
# - use `bool _should_grow()` to return under what conditions
# a point should be added underneath the target.
# - use `bool _should_shrink()` to return under what conditions
# the degen_rate should be removed from the trail's list of points.
enum Persistence {
OFF, # Do not persist. Remove all points after the trail_length.
ALWAYS, # Always persist. Do not remove any points.
CONDITIONAL, # Sometimes persist. Choose an algorithm for when to add and remove points.
}
enum PersistWhen {
ON_MOVEMENT, # Add points during movement and remove points when not moving.
CUSTOM, # Override _should_grow() and _should_shrink() to define when to add/remove points.
}
# The NodePath to the target.
export var target_path: NodePath = @".." setget set_target_path
# If not persisting, the number of points that should be allowed in the trail.
export var trail_length: int = 10
# To what degree the trail should remain in existence before automatically removing points.
export(int, "Off", "Always", "Conditional") var persistence: int = Persistence.OFF
# During conditional persistence, which persistence algorithm to use.
export(int, "On Movement", "Custom") var persistence_condition: int = PersistWhen.ON_MOVEMENT
# During conditional persistence, how many points to remove per frame.
export var degen_rate: int = 1
# If true, automatically set z_index to be one less than the 'target'.
export var auto_z_index: bool = true
# If true, will automatically setup a gradient for a gradually transparent trail.
export var auto_alpha_gradient: bool = true
# The target node to track.
var target: Node2D setget set_target
func _init():
set_as_toplevel(true)
global_position = Vector2()
global_rotation = 0
if auto_alpha_gradient and not gradient:
gradient = Gradient.new()
var first = default_color
first.a = 0
gradient.set_color(0, first)
gradient.set_color(1, default_color)
func _notification(p_what: int):
match p_what:
NOTIFICATION_PARENTED:
self.target_path = target_path
if auto_z_index:
z_index = target.z_index - 1 if target else 0
NOTIFICATION_UNPARENTED:
self.target_path = @""
self.trail_length = 0
func _process(_delta: float):
if target:
match persistence:
Persistence.OFF:
add_point(target.global_position)
while get_point_count() > trail_length:
remove_point(0)
Persistence.ALWAYS:
add_point(target.global_position)
pass
Persistence.CONDITIONAL:
match persistence_condition:
PersistWhen.ON_MOVEMENT:
var moved: bool = get_point_position(get_point_count()-1) != target.global_position if get_point_count() else false
if not get_point_count() or moved:
add_point(target.global_position)
else:
#warning-ignore:unused_variable
for i in range(degen_rate):
remove_point(0)
PersistWhen.CUSTOM:
if _should_grow():
add_point(target.global_position)
if _should_shrink():
#warning-ignore:unused_variable
for i in range(degen_rate):
remove_point(0)
func erase_trail():
#warning-ignore:unused_variable
for i in range(get_point_count()):
remove_point(0)
func set_target(p_value: Node2D):
if p_value:
if get_path_to(p_value) != target_path:
set_target_path(get_path_to(p_value))
else:
target_path = @""
func set_target_path(p_value: NodePath):
target_path = p_value
target = get_node(p_value) as Node2D if has_node(p_value) else null
func _should_grow() -> bool:
return true
func _should_shrink() -> bool:
return true