Merge pull request #104736 from szunami/master

Add one-way collision direction for CollisionShape2Ds
This commit is contained in:
Thaddeus Crews 2026-02-10 08:29:38 -06:00
commit c44b01cd1f
No known key found for this signature in database
GPG key ID: 8C6E5FEB5FC03CCC
25 changed files with 200 additions and 29 deletions

View file

@ -73,6 +73,13 @@
Returns the object's [RID].
</description>
</method>
<method name="get_shape_owner_one_way_collision_direction" qualifiers="const">
<return type="Vector2" />
<param index="0" name="owner_id" type="int" />
<description>
Returns the [code]one_way_collision_direction[/code] of the shape owner identified by the given [param owner_id].
</description>
</method>
<method name="get_shape_owner_one_way_collision_margin" qualifiers="const">
<return type="float" />
<param index="0" name="owner_id" type="int" />
@ -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.
</description>
</method>
<method name="shape_owner_set_one_way_collision_direction">
<return type="void" />
<param index="0" name="owner_id" type="int" />
<param index="1" name="p_direction" type="Vector2" />
<description>
Sets the [code]one_way_collision_direction[/code] of the shape owner identified by the given [param owner_id] to [param p_direction].
</description>
</method>
<method name="shape_owner_set_one_way_collision_margin">
<return type="void" />
<param index="0" name="owner_id" type="int" />

View file

@ -19,6 +19,10 @@
<member name="one_way_collision" type="bool" setter="set_one_way_collision" getter="is_one_way_collision_enabled" default="false">
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].
</member>
<member name="one_way_collision_direction" type="Vector2" setter="set_one_way_collision_direction" getter="get_one_way_collision_direction" default="Vector2(0, 1)">
The direction used for one-way collision.
</member>
<member name="one_way_collision_margin" type="float" setter="set_one_way_collision_margin" getter="get_one_way_collision_margin" default="1.0">
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.

View file

@ -23,6 +23,10 @@
<member name="one_way_collision" type="bool" setter="set_one_way_collision" getter="is_one_way_collision_enabled" default="false">
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].
</member>
<member name="one_way_collision_direction" type="Vector2" setter="set_one_way_collision_direction" getter="get_one_way_collision_direction" default="Vector2(0, 1)">
The direction used for one-way collision.
</member>
<member name="one_way_collision_margin" type="float" setter="set_one_way_collision_margin" getter="get_one_way_collision_margin" default="1.0">
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.

View file

@ -651,8 +651,9 @@
<param index="1" name="shape_idx" type="int" />
<param index="2" name="enable" type="bool" />
<param index="3" name="margin" type="float" />
<param index="4" name="direction" type="Vector2" default="Vector2(0, 1)" />
<description>
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.
</description>
</method>
<method name="body_set_shape_disabled">

View file

@ -668,6 +668,7 @@
<param index="1" name="shape_idx" type="int" />
<param index="2" name="enable" type="bool" />
<param index="3" name="margin" type="float" />
<param index="4" name="direction" type="Vector2" />
<description>
Overridable version of [method PhysicsServer2D.body_set_shape_as_one_way_collision].
</description>

View file

@ -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.

View file

@ -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];

View file

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

View file

@ -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<Shape> 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();

View file

@ -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) {

View file

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

View file

@ -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

View file

@ -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<uint32_t> *r_owners) {
for (const KeyValue<uint32_t, ShapeData> &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);

View file

@ -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<Shape2D> rp_shape);
int shape_owner_get_shape_count(uint32_t p_owner) const;
Ref<Shape2D> shape_owner_get_shape(uint32_t p_owner, int p_shape) const;

View file

@ -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<Vector2> 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<Color> 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);

View file

@ -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<Vector<Vector2>> _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();
};

View file

@ -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<Vector2> 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<Color> 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);

View file

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

View file

@ -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

View file

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

View file

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

View file

@ -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 {}

View file

@ -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() {

View file

@ -199,6 +199,10 @@ protected:
GDVIRTUAL8R_REQUIRED(bool, _body_collide_shape, RID, int, RID, const Transform2D &, const Vector2 &, GDExtensionPtr<Vector2>, int, GDExtensionPtr<int>)
#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)

View file

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