Skip to content

Commit bba353c

Browse files
committed
Extract a common base for RopeAnchor and RopeHandle
1 parent a57099b commit bba353c

3 files changed

Lines changed: 103 additions & 91 deletions

File tree

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
extends Marker2D
2+
class_name BaseRopeTool2D
3+
4+
## Base class for tools like [RopeHandle] and [RopeAnchor] which work on a specific position on a
5+
## specific rope.
6+
7+
## Fake property to trigger a refresh in editor.
8+
@export var force_update: bool: set = _set_force_update
9+
10+
## Enable or disable processing.
11+
@export var enable: bool = true : set = set_enable
12+
13+
## Target rope node.
14+
@export_node_path("Rope") var rope_path: NodePath : set = set_rope_path
15+
16+
## Position on the rope between 0 and 1.
17+
@export_range(0.0, 1.0) var rope_position: float = 1.0 : set = set_rope_position
18+
19+
## If false, only consider the nearest vertex on the rope. Otherwise, interpolate the position between two relevant points when applicable.
20+
@export var precise: bool = false
21+
22+
23+
var _helper: RopeToolHelper
24+
25+
26+
func _init(rope_tool_helper: RopeToolHelper) -> void:
27+
_helper = rope_tool_helper
28+
add_child(_helper)
29+
30+
31+
func _ready() -> void:
32+
set_rope_path(rope_path)
33+
set_enable(enable)
34+
35+
36+
## Determine the nearest position on the rope to this node and use it as target position.
37+
func use_nearest_position() -> void:
38+
use_nearest_position_to_point(global_position)
39+
40+
41+
## Determine the nearest position on the rope to the given point and use it as target position.
42+
func use_nearest_position_to_point(point: Vector2) -> void:
43+
var rope := _helper.target_rope
44+
if rope:
45+
# TODO: Determine precise percentage, not just nearest index
46+
var idx := rope.get_nearest_point_index(point)
47+
var perc := rope.get_point_perc(idx)
48+
rope_position = perc
49+
50+
51+
func set_rope_path(value: NodePath) -> void:
52+
if value == rope_path:
53+
return
54+
55+
rope_path = value
56+
57+
if is_inside_tree():
58+
_helper.set_target_rope_path(rope_path, self)
59+
60+
61+
func set_enable(value: bool) -> void:
62+
if enable == value:
63+
return
64+
65+
enable = value
66+
_helper.enable = value
67+
68+
69+
func set_rope_position(value: float) -> void:
70+
if value == rope_position:
71+
return
72+
rope_position = value
73+
74+
75+
func _set_force_update(_val: bool) -> void:
76+
if _helper.target_rope:
77+
_update()
78+
79+
80+
## Should be overridden
81+
func _update() -> void:
82+
pass

demo/addons/ropesim/RopeAnchor.gd

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,20 @@
11
@tool
2-
extends Marker2D
2+
extends BaseRopeTool2D
33
class_name RopeAnchor
44

55
## Can be used to attach nodes at certain positions on a target rope.
66

77
## Gets emitted just after applying the position. This happens always during _physics_process().
88
signal on_after_update()
99

10-
@export var force_update: bool: set = _set_force_update
11-
## Enable or disable.
12-
@export var enable: bool = true: get = get_enable, set = set_enable
13-
## Target rope node.
14-
@export_node_path("Rope") var rope_path: NodePath: set = set_rope_path
15-
## Position on the rope between 0 and 1.
16-
@export_range(0.0, 1.0) var rope_position: float = 1.0
1710
## Also apply rotation according to the rope curvature.
1811
@export var apply_angle := false
19-
## If false, only consider the nearest vertex on the rope. Otherwise, interpolate the position between two relevant points when applicable.
20-
@export var precise: bool = false
2112

22-
var _helper: RopeToolHelper
2313
var _last_pos: Vector2
2414

2515

2616
func _init() -> void:
27-
if not _helper:
28-
_helper = RopeToolHelper.new(RopeToolHelper.UPDATE_HOOK_POST, self, "_on_post_update")
29-
add_child(_helper)
30-
31-
32-
func _ready() -> void:
33-
set_rope_path(rope_path)
34-
set_enable(enable)
17+
super._init(RopeToolHelper.new(RopeToolHelper.UPDATE_HOOK_POST, self, "_on_post_update"))
3518

3619

3720
func _on_post_update() -> void:
@@ -46,15 +29,6 @@ func set_rope_path(value: NodePath) -> void:
4629
_helper.set_target_rope_path(rope_path, self)
4730

4831

49-
func set_enable(value: bool) -> void:
50-
enable = value
51-
_helper.enable = value
52-
53-
54-
func get_enable() -> bool:
55-
return _helper.enable
56-
57-
5832
## Returns the difference between the last and current position.
5933
func get_velocity() -> Vector2:
6034
return global_position - _last_pos
@@ -74,8 +48,3 @@ func _update() -> void:
7448
var a := rope.get_point(rope.get_point_index(rope_position - 0.1))
7549
var b := rope.get_point(rope.get_point_index(rope_position + 0.1))
7650
global_rotation = (b - a).angle()
77-
78-
79-
func _set_force_update(_val: bool) -> void:
80-
if _helper.target_rope:
81-
_update()

demo/addons/ropesim/RopeHandle.gd

Lines changed: 19 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,30 @@
11
@tool
2-
extends Marker2D
2+
extends BaseRopeTool2D
33
class_name RopeHandle
44

55
## Can be used to control, animate or fixate points on a target rope.
66

77
## Gets emitted just before applying the position. This happens always during _physics_process().
88
signal on_before_update()
99

10-
## Enable or disable
11-
@export var enable: bool = true: get = get_enable, set = set_enable
12-
## Target rope node.
13-
@export_node_path("Rope") var rope_path: NodePath: set = set_rope_path
14-
## Position on the rope between 0 and 1.
15-
@export_range(0.0, 1.0) var rope_position: float = 1.0 : set = set_rope_position
10+
1611
## Whether to smoothly snap to RopeHandle's position instead of instantly.
1712
@export var smoothing: bool = false
13+
1814
## Smoothing speed
1915
@export var position_smoothing_speed: float = 0.5
20-
## If false, only affect the nearest vertex on the rope. Otherwise, affect both surrounding points when applicable.
21-
@export var precise: bool = false
16+
2217
## Determines how much the target point is allowed to move. A value of 0.0 sets the point's position
2318
## but it is still fully affected by simulation and constraining.
2419
## A value of 1.0 completely fixates the point at the handle's position and allows no further movement.
2520
@export_range(0.0, 1.0) var strength: float = 0.0 : set = set_strength
2621

27-
var _helper: RopeToolHelper
2822
var _target_idx: int = 0
2923

3024

3125
func _init() -> void:
32-
if not _helper:
33-
_helper = RopeToolHelper.new(RopeToolHelper.UPDATE_HOOK_PRE, self, "_on_pre_update")
34-
_helper.on_rope_assigned.connect(_on_rope_assigned)
35-
add_child(_helper)
36-
37-
38-
func _ready() -> void:
39-
set_rope_path(rope_path)
40-
set_enable(enable)
26+
super._init(RopeToolHelper.new(RopeToolHelper.UPDATE_HOOK_PRE, self, "_on_pre_update"))
27+
_helper.on_rope_assigned.connect(_on_rope_assigned)
4128

4229

4330
func _enter_tree() -> void:
@@ -50,6 +37,10 @@ func _exit_tree() -> void:
5037

5138
func _on_pre_update() -> void:
5239
on_before_update.emit()
40+
_update()
41+
42+
43+
func _update() -> void:
5344
var rope: Rope = _helper.target_rope
5445

5546
# The point weight is set here instead of _update_state() to ensure that handles do not
@@ -78,28 +69,13 @@ func _move_point(idx: int, from: Vector2, to: Vector2) -> void:
7869
_helper.target_rope.set_point(idx, to)
7970

8071

81-
func set_rope_path(value: NodePath) -> void:
82-
rope_path = value
83-
84-
if is_inside_tree():
85-
_helper.set_target_rope_path(rope_path, self)
86-
87-
8872
func set_enable(value: bool) -> void:
89-
if enable == value:
90-
return
73+
super.set_enable(value)
9174

92-
enable = value
93-
_helper.enable = value
94-
95-
if not enable:
96-
_restore_state(_helper.target_rope)
97-
else:
75+
if enable:
9876
_update_state(null)
99-
100-
101-
func get_enable() -> bool:
102-
return _helper.enable
77+
else:
78+
_restore_state(_helper.target_rope)
10379

10480

10581
func set_strength(value: float) -> void:
@@ -108,25 +84,10 @@ func set_strength(value: float) -> void:
10884

10985

11086
func set_rope_position(value: float) -> void:
111-
rope_position = value
87+
super.set_rope_position(value)
11288
_update_state_current_rope()
11389

11490

115-
## Determine the nearest position on the rope and use it as [member RopeHandle.rope_position].
116-
func use_nearest_position() -> void:
117-
use_nearest_position_to_point(global_position)
118-
119-
120-
## Determine the nearest position on the rope to the given point and use it as [member RopeHandle.rope_position].
121-
func use_nearest_position_to_point(point: Vector2) -> void:
122-
var rope := _helper.target_rope
123-
if rope:
124-
# TODO: Determine precise percentage, not just nearest index
125-
var idx := rope.get_nearest_point_index(point)
126-
var perc := rope.get_point_perc(idx)
127-
rope_position = perc
128-
129-
13091
func _on_rope_assigned(old: Rope) -> void:
13192
_update_state(old)
13293

@@ -137,6 +98,10 @@ func _on_rope_assigned(old: Rope) -> void:
13798
_helper.target_rope.on_point_count_changed.connect(_on_point_count_changed)
13899

139100

101+
func _on_point_count_changed() -> void:
102+
_update_state_current_rope()
103+
104+
140105
func _update_state_current_rope() -> void:
141106
_update_state(_helper.target_rope)
142107

@@ -156,7 +121,3 @@ func _update_state(old_rope: Rope) -> void:
156121
func _restore_state(rope: Rope) -> void:
157122
if rope:
158123
rope.set_point_simulation_weight(_target_idx, 1.0)
159-
160-
161-
func _on_point_count_changed() -> void:
162-
_update_state_current_rope()

0 commit comments

Comments
 (0)