Skip to content

Commit

Permalink
Add settings related to max_endpoint_distance
Browse files Browse the repository at this point in the history
Adds properties to determine in which direction the rope should be
constrained when exceeding max_endpoint_distance.
  • Loading branch information
mphe committed Aug 18, 2024
1 parent b6874d4 commit feb4556
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 40 deletions.
12 changes: 12 additions & 0 deletions demo/addons/ropesim/Rope.gd
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@ signal on_point_count_changed()
## Fixed points in between are not taken into account.
@export var max_endpoint_distance: float = -1

## If [member Rope.max_endpoint_distance] is set, contract the rope towards the first point.
## If [member Rope.resolve_to_end] is set as well or if neither is set, the rope gets contracted
## towards the center.
## [member Rope.fixate_begin] will always take precedence over this property.
@export var resolve_to_begin: bool = false

## If [member Rope.max_endpoint_distance] is set, contract the rope towards the last point.
## If [member Rope.resolve_to_begin] is set as well or if neither is set, the rope gets contracted
## towards the center.
## [member Rope.fixate_begin] will always take precedence over this property.
@export var resolve_to_end: bool = false

## (Optional) Allows to distribute the length of rope segment in a non-uniform manner.
## Useful when certain parts of the rope should be more detailed than the rest.
## For example, if it is known that most movement happens at the beginning of the rope, a curve with
Expand Down
2 changes: 1 addition & 1 deletion demo/project.godot
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ config_version=5
[application]

config/name="ropesim example"
config/features=PackedStringArray("4.2")
config/features=PackedStringArray("4.3")
config/icon="res://rope_examples/icon.svg"

[debug]
Expand Down
133 changes: 110 additions & 23 deletions demo/rope_examples/rope_properties.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,15 @@ metadata/_edit_group_ = true
[node name="RopeHandle" type="Marker2D" parent="Rope15"]
position = Vector2(-106.181, 0)
script = ExtResource("3_mb3ny")
strength = 1.0
rope_path = NodePath("..")
rope_position = 0.0
strength = 1.0

[node name="RopeHandle2" type="Marker2D" parent="Rope15"]
position = Vector2(93.8187, 0)
script = ExtResource("3_mb3ny")
rope_path = NodePath("..")
strength = 1.0
rope_path = NodePath("..")

[node name="Rope16" type="Node2D" parent="."]
position = Vector2(365, 1438)
Expand All @@ -85,15 +85,15 @@ metadata/_edit_group_ = true
[node name="RopeHandle" type="Marker2D" parent="Rope16"]
position = Vector2(-106.181, 0)
script = ExtResource("3_mb3ny")
strength = 1.0
rope_path = NodePath("..")
rope_position = 0.0
strength = 1.0

[node name="RopeHandle2" type="Marker2D" parent="Rope16"]
position = Vector2(93.8187, 0)
script = ExtResource("3_mb3ny")
rope_path = NodePath("..")
strength = 1.0
rope_path = NodePath("..")

[node name="Rope17" type="Node2D" parent="."]
position = Vector2(583, 1438)
Expand All @@ -106,15 +106,15 @@ metadata/_edit_group_ = true
[node name="RopeHandle" type="Marker2D" parent="Rope17"]
position = Vector2(-106.181, 0)
script = ExtResource("3_mb3ny")
strength = 1.0
rope_path = NodePath("..")
rope_position = 0.0
strength = 1.0

[node name="RopeHandle2" type="Marker2D" parent="Rope17"]
position = Vector2(93.819, 0)
script = ExtResource("3_mb3ny")
rope_path = NodePath("..")
strength = 1.0
rope_path = NodePath("..")

[node name="Rope18" type="Node2D" parent="."]
position = Vector2(807, 1438)
Expand All @@ -128,18 +128,18 @@ metadata/_edit_group_ = true
[node name="RopeHandle" type="Marker2D" parent="Rope18"]
position = Vector2(-106.181, 0)
script = ExtResource("3_mb3ny")
strength = 1.0
rope_path = NodePath("..")
rope_position = 0.0
strength = 1.0

[node name="RopeHandle2" type="Marker2D" parent="Rope18"]
position = Vector2(93.819, 0)
script = ExtResource("3_mb3ny")
rope_path = NodePath("..")
strength = 1.0
rope_path = NodePath("..")

[node name="Node2D2" type="Node2D" parent="."]
position = Vector2(180.7, 124.476)
position = Vector2(146.001, 146.237)

[node name="Rope3" type="Node2D" parent="Node2D2"]
position = Vector2(-88.3748, -22.2188)
Expand Down Expand Up @@ -414,13 +414,20 @@ text = "max_endpoint_distance provides an easy way to constraint the rope length

[node name="Label22" type="Label" parent="."]
offset_left = 1267.0
offset_top = 1328.0
offset_top = 1698.0
offset_right = 2007.0
offset_bottom = 1351.0
offset_bottom = 1747.0
text = "max_endpoint_distance only considers the distance between both endpoints.
Does not consider the actual rope length.
"

[node name="Label28" type="Label" parent="."]
offset_left = 1267.0
offset_top = 1364.0
offset_right = 2067.0
offset_bottom = 1387.0
text = "It can be specified how to contract the rope when exceeding max_endpoint_distance."

[node name="Label20" type="Label" parent="."]
offset_left = 1236.0
offset_top = 956.0
Expand Down Expand Up @@ -460,7 +467,7 @@ theme_override_styles/separator = SubResource("StyleBoxFlat_f4u3w")
offset_left = 1105.0
offset_top = 854.0
offset_right = 1309.0
offset_bottom = 1771.0
offset_bottom = 2129.0
theme_override_styles/separator = SubResource("StyleBoxFlat_f4u3w")

[node name="Rope" type="Node2D" parent="."]
Expand All @@ -470,8 +477,8 @@ script = ExtResource("4_rnvio")
[node name="RopeHandle" type="Marker2D" parent="Rope"]
position = Vector2(136, 257)
script = ExtResource("3_mb3ny")
rope_path = NodePath("..")
strength = 1.0
rope_path = NodePath("..")

[node name="Rope2" type="Node2D" parent="."]
position = Vector2(1697, 992)
Expand All @@ -481,54 +488,134 @@ max_endpoint_distance = 100.0
[node name="RopeHandle" type="Marker2D" parent="Rope2"]
position = Vector2(136, 257)
script = ExtResource("3_mb3ny")
rope_path = NodePath("..")
strength = 1.0
rope_path = NodePath("..")

[node name="Label23" type="Label" parent="."]
offset_left = 1236.0
offset_top = 1406.0
offset_top = 1776.0
offset_right = 1460.0
offset_bottom = 1429.0
offset_bottom = 1799.0
text = "max_endpoint_distance = -1"

[node name="Label25" type="Label" parent="."]
offset_left = 1651.0
offset_top = 1497.0
offset_right = 1875.0
offset_bottom = 1520.0
text = "resolve_to_begin = true"

[node name="Label27" type="Label" parent="."]
offset_left = 1650.0
offset_top = 1422.0
offset_right = 1874.0
offset_bottom = 1445.0
text = "default (center)"

[node name="Label26" type="Label" parent="."]
offset_left = 1649.0
offset_top = 1563.0
offset_right = 1873.0
offset_bottom = 1586.0
text = "resolve_to_end = true"

[node name="Label24" type="Label" parent="."]
offset_left = 1609.0
offset_top = 1406.0
offset_top = 1776.0
offset_right = 1837.0
offset_bottom = 1429.0
offset_bottom = 1799.0
text = "max_endpoint_distance = 100"

[node name="Rope4" type="Node2D" parent="."]
position = Vector2(1697, 1442)
position = Vector2(1697, 1812)
script = ExtResource("4_rnvio")
max_endpoint_distance = 100.0

[node name="RopeHandle" type="Marker2D" parent="Rope4"]
position = Vector2(250, 56)
script = ExtResource("3_mb3ny")
strength = 1.0
rope_path = NodePath("..")
rope_position = 0.622
strength = 1.0

[node name="RopeHandle2" type="Marker2D" parent="Rope4"]
position = Vector2(139, 249)
script = ExtResource("3_mb3ny")
rope_path = NodePath("..")
strength = 1.0
rope_path = NodePath("..")

[node name="Rope5" type="Node2D" parent="."]
position = Vector2(1318, 1446)
position = Vector2(1318, 1816)
script = ExtResource("4_rnvio")

[node name="RopeHandle" type="Marker2D" parent="Rope5"]
position = Vector2(250, 56)
script = ExtResource("3_mb3ny")
strength = 1.0
rope_path = NodePath("..")
rope_position = 0.622
strength = 1.0

[node name="RopeHandle2" type="Marker2D" parent="Rope5"]
position = Vector2(139, 249)
script = ExtResource("3_mb3ny")
strength = 1.0
rope_path = NodePath("..")

[node name="Rope6" type="Node2D" parent="."]
position = Vector2(1288, 1431)
script = ExtResource("4_rnvio")
max_endpoint_distance = 150.0
resolve_to_begin = true
fixate_begin = false

[node name="RopeHandle" type="Marker2D" parent="Rope6"]
position = Vector2(-7, 79)
script = ExtResource("3_mb3ny")
strength = 1.0
rope_path = NodePath("..")
rope_position = 0.0

[node name="RopeHandle2" type="Marker2D" parent="Rope6"]
position = Vector2(323, 78)
script = ExtResource("3_mb3ny")
strength = 1.0
rope_path = NodePath("..")

[node name="Rope8" type="Node2D" parent="."]
position = Vector2(1288, 1336)
script = ExtResource("4_rnvio")
max_endpoint_distance = 150.0
fixate_begin = false

[node name="RopeHandle" type="Marker2D" parent="Rope8"]
position = Vector2(-7, 99)
script = ExtResource("3_mb3ny")
strength = 1.0
rope_path = NodePath("..")
rope_position = 0.0

[node name="RopeHandle2" type="Marker2D" parent="Rope8"]
position = Vector2(323, 98)
script = ExtResource("3_mb3ny")
strength = 1.0
rope_path = NodePath("..")

[node name="Rope7" type="Node2D" parent="."]
position = Vector2(1288, 1496)
script = ExtResource("4_rnvio")
max_endpoint_distance = 150.0
resolve_to_end = true
fixate_begin = false

[node name="RopeHandle" type="Marker2D" parent="Rope7"]
position = Vector2(-7, 83)
script = ExtResource("3_mb3ny")
strength = 1.0
rope_path = NodePath("..")
rope_position = 0.0

[node name="RopeHandle2" type="Marker2D" parent="Rope7"]
position = Vector2(323, 82)
script = ExtResource("3_mb3ny")
strength = 1.0
rope_path = NodePath("..")
48 changes: 32 additions & 16 deletions src/NativeRopeContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ void NativeRopeContext::load_context(Node2D* rope)
seg_lengths = rope->call("get_segment_lengths");
simulation_weights = rope->get("_simulation_weights");
fixate_begin = rope->get("fixate_begin");
resolve_to_begin = rope->get("resolve_to_begin");
resolve_to_end = rope->get("resolve_to_end");
}

void NativeRopeContext::simulate(double delta)
Expand Down Expand Up @@ -173,29 +175,43 @@ static void constraint_segment(Vector2* point_a, Vector2* point_b, float weight_
void NativeRopeContext::_constraint()
{
const bool use_euclid_constraint = max_endpoint_distance > 0;
Vector2* first_point;
Vector2* last_point;
float euclid_constraint_first_weight;
float max_stretch_length_sqr;

if (use_euclid_constraint)
{
first_point = &points[0];
last_point = &points[(int)points.size() - 1];
euclid_constraint_first_weight = fixate_begin ? 0.0 : 1.0;
max_stretch_length_sqr = max_endpoint_distance * max_endpoint_distance;
}
Vector2* const first_point = &points[0];
Vector2* const last_point = &points[(int)points.size() - 1];
const float max_stretch_length_sqr = max_endpoint_distance * max_endpoint_distance;
const float rope_length_sqr = first_point->distance_squared_to(*last_point);

for (int _ = 0; _ < num_constraint_iterations; ++_)
{
if (use_euclid_constraint)
if (rope_length_sqr > max_stretch_length_sqr)
{
const float rope_length_sqr = first_point->distance_squared_to(*last_point);

if (rope_length_sqr > max_stretch_length_sqr)
constraint_segment(first_point, last_point, euclid_constraint_first_weight, 1.0, max_endpoint_distance);
float weight_a;
float weight_b;

// Always has priority
if (fixate_begin)
{
weight_a = 0.0;
weight_b = 1.0;
}
else if (resolve_to_begin == resolve_to_end)
{
weight_a = 1.0;
weight_b = 1.0;
}
else
{
weight_a = resolve_to_begin ? 0.0 : 1.0;
weight_b = resolve_to_end ? 0.0 : 1.0;
}

constraint_segment(first_point, last_point, weight_a, weight_b, max_endpoint_distance);
}
}


for (int _ = 0; _ < num_constraint_iterations; ++_)
{
for (int i = 0; i < points.size() - 1; ++i)
constraint_segment(&points[i], &points[i + 1], simulation_weights[i], simulation_weights[i + 1], seg_lengths[i]);
}
Expand Down
2 changes: 2 additions & 0 deletions src/NativeRopeContext.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ namespace godot
int num_constraint_iterations;
Ref<Curve> damping_curve;
bool fixate_begin;
bool resolve_to_begin;
bool resolve_to_end;
};
}

Expand Down

0 comments on commit feb4556

Please sign in to comment.