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);