diff --git a/doc/classes/Area2D.xml b/doc/classes/Area2D.xml index 6fa8e4ae9f43..a1a41d014192 100644 --- a/doc/classes/Area2D.xml +++ b/doc/classes/Area2D.xml @@ -90,6 +90,9 @@ The distance at which the gravity strength is equal to [member gravity]. For example, on a planet 100 pixels in radius with a surface gravity of 4.0 px/s², set the [member gravity] to 4.0 and the unit distance to 100.0. The gravity will have falloff according to the inverse square law, so in the example, at 200 pixels from the center the gravity will be 1.0 px/s² (twice the distance, 1/4th the gravity), at 50 pixels it will be 16.0 px/s² (half the distance, 4x the gravity), and so on. The above is true only when the unit distance is a positive number. When this is set to 0.0, the gravity will be constant regardless of distance. + + If [code]true[/code], gravity is transformed using the area's transform. In other words, rotating the area with this setting active will also rotate the gravity vector. + Override mode for gravity calculations within this area. See [enum SpaceOverride] for possible values. diff --git a/doc/classes/Area3D.xml b/doc/classes/Area3D.xml index 89b3f843af3f..65286a21936d 100644 --- a/doc/classes/Area3D.xml +++ b/doc/classes/Area3D.xml @@ -90,6 +90,9 @@ The distance at which the gravity strength is equal to [member gravity]. For example, on a planet 100 meters in radius with a surface gravity of 4.0 m/s², set the [member gravity] to 4.0 and the unit distance to 100.0. The gravity will have falloff according to the inverse square law, so in the example, at 200 meters from the center the gravity will be 1.0 m/s² (twice the distance, 1/4th the gravity), at 50 meters it will be 16.0 m/s² (half the distance, 4x the gravity), and so on. The above is true only when the unit distance is a positive number. When this is set to 0.0, the gravity will be constant regardless of distance. + + If [code]true[/code], gravity is transformed using the area's transform. In other words, rotating the area with this setting active will also rotate the gravity vector. + Override mode for gravity calculations within this area. See [enum SpaceOverride] for possible values. diff --git a/doc/classes/PhysicsServer2D.xml b/doc/classes/PhysicsServer2D.xml index 39d18a9e359a..39a8616b1a5f 100644 --- a/doc/classes/PhysicsServer2D.xml +++ b/doc/classes/PhysicsServer2D.xml @@ -1050,6 +1050,9 @@ Constant to set/get the priority (order of processing) of an area. The default value of this parameter is [code]0[/code]. + + Constant to set/get whether the area transform is applied to the gravity vector. + This area does not affect gravity/damp. These are generally areas that exist only to detect collisions, and objects entering or exiting them. diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml index a21be3f66835..aac955a78b51 100644 --- a/doc/classes/PhysicsServer3D.xml +++ b/doc/classes/PhysicsServer3D.xml @@ -1361,6 +1361,9 @@ Constant to set/get the exponential rate at which wind force decreases with distance from its origin. + + Constant to set/get whether the area transform is applied to the gravity vector. + This area does not affect gravity/damp. These are generally areas that exist only to detect collisions, and objects entering or exiting them. diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp index 2ea7a8d6aef5..55b3ac75d49d 100644 --- a/scene/2d/area_2d.cpp +++ b/scene/2d/area_2d.cpp @@ -51,6 +51,15 @@ bool Area2D::is_gravity_a_point() const { return gravity_is_point; } +void Area2D::set_gravity_apply_transform(bool p_enabled) { + gravity_apply_transform = p_enabled; + PhysicsServer2D::get_singleton()->area_set_param(get_rid(), PhysicsServer2D::AREA_PARAM_GRAVITY_APPLY_TRANSFORM, p_enabled); +} + +bool Area2D::is_gravity_apply_transform() const { + return gravity_apply_transform; +} + void Area2D::set_gravity_point_unit_distance(real_t p_scale) { gravity_point_unit_distance = p_scale; PhysicsServer2D::get_singleton()->area_set_param(get_rid(), PhysicsServer2D::AREA_PARAM_GRAVITY_POINT_UNIT_DISTANCE, p_scale); @@ -532,6 +541,8 @@ void Area2D::_validate_property(PropertyInfo &p_property) const { if (gravity_is_point) { if (p_property.name == "gravity_direction") { p_property.usage = PROPERTY_USAGE_NO_EDITOR; + } else if (p_property.name == "gravity_apply_transform") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } else { if (p_property.name.begins_with("gravity_point_")) { @@ -557,6 +568,9 @@ void Area2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_gravity_is_point", "enable"), &Area2D::set_gravity_is_point); ClassDB::bind_method(D_METHOD("is_gravity_a_point"), &Area2D::is_gravity_a_point); + ClassDB::bind_method(D_METHOD("set_gravity_apply_transform", "enable"), &Area2D::set_gravity_apply_transform); + ClassDB::bind_method(D_METHOD("is_gravity_apply_transform"), &Area2D::is_gravity_apply_transform); + ClassDB::bind_method(D_METHOD("set_gravity_point_unit_distance", "distance_scale"), &Area2D::set_gravity_point_unit_distance); ClassDB::bind_method(D_METHOD("get_gravity_point_unit_distance"), &Area2D::get_gravity_point_unit_distance); @@ -622,6 +636,7 @@ void Area2D::_bind_methods() { ADD_GROUP("Gravity", "gravity_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "gravity_space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_gravity_space_override_mode", "get_gravity_space_override_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gravity_point", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_gravity_is_point", "is_gravity_a_point"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gravity_apply_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_gravity_apply_transform", "is_gravity_apply_transform"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_point_unit_distance", PROPERTY_HINT_RANGE, "0,1024,0.001,or_greater,exp,suffix:px"), "set_gravity_point_unit_distance", "get_gravity_point_unit_distance"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity_point_center", PROPERTY_HINT_NONE, "suffix:px"), "set_gravity_point_center", "get_gravity_point_center"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity_direction"), "set_gravity_direction", "get_gravity_direction"); diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h index 421c29f7589f..d9994820facf 100644 --- a/scene/2d/area_2d.h +++ b/scene/2d/area_2d.h @@ -51,6 +51,7 @@ class Area2D : public CollisionObject2D { Vector2 gravity_vec; real_t gravity = 0.0; bool gravity_is_point = false; + bool gravity_apply_transform = false; real_t gravity_point_unit_distance = 0.0; SpaceOverride linear_damp_space_override = SPACE_OVERRIDE_DISABLED; @@ -144,6 +145,9 @@ class Area2D : public CollisionObject2D { void set_gravity_is_point(bool p_enabled); bool is_gravity_a_point() const; + void set_gravity_apply_transform(bool p_enabled); + bool is_gravity_apply_transform() const; + void set_gravity_point_unit_distance(real_t p_scale); real_t get_gravity_point_unit_distance() const; diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp index 29d151b7263d..beae580aefb3 100644 --- a/scene/3d/area_3d.cpp +++ b/scene/3d/area_3d.cpp @@ -51,6 +51,15 @@ bool Area3D::is_gravity_a_point() const { return gravity_is_point; } +void Area3D::set_gravity_apply_transform(bool p_enabled) { + gravity_apply_transform = p_enabled; + PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_GRAVITY_APPLY_TRANSFORM, p_enabled); +} + +bool Area3D::is_gravity_apply_transform() const { + return gravity_apply_transform; +} + void Area3D::set_gravity_point_unit_distance(real_t p_scale) { gravity_point_unit_distance = p_scale; PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_UNIT_DISTANCE, p_scale); @@ -632,6 +641,8 @@ void Area3D::_validate_property(PropertyInfo &p_property) const { if (gravity_is_point) { if (p_property.name == "gravity_direction") { p_property.usage = PROPERTY_USAGE_NO_EDITOR; + } else if (p_property.name == "gravity_apply_transform") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } else { if (p_property.name.begins_with("gravity_point_")) { @@ -657,6 +668,9 @@ void Area3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_gravity_is_point", "enable"), &Area3D::set_gravity_is_point); ClassDB::bind_method(D_METHOD("is_gravity_a_point"), &Area3D::is_gravity_a_point); + ClassDB::bind_method(D_METHOD("set_gravity_apply_transform", "enable"), &Area3D::set_gravity_apply_transform); + ClassDB::bind_method(D_METHOD("is_gravity_apply_transform"), &Area3D::is_gravity_apply_transform); + ClassDB::bind_method(D_METHOD("set_gravity_point_unit_distance", "distance_scale"), &Area3D::set_gravity_point_unit_distance); ClassDB::bind_method(D_METHOD("get_gravity_point_unit_distance"), &Area3D::get_gravity_point_unit_distance); @@ -743,6 +757,7 @@ void Area3D::_bind_methods() { ADD_GROUP("Gravity", "gravity_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "gravity_space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_gravity_space_override_mode", "get_gravity_space_override_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gravity_point", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_gravity_is_point", "is_gravity_a_point"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gravity_apply_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_gravity_apply_transform", "is_gravity_apply_transform"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_point_unit_distance", PROPERTY_HINT_RANGE, "0,1024,0.001,or_greater,exp,suffix:m"), "set_gravity_point_unit_distance", "get_gravity_point_unit_distance"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity_point_center", PROPERTY_HINT_NONE, "suffix:m"), "set_gravity_point_center", "get_gravity_point_center"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity_direction"), "set_gravity_direction", "get_gravity_direction"); diff --git a/scene/3d/area_3d.h b/scene/3d/area_3d.h index 454c8c296061..776e7fb88ca5 100644 --- a/scene/3d/area_3d.h +++ b/scene/3d/area_3d.h @@ -51,6 +51,7 @@ class Area3D : public CollisionObject3D { Vector3 gravity_vec; real_t gravity = 0.0; bool gravity_is_point = false; + bool gravity_apply_transform = false; real_t gravity_point_unit_distance = 0.0; SpaceOverride linear_damp_space_override = SPACE_OVERRIDE_DISABLED; @@ -155,6 +156,9 @@ class Area3D : public CollisionObject3D { void set_gravity_is_point(bool p_enabled); bool is_gravity_a_point() const; + void set_gravity_apply_transform(bool p_enabled); + bool is_gravity_apply_transform() const; + void set_gravity_point_unit_distance(real_t p_scale); real_t get_gravity_point_unit_distance() const; diff --git a/servers/physics_2d/godot_area_2d.cpp b/servers/physics_2d/godot_area_2d.cpp index 4d2148aa07b4..c143140ca436 100644 --- a/servers/physics_2d/godot_area_2d.cpp +++ b/servers/physics_2d/godot_area_2d.cpp @@ -145,6 +145,9 @@ void GodotArea2D::set_param(PhysicsServer2D::AreaParameter p_param, const Varian case PhysicsServer2D::AREA_PARAM_GRAVITY_IS_POINT: gravity_is_point = p_value; break; + case PhysicsServer2D::AREA_PARAM_GRAVITY_APPLY_TRANSFORM: + gravity_apply_transform = p_value; + break; case PhysicsServer2D::AREA_PARAM_GRAVITY_POINT_UNIT_DISTANCE: gravity_point_unit_distance = p_value; break; @@ -176,6 +179,8 @@ Variant GodotArea2D::get_param(PhysicsServer2D::AreaParameter p_param) const { return gravity_vector; case PhysicsServer2D::AREA_PARAM_GRAVITY_IS_POINT: return gravity_is_point; + case PhysicsServer2D::AREA_PARAM_GRAVITY_APPLY_TRANSFORM: + return gravity_apply_transform; case PhysicsServer2D::AREA_PARAM_GRAVITY_POINT_UNIT_DISTANCE: return gravity_point_unit_distance; case PhysicsServer2D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE: @@ -312,6 +317,8 @@ void GodotArea2D::compute_gravity(const Vector2 &p_position, Vector2 &r_gravity) } else { r_gravity = v.normalized() * get_gravity(); } + } else if (gravity_apply_transform) { + r_gravity = get_transform().basis_xform(get_gravity_vector()) * get_gravity(); } else { r_gravity = get_gravity_vector() * get_gravity(); } diff --git a/servers/physics_2d/godot_area_2d.h b/servers/physics_2d/godot_area_2d.h index 234e4eb9a9d2..6732a565ee7f 100644 --- a/servers/physics_2d/godot_area_2d.h +++ b/servers/physics_2d/godot_area_2d.h @@ -48,6 +48,7 @@ class GodotArea2D : public GodotCollisionObject2D { real_t gravity = 9.80665; Vector2 gravity_vector = Vector2(0, -1); bool gravity_is_point = false; + bool gravity_apply_transform = false; real_t gravity_point_unit_distance = 0.0; real_t linear_damp = 0.1; real_t angular_damp = 1.0; @@ -124,6 +125,9 @@ class GodotArea2D : public GodotCollisionObject2D { _FORCE_INLINE_ void set_gravity_as_point(bool p_enable) { gravity_is_point = p_enable; } _FORCE_INLINE_ bool is_gravity_point() const { return gravity_is_point; } + _FORCE_INLINE_ void set_gravity_apply_transform(bool p_enable) { gravity_apply_transform = p_enable; } + _FORCE_INLINE_ bool is_gravity_apply_transform() const { return gravity_apply_transform; } + _FORCE_INLINE_ void set_gravity_point_unit_distance(real_t scale) { gravity_point_unit_distance = scale; } _FORCE_INLINE_ real_t get_gravity_point_unit_distance() const { return gravity_point_unit_distance; } diff --git a/servers/physics_3d/godot_area_3d.cpp b/servers/physics_3d/godot_area_3d.cpp index 5bf16aa6884f..3f5942e6de4f 100644 --- a/servers/physics_3d/godot_area_3d.cpp +++ b/servers/physics_3d/godot_area_3d.cpp @@ -152,6 +152,9 @@ void GodotArea3D::set_param(PhysicsServer3D::AreaParameter p_param, const Varian case PhysicsServer3D::AREA_PARAM_GRAVITY_IS_POINT: gravity_is_point = p_value; break; + case PhysicsServer3D::AREA_PARAM_GRAVITY_APPLY_TRANSFORM: + gravity_apply_transform = p_value; + break; case PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_UNIT_DISTANCE: gravity_point_unit_distance = p_value; break; @@ -197,6 +200,8 @@ Variant GodotArea3D::get_param(PhysicsServer3D::AreaParameter p_param) const { return gravity_vector; case PhysicsServer3D::AREA_PARAM_GRAVITY_IS_POINT: return gravity_is_point; + case PhysicsServer3D::AREA_PARAM_GRAVITY_APPLY_TRANSFORM: + return gravity_apply_transform; case PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_UNIT_DISTANCE: return gravity_point_unit_distance; case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE: @@ -341,6 +346,8 @@ void GodotArea3D::compute_gravity(const Vector3 &p_position, Vector3 &r_gravity) } else { r_gravity = v.normalized() * get_gravity(); } + } else if (gravity_apply_transform) { + r_gravity = get_transform().get_basis().xform(get_gravity_vector()) * get_gravity(); } else { r_gravity = get_gravity_vector() * get_gravity(); } diff --git a/servers/physics_3d/godot_area_3d.h b/servers/physics_3d/godot_area_3d.h index f05d0f90197c..63e1e3f707a5 100644 --- a/servers/physics_3d/godot_area_3d.h +++ b/servers/physics_3d/godot_area_3d.h @@ -49,6 +49,7 @@ class GodotArea3D : public GodotCollisionObject3D { real_t gravity = 9.80665; Vector3 gravity_vector = Vector3(0, -1, 0); bool gravity_is_point = false; + bool gravity_apply_transform = false; real_t gravity_point_unit_distance = 0.0; real_t linear_damp = 0.1; real_t angular_damp = 0.1; @@ -133,6 +134,9 @@ class GodotArea3D : public GodotCollisionObject3D { _FORCE_INLINE_ void set_gravity_as_point(bool p_enable) { gravity_is_point = p_enable; } _FORCE_INLINE_ bool is_gravity_point() const { return gravity_is_point; } + _FORCE_INLINE_ void set_gravity_apply_transform(bool p_enable) { gravity_apply_transform = p_enable; } + _FORCE_INLINE_ bool is_gravity_apply_transform() const { return gravity_apply_transform; } + _FORCE_INLINE_ void set_gravity_point_unit_distance(real_t scale) { gravity_point_unit_distance = scale; } _FORCE_INLINE_ real_t get_gravity_point_unit_distance() const { return gravity_point_unit_distance; } diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp index 79a8ebe3d1e1..ba254350214b 100644 --- a/servers/physics_server_2d.cpp +++ b/servers/physics_server_2d.cpp @@ -811,6 +811,7 @@ void PhysicsServer2D::_bind_methods() { BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_OVERRIDE_MODE); BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY); BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_VECTOR); + BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_APPLY_TRANSFORM); BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_IS_POINT); BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_POINT_UNIT_DISTANCE); BIND_ENUM_CONSTANT(AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE); diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h index f1f6e843215d..630c6ff4165e 100644 --- a/servers/physics_server_2d.h +++ b/servers/physics_server_2d.h @@ -292,7 +292,8 @@ class PhysicsServer2D : public Object { AREA_PARAM_LINEAR_DAMP, AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE, AREA_PARAM_ANGULAR_DAMP, - AREA_PARAM_PRIORITY + AREA_PARAM_PRIORITY, + AREA_PARAM_GRAVITY_APPLY_TRANSFORM }; virtual RID area_create() = 0; diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index 6b8d3d1af684..cf57ade0d3cb 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -976,6 +976,7 @@ void PhysicsServer3D::_bind_methods() { BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_OVERRIDE_MODE); BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY); BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_VECTOR); + BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_APPLY_TRANSFORM); BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_IS_POINT); BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_POINT_UNIT_DISTANCE); BIND_ENUM_CONSTANT(AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE); diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h index 33e9f8a7c9e7..4568f5bb619e 100644 --- a/servers/physics_server_3d.h +++ b/servers/physics_server_3d.h @@ -327,6 +327,7 @@ class PhysicsServer3D : public Object { AREA_PARAM_WIND_SOURCE, AREA_PARAM_WIND_DIRECTION, AREA_PARAM_WIND_ATTENUATION_FACTOR, + AREA_PARAM_GRAVITY_APPLY_TRANSFORM, }; virtual RID area_create() = 0;