Skip to content

Commit a57099b

Browse files
committed
Add example on how to attach a RigidBody to a rope
Also adds a input_node_override property to RopeInteraction to allow specifying a separate node for position input and position output. This is needed when dealing with RigidBodys which use a PinJoint as target node and the RigidBody as input node overide.
1 parent 1c8799a commit a57099b

4 files changed

Lines changed: 121 additions & 7 deletions

File tree

demo/addons/ropesim/RopeInteraction.gd

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,14 @@ class_name RopeInteraction
44

55
## Handles mutual interaction of a target node with a rope.
66
## Useful for rope grabbing or pulling mechanics where an object should be able to affect the rope
7-
## while also being constrained by it.
8-
## Uses [RopeHandle] and [RopeAnchor] internally.
7+
## while also being constrained by it.[br]
8+
## [br]
9+
## Internally, a [RopeHandle] and a [RopeAnchor] is used to update the rope and retrieve the new
10+
## position afterwards.[br]
11+
## It essentially works by running the following three steps every frame:[br]
12+
## 1. Set [RopeHandle] position to target node position.[br]
13+
## 2. Wait for rope simulation to be finished.[br]
14+
## 3. Set target node position to [RopeAnchor] position.
915

1016
## Emitted when the target node should be moved and [member RopeInteraction.position_update_mode] is [enum RopeInteraction.Signal].
1117
signal on_movement_request(target: Node2D, anchor: RopeAnchor)
@@ -27,14 +33,17 @@ enum PositionUpdateMode {
2733
## Enable or disable.
2834
@export var enable: bool = true : set = set_enable
2935

30-
## Determines how the position of the target node is updated.
36+
## Determines how the position of the target node should be updated.
3137
@export var position_update_mode: PositionUpdateMode = PositionUpdateMode.EmitSignal
3238

3339
## Target node that should be attached to the rope.
3440
@export var target_node: Node2D
3541

42+
## (Optional) Use the given node instead of the target node to update the rope point's position.
43+
## If set, the target node will only be snapped to the rope, but it will not affect it.
44+
@export var input_node_override: Node2D
45+
3646
## Target rope.
37-
# @export_node_path("Rope") var rope: NodePath : set = set_rope
3847
@export var rope: Rope : set = set_rope
3948

4049
## Position on the rope between 0 and 1.
@@ -61,9 +70,13 @@ func _init() -> void:
6170
func _enter_tree() -> void:
6271
set_rope(rope)
6372

73+
if not target_node:
74+
push_warning("RopeInteraction: No target node selected -> Disabling")
75+
enable = false
76+
6477

6578
func _on_before_update() -> void:
66-
_handle.global_position = target_node.global_position
79+
_handle.global_position = (input_node_override if input_node_override else target_node).global_position
6780

6881

6982
func _on_after_update() -> void:

demo/rope_examples/benchmark.tscn

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ offset_left = 449.0
1010
offset_top = -1.0
1111
offset_right = 509.0
1212
offset_bottom = 22.0
13-
text = "192 Ropes
14-
2.82 ms"
13+
text = "384 Ropes
14+
3.99 ms"
1515
script = ExtResource("2_ms00a")
1616

1717
[node name="Node2D9" type="Node2D" parent="."]
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
[gd_scene load_steps=5 format=3 uid="uid://gex7loccj42u"]
2+
3+
[ext_resource type="PackedScene" uid="uid://beuu34gtk2nhm" path="res://rope_examples/scripts/rope_with_rigidbody.tscn" id="1_aij5x"]
4+
[ext_resource type="Texture2D" uid="uid://criwv6nuivcxy" path="res://rope_examples/icon.svg" id="3_xivx8"]
5+
[ext_resource type="Script" path="res://rope_examples/scripts/character_body_2d.gd" id="5_du4tb"]
6+
7+
[sub_resource type="RectangleShape2D" id="RectangleShape2D_6gqpg"]
8+
size = Vector2(64, 64)
9+
10+
[node name="Node2D" type="Node2D"]
11+
12+
[node name="rope_with_body" parent="." instance=ExtResource("1_aij5x")]
13+
14+
[node name="rope_with_body2" parent="." instance=ExtResource("1_aij5x")]
15+
position = Vector2(498, 0)
16+
17+
[node name="rope_with_body3" parent="." instance=ExtResource("1_aij5x")]
18+
position = Vector2(589, 0)
19+
20+
[node name="Player" type="CharacterBody2D" parent="."]
21+
process_physics_priority = -100
22+
position = Vector2(227, 253)
23+
collision_mask = 0
24+
motion_mode = 1
25+
script = ExtResource("5_du4tb")
26+
metadata/_edit_group_ = true
27+
28+
[node name="CollisionShape2D" type="CollisionShape2D" parent="Player"]
29+
shape = SubResource("RectangleShape2D_6gqpg")
30+
31+
[node name="Icon" type="Sprite2D" parent="Player"]
32+
scale = Vector2(0.5, 0.5)
33+
texture = ExtResource("3_xivx8")
34+
35+
[node name="Label2" type="Label" parent="Player"]
36+
offset_left = -46.0
37+
offset_top = 36.0
38+
offset_right = 42.0
39+
offset_bottom = 59.0
40+
text = "WSAD"
41+
horizontal_alignment = 1
42+
43+
[node name="Label" type="Label" parent="."]
44+
offset_left = 10.0
45+
offset_top = 481.0
46+
offset_right = 852.0
47+
offset_bottom = 504.0
48+
text = "Basic example on how to attach a RigidBody to a rope and enabling corresponding physics reactions.
49+
50+
A PinJoint2D fixates the RigidBody to the rope.
51+
A RopeInteraction uses the RigidBody to control the rope and updates the PinJoint2D respectively."
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
[gd_scene load_steps=6 format=3 uid="uid://beuu34gtk2nhm"]
2+
3+
[ext_resource type="Script" path="res://addons/ropesim/Rope.gd" id="1_4r73y"]
4+
[ext_resource type="Script" path="res://addons/ropesim/RopeInteraction.gd" id="2_1yts0"]
5+
[ext_resource type="Texture2D" uid="uid://criwv6nuivcxy" path="res://rope_examples/icon.svg" id="3_uwcl5"]
6+
7+
[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_nwm6u"]
8+
9+
[sub_resource type="RectangleShape2D" id="RectangleShape2D_3g7xa"]
10+
size = Vector2(64, 64)
11+
12+
[node name="rope_with_body" type="Node2D"]
13+
position = Vector2(408, 0)
14+
15+
[node name="Rope" type="Node2D" parent="."]
16+
script = ExtResource("1_4r73y")
17+
num_segments = 15
18+
rope_length = 250.0
19+
gravity = 75.0
20+
num_constraint_iterations = 20
21+
22+
[node name="RopeInteraction" type="Node" parent="." node_paths=PackedStringArray("target_node", "input_node_override", "rope")]
23+
script = ExtResource("2_1yts0")
24+
position_update_mode = 0
25+
target_node = NodePath("../pin_point")
26+
input_node_override = NodePath("../hanging_rigidbody")
27+
rope = NodePath("../Rope")
28+
29+
[node name="pin_point" type="CharacterBody2D" parent="."]
30+
position = Vector2(0, 250)
31+
collision_layer = 0
32+
collision_mask = 0
33+
motion_mode = 1
34+
35+
[node name="PinJoint2D" type="PinJoint2D" parent="pin_point"]
36+
node_a = NodePath("../../hanging_rigidbody")
37+
node_b = NodePath("..")
38+
39+
[node name="hanging_rigidbody" type="RigidBody2D" parent="."]
40+
position = Vector2(0, 250)
41+
mass = 5.0
42+
physics_material_override = SubResource("PhysicsMaterial_nwm6u")
43+
metadata/_edit_group_ = true
44+
45+
[node name="CollisionShape2D" type="CollisionShape2D" parent="hanging_rigidbody"]
46+
shape = SubResource("RectangleShape2D_3g7xa")
47+
48+
[node name="Icon" type="Sprite2D" parent="hanging_rigidbody"]
49+
scale = Vector2(0.5, 0.5)
50+
texture = ExtResource("3_uwcl5")

0 commit comments

Comments
 (0)