diff --git a/doc/classes/CollisionObject2D.xml b/doc/classes/CollisionObject2D.xml
index 9daac969e8..6189f37c23 100644
--- a/doc/classes/CollisionObject2D.xml
+++ b/doc/classes/CollisionObject2D.xml
@@ -73,6 +73,13 @@
Returns the object's [RID].
+
+
+
+
+ Returns the [code]one_way_collision_direction[/code] of the shape owner identified by the given [param owner_id].
+
+
@@ -206,6 +213,14 @@
If [param enable] is [code]true[/code], collisions for the shape owner originating from this [CollisionObject2D] will not be reported to collided with [CollisionObject2D]s.
+
+
+
+
+
+ Sets the [code]one_way_collision_direction[/code] of the shape owner identified by the given [param owner_id] to [param p_direction].
+
+
diff --git a/doc/classes/CollisionPolygon2D.xml b/doc/classes/CollisionPolygon2D.xml
index 5dda453644..8a5bc738a7 100644
--- a/doc/classes/CollisionPolygon2D.xml
+++ b/doc/classes/CollisionPolygon2D.xml
@@ -19,6 +19,10 @@
If [code]true[/code], only edges that face up, relative to [CollisionPolygon2D]'s rotation, will collide with other objects.
[b]Note:[/b] This property has no effect if this [CollisionPolygon2D] is a child of an [Area2D] node.
+ [b]Note:[/b] The one way collision direction can be configured by setting [member one_way_collision_direction].
+
+
+ The direction used for one-way collision.
The margin used for one-way collision (in pixels). Higher values will make the shape thicker, and work better for colliders that enter the polygon at a high velocity.
diff --git a/doc/classes/CollisionShape2D.xml b/doc/classes/CollisionShape2D.xml
index 35049e4b8a..f42021d5a6 100644
--- a/doc/classes/CollisionShape2D.xml
+++ b/doc/classes/CollisionShape2D.xml
@@ -23,6 +23,10 @@
Sets whether this collision shape should only detect collision on one side (top or bottom).
[b]Note:[/b] This property has no effect if this [CollisionShape2D] is a child of an [Area2D] node.
+ [b]Note:[/b] The one way collision direction can be configured by setting [member one_way_collision_direction].
+
+
+ The direction used for one-way collision.
The margin used for one-way collision (in pixels). Higher values will make the shape thicker, and work better for colliders that enter the shape at a high velocity.
diff --git a/doc/classes/PhysicsServer2D.xml b/doc/classes/PhysicsServer2D.xml
index 75a492fb26..8f84fb8c00 100644
--- a/doc/classes/PhysicsServer2D.xml
+++ b/doc/classes/PhysicsServer2D.xml
@@ -651,8 +651,9 @@
+
- Sets the one-way collision properties of the body's shape with the given index. If [param enable] is [code]true[/code], the one-way collision direction given by the shape's local upward axis [code]body_get_shape_transform(body, shape_idx).y[/code] will be used to ignore collisions with the shape in the opposite direction, and to ensure depenetration of kinematic bodies happens in this direction.
+ Sets the one-way collision properties of the body's shape with the given index. If [param enable] is [code]true[/code], the one-way collision direction given by [param direction] in the shape's local space (that is [code]body_get_shape_transform(body, shape_idx).basis_xform(direction).normalized()[/code] in the body's local space) will be used to ignore collisions with the shape in the opposite direction, and to ensure depenetration of kinematic bodies happens in this direction.
diff --git a/doc/classes/PhysicsServer2DExtension.xml b/doc/classes/PhysicsServer2DExtension.xml
index f1a12d6da2..26769b6552 100644
--- a/doc/classes/PhysicsServer2DExtension.xml
+++ b/doc/classes/PhysicsServer2DExtension.xml
@@ -668,6 +668,7 @@
+
Overridable version of [method PhysicsServer2D.body_set_shape_as_one_way_collision].
diff --git a/misc/extension_api_validation/4.6-stable/GH-104736.txt b/misc/extension_api_validation/4.6-stable/GH-104736.txt
new file mode 100644
index 0000000000..655436d4c1
--- /dev/null
+++ b/misc/extension_api_validation/4.6-stable/GH-104736.txt
@@ -0,0 +1,6 @@
+GH-104736
+---------
+Validate extension JSON: Error: Field 'classes/PhysicsServer2D/methods/body_set_shape_as_one_way_collision/arguments': size changed value in new API, from 4 to 5.
+Validate extension JSON: Error: Field 'classes/PhysicsServer2DExtension/methods/_body_set_shape_as_one_way_collision/arguments': size changed value in new API, from 4 to 5.
+
+Argument added. Compatibility methods registered.
diff --git a/modules/godot_physics_2d/godot_body_pair_2d.cpp b/modules/godot_physics_2d/godot_body_pair_2d.cpp
index 3cb3f8ee51..c108b9fb06 100644
--- a/modules/godot_physics_2d/godot_body_pair_2d.cpp
+++ b/modules/godot_physics_2d/godot_body_pair_2d.cpp
@@ -221,7 +221,8 @@ bool GodotBodyPair2D::_test_ccd(real_t p_step, GodotBody2D *p_A, int p_shape_A,
// Check one-way collision based on motion direction.
if (p_A->get_shape(p_shape_A)->allows_one_way_collision() && p_B->is_shape_set_as_one_way_collision(p_shape_B)) {
- Vector2 direction = predicted_xform_B.columns[1].normalized();
+ Vector2 direction = predicted_xform_B.basis_xform(p_B->get_shape_one_way_collision_direction(p_shape_B)).normalized();
+
if (direction.dot(mnormal) < CMP_EPSILON) {
collided = false;
oneway_disabled = true;
@@ -318,7 +319,8 @@ bool GodotBodyPair2D::setup(real_t p_step) {
if (!prev_collided) {
if (shape_B_ptr->allows_one_way_collision() && A->is_shape_set_as_one_way_collision(shape_A)) {
- Vector2 direction = xform_A.columns[1].normalized();
+ Vector2 direction = xform_A.basis_xform(A->get_shape_one_way_collision_direction(shape_A)).normalized();
+
bool valid = false;
for (int i = 0; i < contact_count; i++) {
Contact &c = contacts[i];
@@ -336,7 +338,8 @@ bool GodotBodyPair2D::setup(real_t p_step) {
}
if (shape_A_ptr->allows_one_way_collision() && B->is_shape_set_as_one_way_collision(shape_B)) {
- Vector2 direction = xform_B.columns[1].normalized();
+ Vector2 direction = xform_B.basis_xform(B->get_shape_one_way_collision_direction(shape_B)).normalized();
+
bool valid = false;
for (int i = 0; i < contact_count; i++) {
Contact &c = contacts[i];
diff --git a/modules/godot_physics_2d/godot_collision_object_2d.cpp b/modules/godot_physics_2d/godot_collision_object_2d.cpp
index 9851cac140..e26251c571 100644
--- a/modules/godot_physics_2d/godot_collision_object_2d.cpp
+++ b/modules/godot_physics_2d/godot_collision_object_2d.cpp
@@ -41,6 +41,7 @@ void GodotCollisionObject2D::add_shape(GodotShape2D *p_shape, const Transform2D
s.disabled = p_disabled;
s.one_way_collision = false;
s.one_way_collision_margin = 0;
+ s.one_way_collision_direction = Vector2(0, 1);
shapes.push_back(s);
p_shape->add_owner(this);
diff --git a/modules/godot_physics_2d/godot_collision_object_2d.h b/modules/godot_physics_2d/godot_collision_object_2d.h
index 71d3f37cc9..ebeb056f9c 100644
--- a/modules/godot_physics_2d/godot_collision_object_2d.h
+++ b/modules/godot_physics_2d/godot_collision_object_2d.h
@@ -61,6 +61,7 @@ private:
bool disabled = false;
bool one_way_collision = false;
real_t one_way_collision_margin = 0.0;
+ Vector2 one_way_collision_direction = Vector2(0.0, 1.0);
};
Vector shapes;
@@ -139,10 +140,11 @@ public:
return shapes[p_idx].disabled;
}
- _FORCE_INLINE_ void set_shape_as_one_way_collision(int p_idx, bool p_one_way_collision, real_t p_margin) {
+ _FORCE_INLINE_ void set_shape_as_one_way_collision(int p_idx, bool p_one_way_collision, real_t p_margin, const Vector2 &p_direction) {
CRASH_BAD_INDEX(p_idx, shapes.size());
shapes.write[p_idx].one_way_collision = p_one_way_collision;
shapes.write[p_idx].one_way_collision_margin = p_margin;
+ shapes.write[p_idx].one_way_collision_direction = p_direction;
}
_FORCE_INLINE_ bool is_shape_set_as_one_way_collision(int p_idx) const {
CRASH_BAD_INDEX(p_idx, shapes.size());
@@ -154,6 +156,11 @@ public:
return shapes[p_idx].one_way_collision_margin;
}
+ Vector2 get_shape_one_way_collision_direction(int p_idx) const {
+ CRASH_BAD_INDEX(p_idx, shapes.size());
+ return shapes[p_idx].one_way_collision_direction;
+ }
+
void set_collision_mask(uint32_t p_mask) {
collision_mask = p_mask;
_shape_changed();
diff --git a/modules/godot_physics_2d/godot_physics_server_2d.cpp b/modules/godot_physics_2d/godot_physics_server_2d.cpp
index 56bc32b46f..666f40d29f 100644
--- a/modules/godot_physics_2d/godot_physics_server_2d.cpp
+++ b/modules/godot_physics_2d/godot_physics_server_2d.cpp
@@ -656,13 +656,13 @@ void GodotPhysicsServer2D::body_set_shape_disabled(RID p_body, int p_shape_idx,
body->set_shape_disabled(p_shape_idx, p_disabled);
}
-void GodotPhysicsServer2D::body_set_shape_as_one_way_collision(RID p_body, int p_shape_idx, bool p_enable, real_t p_margin) {
+void GodotPhysicsServer2D::body_set_shape_as_one_way_collision(RID p_body, int p_shape_idx, bool p_enable, real_t p_margin, const Vector2 &p_direction) {
GodotBody2D *body = body_owner.get_or_null(p_body);
ERR_FAIL_NULL(body);
ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count());
FLUSH_QUERY_CHECK(body);
- body->set_shape_as_one_way_collision(p_shape_idx, p_enable, p_margin);
+ body->set_shape_as_one_way_collision(p_shape_idx, p_enable, p_margin, p_direction);
}
void GodotPhysicsServer2D::body_set_continuous_collision_detection_mode(RID p_body, CCDMode p_mode) {
diff --git a/modules/godot_physics_2d/godot_physics_server_2d.h b/modules/godot_physics_2d/godot_physics_server_2d.h
index 2826718e54..c9130c55e9 100644
--- a/modules/godot_physics_2d/godot_physics_server_2d.h
+++ b/modules/godot_physics_2d/godot_physics_server_2d.h
@@ -185,7 +185,7 @@ public:
virtual void body_clear_shapes(RID p_body) override;
virtual void body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) override;
- virtual void body_set_shape_as_one_way_collision(RID p_body, int p_shape_idx, bool p_enable, real_t p_margin) override;
+ virtual void body_set_shape_as_one_way_collision(RID p_body, int p_shape_idx, bool p_enable, real_t p_margin, const Vector2 &p_direction) override;
virtual void body_attach_object_instance_id(RID p_body, ObjectID p_id) override;
virtual ObjectID body_get_object_instance_id(RID p_body) const override;
diff --git a/modules/godot_physics_2d/godot_space_2d.cpp b/modules/godot_physics_2d/godot_space_2d.cpp
index b3d7cea487..dcd934fa4c 100644
--- a/modules/godot_physics_2d/godot_space_2d.cpp
+++ b/modules/godot_physics_2d/godot_space_2d.cpp
@@ -637,7 +637,7 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D::
Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
if (body_shape->allows_one_way_collision() && col_obj->is_shape_set_as_one_way_collision(shape_idx)) {
- cbk.valid_dir = col_obj_shape_xform.columns[1].normalized();
+ cbk.valid_dir = col_obj_shape_xform.basis_xform(col_obj->get_shape_one_way_collision_direction(shape_idx)).normalized();
real_t owc_margin = col_obj->get_shape_one_way_collision_margin(shape_idx);
cbk.valid_depth = MAX(owc_margin, margin); //user specified, but never less than actual margin or it won't work
@@ -802,7 +802,8 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D::
//test initial overlap
if (GodotCollisionSolver2D::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), nullptr, nullptr, nullptr, 0)) {
if (body_shape->allows_one_way_collision() && col_obj->is_shape_set_as_one_way_collision(col_shape_idx)) {
- Vector2 direction = col_obj_shape_xform.columns[1].normalized();
+ Vector2 direction = col_obj_shape_xform.basis_xform(col_obj->get_shape_one_way_collision_direction(col_shape_idx)).normalized();
+
if (motion_normal.dot(direction) < 0) {
continue;
}
@@ -852,8 +853,7 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D::
cbk.amount = 0;
cbk.passed = 0;
cbk.ptr = cd;
- cbk.valid_dir = col_obj_shape_xform.columns[1].normalized();
-
+ cbk.valid_dir = col_obj_shape_xform.basis_xform(col_obj->get_shape_one_way_collision_direction(col_shape_idx)).normalized();
cbk.valid_depth = 10e20;
Vector2 sep = motion_normal; //important optimization for this to work fast enough
@@ -943,7 +943,7 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D::
Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
if (body_shape->allows_one_way_collision() && col_obj->is_shape_set_as_one_way_collision(shape_idx)) {
- rcd.valid_dir = col_obj_shape_xform.columns[1].normalized();
+ rcd.valid_dir = col_obj_shape_xform.basis_xform(col_obj->get_shape_one_way_collision_direction(shape_idx)).normalized();
real_t owc_margin = col_obj->get_shape_one_way_collision_margin(shape_idx);
rcd.valid_depth = MAX(owc_margin, margin); //user specified, but never less than actual margin or it won't work
diff --git a/scene/2d/physics/collision_object_2d.cpp b/scene/2d/physics/collision_object_2d.cpp
index 97564f491b..6db7449147 100644
--- a/scene/2d/physics/collision_object_2d.cpp
+++ b/scene/2d/physics/collision_object_2d.cpp
@@ -346,7 +346,7 @@ void CollisionObject2D::shape_owner_set_one_way_collision(uint32_t p_owner, bool
ShapeData &sd = shapes[p_owner];
sd.one_way_collision = p_enable;
for (int i = 0; i < sd.shapes.size(); i++) {
- PhysicsServer2D::get_singleton()->body_set_shape_as_one_way_collision(rid, sd.shapes[i].index, sd.one_way_collision, sd.one_way_collision_margin);
+ PhysicsServer2D::get_singleton()->body_set_shape_as_one_way_collision(rid, sd.shapes[i].index, sd.one_way_collision, sd.one_way_collision_margin, sd.one_way_collision_direction);
}
}
@@ -366,7 +366,21 @@ void CollisionObject2D::shape_owner_set_one_way_collision_margin(uint32_t p_owne
ShapeData &sd = shapes[p_owner];
sd.one_way_collision_margin = p_margin;
for (int i = 0; i < sd.shapes.size(); i++) {
- PhysicsServer2D::get_singleton()->body_set_shape_as_one_way_collision(rid, sd.shapes[i].index, sd.one_way_collision, sd.one_way_collision_margin);
+ PhysicsServer2D::get_singleton()->body_set_shape_as_one_way_collision(rid, sd.shapes[i].index, sd.one_way_collision, sd.one_way_collision_margin, sd.one_way_collision_direction);
+ }
+}
+
+void CollisionObject2D::shape_owner_set_one_way_collision_direction(uint32_t p_owner, const Vector2 &p_direction) {
+ if (area) {
+ return; //not for areas
+ }
+
+ ERR_FAIL_COND(!shapes.has(p_owner));
+
+ ShapeData &sd = shapes[p_owner];
+ sd.one_way_collision_direction = p_direction.normalized();
+ for (int i = 0; i < sd.shapes.size(); i++) {
+ PhysicsServer2D::get_singleton()->body_set_shape_as_one_way_collision(rid, sd.shapes[i].index, sd.one_way_collision, sd.one_way_collision_margin, sd.one_way_collision_direction);
}
}
@@ -376,6 +390,12 @@ real_t CollisionObject2D::get_shape_owner_one_way_collision_margin(uint32_t p_ow
return shapes[p_owner].one_way_collision_margin;
}
+Vector2 CollisionObject2D::get_shape_owner_one_way_collision_direction(uint32_t p_owner) const {
+ ERR_FAIL_COND_V(!shapes.has(p_owner), Vector2());
+
+ return shapes[p_owner].one_way_collision_direction;
+}
+
void CollisionObject2D::get_shape_owners(List *r_owners) {
for (const KeyValue &E : shapes) {
r_owners->push_back(E.key);
@@ -619,6 +639,8 @@ void CollisionObject2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_shape_owner_one_way_collision_enabled", "owner_id"), &CollisionObject2D::is_shape_owner_one_way_collision_enabled);
ClassDB::bind_method(D_METHOD("shape_owner_set_one_way_collision_margin", "owner_id", "margin"), &CollisionObject2D::shape_owner_set_one_way_collision_margin);
ClassDB::bind_method(D_METHOD("get_shape_owner_one_way_collision_margin", "owner_id"), &CollisionObject2D::get_shape_owner_one_way_collision_margin);
+ ClassDB::bind_method(D_METHOD("get_shape_owner_one_way_collision_direction", "owner_id"), &CollisionObject2D::get_shape_owner_one_way_collision_direction);
+ ClassDB::bind_method(D_METHOD("shape_owner_set_one_way_collision_direction", "owner_id", "p_direction"), &CollisionObject2D::shape_owner_set_one_way_collision_direction);
ClassDB::bind_method(D_METHOD("shape_owner_add_shape", "owner_id", "shape"), &CollisionObject2D::shape_owner_add_shape);
ClassDB::bind_method(D_METHOD("shape_owner_get_shape_count", "owner_id"), &CollisionObject2D::shape_owner_get_shape_count);
ClassDB::bind_method(D_METHOD("shape_owner_get_shape", "owner_id", "shape_id"), &CollisionObject2D::shape_owner_get_shape);
diff --git a/scene/2d/physics/collision_object_2d.h b/scene/2d/physics/collision_object_2d.h
index 3156d906ce..f4be266ebc 100644
--- a/scene/2d/physics/collision_object_2d.h
+++ b/scene/2d/physics/collision_object_2d.h
@@ -74,6 +74,7 @@ private:
bool disabled = false;
bool one_way_collision = false;
real_t one_way_collision_margin = 0.0;
+ Vector2 one_way_collision_direction = Vector2(0.0, 1.0);
};
int total_subshapes = 0;
@@ -154,6 +155,9 @@ public:
void shape_owner_set_one_way_collision_margin(uint32_t p_owner, real_t p_margin);
real_t get_shape_owner_one_way_collision_margin(uint32_t p_owner) const;
+ void shape_owner_set_one_way_collision_direction(uint32_t p_owner, const Vector2 &p_direction);
+ Vector2 get_shape_owner_one_way_collision_direction(uint32_t p_owner) const;
+
void shape_owner_add_shape(uint32_t p_owner, RequiredParam rp_shape);
int shape_owner_get_shape_count(uint32_t p_owner) const;
Ref shape_owner_get_shape(uint32_t p_owner, int p_shape) const;
diff --git a/scene/2d/physics/collision_polygon_2d.cpp b/scene/2d/physics/collision_polygon_2d.cpp
index c7468c5feb..f40c460d51 100644
--- a/scene/2d/physics/collision_polygon_2d.cpp
+++ b/scene/2d/physics/collision_polygon_2d.cpp
@@ -151,14 +151,14 @@ void CollisionPolygon2D::_notification(int p_what) {
if (one_way_collision) {
Color dcol = get_tree()->get_debug_collisions_color(); //0.9,0.2,0.2,0.4);
dcol.a = 1.0;
- Vector2 line_to(0, 20);
+ Vector2 line_to = 20.0 * one_way_collision_direction;
draw_line(Vector2(), line_to, dcol, 3);
real_t tsize = 8;
Vector pts = {
- line_to + Vector2(0, tsize),
- line_to + Vector2(Math::SQRT12 * tsize, 0),
- line_to + Vector2(-Math::SQRT12 * tsize, 0)
+ line_to + tsize * one_way_collision_direction,
+ line_to + Math::SQRT12 * tsize * one_way_collision_direction.orthogonal(),
+ line_to - Math::SQRT12 * tsize * one_way_collision_direction.orthogonal(),
};
Vector cols{ dcol, dcol, dcol };
@@ -292,6 +292,22 @@ real_t CollisionPolygon2D::get_one_way_collision_margin() const {
return one_way_collision_margin;
}
+void CollisionPolygon2D::set_one_way_collision_direction(const Vector2 &p_direction) {
+ if (p_direction == one_way_collision_direction) {
+ return;
+ }
+
+ one_way_collision_direction = p_direction.normalized();
+ queue_redraw();
+ if (collision_object) {
+ collision_object->shape_owner_set_one_way_collision_direction(owner_id, p_direction);
+ }
+}
+
+Vector2 CollisionPolygon2D::get_one_way_collision_direction() const {
+ return one_way_collision_direction;
+}
+
void CollisionPolygon2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_polygon", "polygon"), &CollisionPolygon2D::set_polygon);
ClassDB::bind_method(D_METHOD("get_polygon"), &CollisionPolygon2D::get_polygon);
@@ -304,6 +320,8 @@ void CollisionPolygon2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_one_way_collision_enabled"), &CollisionPolygon2D::is_one_way_collision_enabled);
ClassDB::bind_method(D_METHOD("set_one_way_collision_margin", "margin"), &CollisionPolygon2D::set_one_way_collision_margin);
ClassDB::bind_method(D_METHOD("get_one_way_collision_margin"), &CollisionPolygon2D::get_one_way_collision_margin);
+ ClassDB::bind_method(D_METHOD("set_one_way_collision_direction", "direction"), &CollisionPolygon2D::set_one_way_collision_direction);
+ ClassDB::bind_method(D_METHOD("get_one_way_collision_direction"), &CollisionPolygon2D::get_one_way_collision_direction);
ADD_PROPERTY(PropertyInfo(Variant::INT, "build_mode", PROPERTY_HINT_ENUM, "Solids,Segments"), "set_build_mode", "get_build_mode");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon");
@@ -312,6 +330,7 @@ void CollisionPolygon2D::_bind_methods() {
ADD_GROUP("One Way Collision", "one_way_collision");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_way_collision", PROPERTY_HINT_GROUP_ENABLE), "set_one_way_collision", "is_one_way_collision_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "one_way_collision_margin", PROPERTY_HINT_RANGE, "0,128,0.1,suffix:px"), "set_one_way_collision_margin", "get_one_way_collision_margin");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "one_way_collision_direction"), "set_one_way_collision_direction", "get_one_way_collision_direction");
BIND_ENUM_CONSTANT(BUILD_SOLIDS);
BIND_ENUM_CONSTANT(BUILD_SEGMENTS);
diff --git a/scene/2d/physics/collision_polygon_2d.h b/scene/2d/physics/collision_polygon_2d.h
index ad6282033c..702c858ae5 100644
--- a/scene/2d/physics/collision_polygon_2d.h
+++ b/scene/2d/physics/collision_polygon_2d.h
@@ -52,6 +52,7 @@ protected:
bool disabled = false;
bool one_way_collision = false;
real_t one_way_collision_margin = 1.0;
+ Vector2 one_way_collision_direction = Vector2(0.0, 1.0);
Vector> _decompose_in_convex();
@@ -87,6 +88,9 @@ public:
void set_one_way_collision_margin(real_t p_margin);
real_t get_one_way_collision_margin() const;
+ void set_one_way_collision_direction(const Vector2 &p_direction);
+ Vector2 get_one_way_collision_direction() const;
+
CollisionPolygon2D();
};
diff --git a/scene/2d/physics/collision_shape_2d.cpp b/scene/2d/physics/collision_shape_2d.cpp
index 037fb9489c..54ed91fed9 100644
--- a/scene/2d/physics/collision_shape_2d.cpp
+++ b/scene/2d/physics/collision_shape_2d.cpp
@@ -47,6 +47,7 @@ void CollisionShape2D::_update_in_shape_owner(bool p_xform_only) {
collision_object->shape_owner_set_disabled(owner_id, disabled);
collision_object->shape_owner_set_one_way_collision(owner_id, one_way_collision);
collision_object->shape_owner_set_one_way_collision_margin(owner_id, one_way_collision_margin);
+ collision_object->shape_owner_set_one_way_collision_direction(owner_id, one_way_collision_direction);
}
void CollisionShape2D::_notification(int p_what) {
@@ -114,14 +115,15 @@ void CollisionShape2D::_notification(int p_what) {
if (disabled) {
draw_col = draw_col.darkened(0.25);
}
- Vector2 line_to(0, 20);
+
+ Vector2 line_to = 20.0 * one_way_collision_direction;
draw_line(Vector2(), line_to, draw_col, 2);
real_t tsize = 8;
Vector pts{
- line_to + Vector2(0, tsize),
- line_to + Vector2(Math::SQRT12 * tsize, 0),
- line_to + Vector2(-Math::SQRT12 * tsize, 0)
+ line_to + tsize * one_way_collision_direction,
+ line_to + Math::SQRT12 * tsize * one_way_collision_direction.orthogonal(),
+ line_to - Math::SQRT12 * tsize * one_way_collision_direction.orthogonal(),
};
Vector cols{ draw_col, draw_col, draw_col };
@@ -227,6 +229,22 @@ real_t CollisionShape2D::get_one_way_collision_margin() const {
return one_way_collision_margin;
}
+void CollisionShape2D::set_one_way_collision_direction(const Vector2 &p_direction) {
+ if (p_direction == one_way_collision_direction) {
+ return;
+ }
+
+ one_way_collision_direction = p_direction.normalized();
+ if (collision_object) {
+ collision_object->shape_owner_set_one_way_collision_direction(owner_id, p_direction.normalized());
+ }
+ queue_redraw();
+}
+
+Vector2 CollisionShape2D::get_one_way_collision_direction() const {
+ return one_way_collision_direction;
+}
+
Color CollisionShape2D::_get_default_debug_color() const {
const SceneTree *st = SceneTree::get_singleton();
return st ? st->get_debug_collisions_color() : Color(0.0, 0.0, 0.0, 0.0);
@@ -283,12 +301,15 @@ void CollisionShape2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_one_way_collision_enabled"), &CollisionShape2D::is_one_way_collision_enabled);
ClassDB::bind_method(D_METHOD("set_one_way_collision_margin", "margin"), &CollisionShape2D::set_one_way_collision_margin);
ClassDB::bind_method(D_METHOD("get_one_way_collision_margin"), &CollisionShape2D::get_one_way_collision_margin);
+ ClassDB::bind_method(D_METHOD("set_one_way_collision_direction", "p_direction"), &CollisionShape2D::set_one_way_collision_direction);
+ ClassDB::bind_method(D_METHOD("get_one_way_collision_direction"), &CollisionShape2D::get_one_way_collision_direction);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, Shape2D::get_class_static()), "set_shape", "get_shape");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
ADD_GROUP("One Way Collision", "one_way_collision");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_way_collision", PROPERTY_HINT_GROUP_ENABLE), "set_one_way_collision", "is_one_way_collision_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "one_way_collision_margin", PROPERTY_HINT_RANGE, "0,128,0.1,suffix:px"), "set_one_way_collision_margin", "get_one_way_collision_margin");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "one_way_collision_direction", PROPERTY_HINT_NONE, "suffix:px"), "set_one_way_collision_direction", "get_one_way_collision_direction");
ClassDB::bind_method(D_METHOD("set_debug_color", "color"), &CollisionShape2D::set_debug_color);
ClassDB::bind_method(D_METHOD("get_debug_color"), &CollisionShape2D::get_debug_color);
diff --git a/scene/2d/physics/collision_shape_2d.h b/scene/2d/physics/collision_shape_2d.h
index 5de56c80b3..38e2838ed1 100644
--- a/scene/2d/physics/collision_shape_2d.h
+++ b/scene/2d/physics/collision_shape_2d.h
@@ -44,6 +44,7 @@ class CollisionShape2D : public Node2D {
bool disabled = false;
bool one_way_collision = false;
real_t one_way_collision_margin = 1.0;
+ Vector2 one_way_collision_direction = Vector2(0.0, 1.0);
void _shape_changed();
void _update_in_shape_owner(bool p_xform_only = false);
@@ -83,6 +84,9 @@ public:
void set_one_way_collision_margin(real_t p_margin);
real_t get_one_way_collision_margin() const;
+ void set_one_way_collision_direction(const Vector2 &p_direction);
+ Vector2 get_one_way_collision_direction() const;
+
void set_debug_color(const Color &p_color);
Color get_debug_color() const;
diff --git a/servers/physics_2d/physics_server_2d.compat.inc b/servers/physics_2d/physics_server_2d.compat.inc
new file mode 100644
index 0000000000..d6d48d6c22
--- /dev/null
+++ b/servers/physics_2d/physics_server_2d.compat.inc
@@ -0,0 +1,41 @@
+/**************************************************************************/
+/* physics_server_2d.compat.inc */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef DISABLE_DEPRECATED
+
+void PhysicsServer2D::_body_set_shape_as_one_way_collision_bind_compat_104736(RID p_body, int p_shape_idx, bool p_enable, real_t p_margin) {
+ body_set_shape_as_one_way_collision(p_body, p_shape_idx, p_enable, p_margin, Vector2(0, 1));
+}
+
+void PhysicsServer2D::_bind_compatibility_methods() {
+ ClassDB::bind_compatibility_method(D_METHOD("body_set_shape_as_one_way_collision", "body", "shape_idx", "enable", "margin"), &PhysicsServer2D::_body_set_shape_as_one_way_collision_bind_compat_104736);
+}
+
+#endif
diff --git a/servers/physics_2d/physics_server_2d.cpp b/servers/physics_2d/physics_server_2d.cpp
index 9f4870a3b3..5cd1da41f1 100644
--- a/servers/physics_2d/physics_server_2d.cpp
+++ b/servers/physics_2d/physics_server_2d.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "physics_server_2d.h"
+#include "physics_server_2d.compat.inc"
#include "core/config/project_settings.h"
#include "core/variant/typed_array.h"
@@ -704,7 +705,7 @@ void PhysicsServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("body_clear_shapes", "body"), &PhysicsServer2D::body_clear_shapes);
ClassDB::bind_method(D_METHOD("body_set_shape_disabled", "body", "shape_idx", "disabled"), &PhysicsServer2D::body_set_shape_disabled);
- ClassDB::bind_method(D_METHOD("body_set_shape_as_one_way_collision", "body", "shape_idx", "enable", "margin"), &PhysicsServer2D::body_set_shape_as_one_way_collision);
+ ClassDB::bind_method(D_METHOD("body_set_shape_as_one_way_collision", "body", "shape_idx", "enable", "margin", "direction"), &PhysicsServer2D::body_set_shape_as_one_way_collision, Vector2(0, 1));
ClassDB::bind_method(D_METHOD("body_attach_object_instance_id", "body", "id"), &PhysicsServer2D::body_attach_object_instance_id);
ClassDB::bind_method(D_METHOD("body_get_object_instance_id", "body"), &PhysicsServer2D::body_get_object_instance_id);
diff --git a/servers/physics_2d/physics_server_2d.h b/servers/physics_2d/physics_server_2d.h
index 3a9d8d4e4c..2bbc9d6449 100644
--- a/servers/physics_2d/physics_server_2d.h
+++ b/servers/physics_2d/physics_server_2d.h
@@ -221,6 +221,11 @@ class PhysicsServer2D : public Object {
protected:
static void _bind_methods();
+#ifndef DISABLE_DEPRECATED
+ void _body_set_shape_as_one_way_collision_bind_compat_104736(RID p_body, int p_shape_idx, bool p_enable, real_t p_margin);
+ static void _bind_compatibility_methods();
+#endif
+
public:
static PhysicsServer2D *get_singleton();
@@ -380,7 +385,7 @@ public:
virtual Transform2D body_get_shape_transform(RID p_body, int p_shape_idx) const = 0;
virtual void body_set_shape_disabled(RID p_body, int p_shape, bool p_disabled) = 0;
- virtual void body_set_shape_as_one_way_collision(RID p_body, int p_shape, bool p_enabled, real_t p_margin = 0) = 0;
+ virtual void body_set_shape_as_one_way_collision(RID p_body, int p_shape, bool p_enabled, real_t p_margin = 0, const Vector2 &p_direction = Vector2(0, 1)) = 0;
virtual void body_remove_shape(RID p_body, int p_shape_idx) = 0;
virtual void body_clear_shapes(RID p_body) = 0;
diff --git a/servers/physics_2d/physics_server_2d_dummy.h b/servers/physics_2d/physics_server_2d_dummy.h
index 1f0b7f71c3..92bc1c855f 100644
--- a/servers/physics_2d/physics_server_2d_dummy.h
+++ b/servers/physics_2d/physics_server_2d_dummy.h
@@ -227,7 +227,7 @@ public:
virtual Transform2D body_get_shape_transform(RID p_body, int p_shape_idx) const override { return Transform2D(); }
virtual void body_set_shape_disabled(RID p_body, int p_shape, bool p_disabled) override {}
- virtual void body_set_shape_as_one_way_collision(RID p_body, int p_shape, bool p_enabled, real_t p_margin = 0) override {}
+ virtual void body_set_shape_as_one_way_collision(RID p_body, int p_shape, bool p_enabled, real_t p_margin = 0, const Vector2 &p_direction = Vector2(0, 1)) override {}
virtual void body_remove_shape(RID p_body, int p_shape_idx) override {}
virtual void body_clear_shapes(RID p_body) override {}
diff --git a/servers/physics_2d/physics_server_2d_extension.cpp b/servers/physics_2d/physics_server_2d_extension.cpp
index ea4e229e53..6a9d23d7ac 100644
--- a/servers/physics_2d/physics_server_2d_extension.cpp
+++ b/servers/physics_2d/physics_server_2d_extension.cpp
@@ -232,7 +232,7 @@ void PhysicsServer2DExtension::_bind_methods() {
GDVIRTUAL_BIND(_body_get_shape_transform, "body", "shape_idx");
GDVIRTUAL_BIND(_body_set_shape_disabled, "body", "shape_idx", "disabled");
- GDVIRTUAL_BIND(_body_set_shape_as_one_way_collision, "body", "shape_idx", "enable", "margin");
+ GDVIRTUAL_BIND(_body_set_shape_as_one_way_collision, "body", "shape_idx", "enable", "margin", "direction");
GDVIRTUAL_BIND(_body_remove_shape, "body", "shape_idx");
GDVIRTUAL_BIND(_body_clear_shapes, "body");
@@ -348,6 +348,10 @@ void PhysicsServer2DExtension::_bind_methods() {
GDVIRTUAL_BIND(_is_flushing_queries);
GDVIRTUAL_BIND(_get_process_info, "process_info");
+
+#ifndef DISABLE_DEPRECATED
+ GDVIRTUAL_BIND_COMPAT(_body_set_shape_as_one_way_collision_bind_compat_104736, "body", "shape_idx", "enable", "margin");
+#endif
}
PhysicsServer2DExtension::PhysicsServer2DExtension() {
diff --git a/servers/physics_2d/physics_server_2d_extension.h b/servers/physics_2d/physics_server_2d_extension.h
index 506e9c5240..788b3160b3 100644
--- a/servers/physics_2d/physics_server_2d_extension.h
+++ b/servers/physics_2d/physics_server_2d_extension.h
@@ -199,6 +199,10 @@ protected:
GDVIRTUAL8R_REQUIRED(bool, _body_collide_shape, RID, int, RID, const Transform2D &, const Vector2 &, GDExtensionPtr, int, GDExtensionPtr)
+#ifndef DISABLE_DEPRECATED
+ GDVIRTUAL4_COMPAT(_body_set_shape_as_one_way_collision_bind_compat_104736, _body_set_shape_as_one_way_collision, RID, int, bool, real_t)
+#endif
+
public:
// The warning is valid, but unavoidable. If the function is not overridden it will error anyway.
@@ -305,7 +309,7 @@ public:
EXBIND2RC(Transform2D, body_get_shape_transform, RID, int)
EXBIND3(body_set_shape_disabled, RID, int, bool)
- EXBIND4(body_set_shape_as_one_way_collision, RID, int, bool, real_t)
+ EXBIND5(body_set_shape_as_one_way_collision, RID, int, bool, real_t, const Vector2 &)
EXBIND2(body_remove_shape, RID, int)
EXBIND1(body_clear_shapes, RID)
diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.h b/servers/physics_2d/physics_server_2d_wrap_mt.h
index 194d548cb8..fbea3555fa 100644
--- a/servers/physics_2d/physics_server_2d_wrap_mt.h
+++ b/servers/physics_2d/physics_server_2d_wrap_mt.h
@@ -191,7 +191,7 @@ public:
FUNC2RC(RID, body_get_shape, RID, int);
FUNC3(body_set_shape_disabled, RID, int, bool);
- FUNC4(body_set_shape_as_one_way_collision, RID, int, bool, real_t);
+ FUNC5(body_set_shape_as_one_way_collision, RID, int, bool, real_t, const Vector2 &);
FUNC2(body_remove_shape, RID, int);
FUNC1(body_clear_shapes, RID);