Skip to content

Commit 46a8615

Browse files
committed
Various fixes and improvements
- Fix NaN when two handles are at the some position - Add option to Ropesim menu to reset the rope - Add function to RopeHandle to use the nearest rope position to a given point - Fix RopeHandle not updating its target index when the rope segment count changes - Make RopeHandle update its strength continously to prevent two handles overwriting each other's strength if they share the same rope position.
1 parent f33c4aa commit 46a8615

4 files changed

Lines changed: 45 additions & 11 deletions

File tree

demo/addons/ropesim/RopeHandle.gd

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ func _on_pre_update() -> void:
5252
on_before_update.emit()
5353
var rope: Rope = _helper.target_rope
5454

55+
# The point weight is set here instead of _update_state() to ensure that handles do not
56+
# overwrite each other's strength values if they coincidentally target the same point index.
57+
rope.set_point_simulation_weight(_target_idx, 1.0 - strength)
58+
5559
# Only use this method if this is not the last point.
5660
if precise and _target_idx < rope.get_num_points() - 1:
5761
# TODO: Consider creating a corresponding function in Rope.gd for universal access, e.g. set_point_interpolated().
@@ -99,7 +103,7 @@ func get_enable() -> bool:
99103

100104

101105
func set_strength(value: float) -> void:
102-
strength = value
106+
strength = clampf(value, 0.0, 1.0)
103107
_update_state_current_rope()
104108

105109

@@ -108,9 +112,30 @@ func set_rope_position(value: float) -> void:
108112
_update_state_current_rope()
109113

110114

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+
111130
func _on_rope_assigned(old: Rope) -> void:
112131
_update_state(old)
113132

133+
if old:
134+
old.on_point_count_changed.disconnect(_on_point_count_changed)
135+
136+
if _helper.target_rope:
137+
_helper.target_rope.on_point_count_changed.connect(_on_point_count_changed)
138+
114139

115140
func _update_state_current_rope() -> void:
116141
_update_state(_helper.target_rope)
@@ -124,14 +149,14 @@ func _update_state(old_rope: Rope) -> void:
124149

125150
var rope := _helper.target_rope
126151

127-
# Compute and apply new state
128152
if rope:
129153
_target_idx = rope.get_point_index(rope_position)
130-
# TODO: Maybe set this value in _on_pre_update() so if it gets overwritten by another
131-
# handle, it will be automatically restored when the other handle targets a different position again.
132-
rope.set_point_simulation_weight(_target_idx, 1.0 - clampf(strength, 0.0, 1.0))
133154

134155

135156
func _restore_state(rope: Rope) -> void:
136157
if rope:
137158
rope.set_point_simulation_weight(_target_idx, 1.0)
159+
160+
161+
func _on_point_count_changed() -> void:
162+
_update_state_current_rope()

demo/addons/ropesim/RopeInteraction.gd

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,8 @@ func _on_after_update() -> void:
9494

9595
## Determine the nearest position on the rope to the target node and use it as [member RopeInteraction.rope_position].
9696
func use_nearest_position() -> void:
97-
# TODO: Determine precise percentage, not just nearest index
98-
var idx := rope.get_nearest_point_index(target_node.global_position)
99-
var perc := rope.get_point_perc(idx)
100-
rope_position = perc
97+
_handle.use_nearest_position_to_point(target_node.global_position)
98+
rope_position = _handle.rope_position
10199

102100

103101
## Snaps the target node to the current position on the rope.

demo/addons/ropesim/plugin.gd

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
extends EditorPlugin
33

44
const MENU_INDEX_UPDATE_IN_EDITOR = 0
5+
const MENU_INDEX_RESET_ROPE = 1
56

67
var _menu_toolbox: HBoxContainer
78
var _menu_popup: PopupMenu
9+
var _edited_object: Node
10+
811

912
func _enter_tree() -> void:
1013
_build_gui()
@@ -28,8 +31,10 @@ func _handles(object: Object) -> bool:
2831
)
2932

3033

31-
func _edit(_object: Object) -> void:
34+
func _edit(object: Object) -> void:
35+
_edited_object = object
3236
_menu_toolbox.show()
37+
_menu_popup.set_item_disabled(MENU_INDEX_RESET_ROPE, not object is Rope)
3338

3439

3540
func _build_gui() -> void:
@@ -43,6 +48,8 @@ func _build_gui() -> void:
4348
_menu_popup = menu_button.get_popup()
4449
_menu_popup.add_check_item("Preview in Editor")
4550
_menu_popup.set_item_checked(MENU_INDEX_UPDATE_IN_EDITOR, NativeRopeServer.update_in_editor)
51+
_menu_popup.add_item("Reset Rope")
52+
_menu_popup.set_item_tooltip(MENU_INDEX_RESET_ROPE, "Reset the selected rope into its base position.")
4653
_menu_popup.connect("id_pressed", self._menu_item_clicked)
4754

4855

@@ -52,6 +59,10 @@ func _menu_item_clicked(idx: int) -> void:
5259
var value := not _menu_popup.is_item_checked(idx)
5360
_menu_popup.set_item_checked(MENU_INDEX_UPDATE_IN_EDITOR, value)
5461
NativeRopeServer.update_in_editor = value
62+
MENU_INDEX_RESET_ROPE:
63+
var rope := _edited_object as Rope
64+
if rope:
65+
rope.reset()
5566

5667

5768
func _free_gui() -> void:

src/NativeRopeContext.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ static void constraint_segment(Vector2* point_a, Vector2* point_b, float weight_
157157
const Vector2 diff = *point_b - *point_a;
158158
const float distance = diff.length();
159159
const float error = (seg_length - distance) * 0.5f;
160-
const Vector2 dir = error * (diff / distance);
160+
const Vector2 dir = error * (diff / Math::max(distance, 0.001f));
161161

162162
// If one point has a weight < 1.0, the other point must compensate the difference in
163163
// relation to its own weight.

0 commit comments

Comments
 (0)