diff --git a/doc/classes/KinematicBody.xml b/doc/classes/KinematicBody.xml
index 6fa93ee0cfd..464369d197c 100644
--- a/doc/classes/KinematicBody.xml
+++ b/doc/classes/KinematicBody.xml
@@ -23,6 +23,13 @@
Returns [code]true[/code] if the specified [code]axis[/code] is locked. See also [member move_lock_x], [member move_lock_y] and [member move_lock_z].
+
+
+
+
+ Returns the floor's collision angle at the last collision point according to [code]up_direction[/code], which is [code]Vector3.UP[/code] by default. This value is always positive and only valid after calling [method move_and_slide] and when [method is_on_floor] returns [code]true[/code].
+
+
@@ -35,6 +42,12 @@
Returns the linear velocity of the floor at the last collision point. Only valid after calling [method move_and_slide] or [method move_and_slide_with_snap] and when [method is_on_floor] returns [code]true[/code].
+
+
+
+ Returns a [KinematicCollision], which contains information about the latest collision that occurred during the last call to [method move_and_slide].
+
+
diff --git a/doc/classes/KinematicBody2D.xml b/doc/classes/KinematicBody2D.xml
index 7f2e446432c..c61f89bcc63 100644
--- a/doc/classes/KinematicBody2D.xml
+++ b/doc/classes/KinematicBody2D.xml
@@ -15,6 +15,13 @@
https://godotengine.org/asset-library/asset/120
+
+
+
+
+ Returns the floor's collision angle at the last collision point according to [code]up_direction[/code], which is [code]Vector2.UP[/code] by default. This value is always positive and only valid after calling [method move_and_slide] and when [method is_on_floor] returns [code]true[/code].
+
+
@@ -27,6 +34,12 @@
Returns the linear velocity of the floor at the last collision point. Only valid after calling [method move_and_slide] or [method move_and_slide_with_snap] and when [method is_on_floor] returns [code]true[/code].
+
+
+
+ Returns a [KinematicCollision2D], which contains information about the latest collision that occurred during the last call to [method move_and_slide].
+
+
diff --git a/doc/classes/KinematicCollision.xml b/doc/classes/KinematicCollision.xml
index 17be68c071d..2e118adf025 100644
--- a/doc/classes/KinematicCollision.xml
+++ b/doc/classes/KinematicCollision.xml
@@ -10,6 +10,13 @@
+
+
+
+
+ The collision angle according to [code]up_direction[/code], which is [code]Vector3.UP[/code] by default. This value is always positive.
+
+
diff --git a/doc/classes/KinematicCollision2D.xml b/doc/classes/KinematicCollision2D.xml
index d70d53e6c00..90dd0af0def 100644
--- a/doc/classes/KinematicCollision2D.xml
+++ b/doc/classes/KinematicCollision2D.xml
@@ -10,6 +10,13 @@
+
+
+
+
+ The collision angle according to [code]up_direction[/code], which is [code]Vector2.UP[/code] by default. This value is always positive.
+
+
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index f382334a979..2acf3d49f4f 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -1281,6 +1281,11 @@ Vector2 KinematicBody2D::get_floor_normal() const {
return floor_normal;
}
+real_t KinematicBody2D::get_floor_angle(const Vector2 &p_up_direction) const {
+ ERR_FAIL_COND_V(p_up_direction == Vector2(), 0);
+ return Math::acos(floor_normal.dot(p_up_direction));
+}
+
Vector2 KinematicBody2D::get_floor_velocity() const {
return floor_velocity;
}
@@ -1323,6 +1328,13 @@ Ref KinematicBody2D::_get_slide_collision(int p_bounce) {
return slide_colliders[p_bounce];
}
+Ref KinematicBody2D::_get_last_slide_collision() {
+ if (colliders.size() == 0) {
+ return Ref();
+ }
+ return _get_slide_collision(colliders.size() - 1);
+}
+
void KinematicBody2D::set_sync_to_physics(bool p_enable) {
if (sync_to_physics == p_enable) {
return;
@@ -1396,6 +1408,7 @@ void KinematicBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_on_ceiling"), &KinematicBody2D::is_on_ceiling);
ClassDB::bind_method(D_METHOD("is_on_wall"), &KinematicBody2D::is_on_wall);
ClassDB::bind_method(D_METHOD("get_floor_normal"), &KinematicBody2D::get_floor_normal);
+ ClassDB::bind_method(D_METHOD("get_floor_angle", "up_direction"), &KinematicBody2D::get_floor_angle, DEFVAL(Vector2(0.0, -1.0)));
ClassDB::bind_method(D_METHOD("get_floor_velocity"), &KinematicBody2D::get_floor_velocity);
ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &KinematicBody2D::set_safe_margin);
@@ -1403,6 +1416,7 @@ void KinematicBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_slide_count"), &KinematicBody2D::get_slide_count);
ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &KinematicBody2D::_get_slide_collision);
+ ClassDB::bind_method(D_METHOD("get_last_slide_collision"), &KinematicBody2D::_get_last_slide_collision);
ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &KinematicBody2D::set_sync_to_physics);
ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &KinematicBody2D::is_sync_to_physics_enabled);
@@ -1448,6 +1462,12 @@ Vector2 KinematicCollision2D::get_travel() const {
Vector2 KinematicCollision2D::get_remainder() const {
return collision.remainder;
}
+
+real_t KinematicCollision2D::get_angle(const Vector2 &p_up_direction) const {
+ ERR_FAIL_COND_V(p_up_direction == Vector2(), 0);
+ return collision.get_angle(p_up_direction);
+}
+
Object *KinematicCollision2D::get_local_shape() const {
if (!owner) {
return nullptr;
@@ -1496,6 +1516,7 @@ void KinematicCollision2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_normal"), &KinematicCollision2D::get_normal);
ClassDB::bind_method(D_METHOD("get_travel"), &KinematicCollision2D::get_travel);
ClassDB::bind_method(D_METHOD("get_remainder"), &KinematicCollision2D::get_remainder);
+ ClassDB::bind_method(D_METHOD("get_angle", "up_direction"), &KinematicCollision2D::get_angle, DEFVAL(Vector2(0.0, -1.0)));
ClassDB::bind_method(D_METHOD("get_local_shape"), &KinematicCollision2D::get_local_shape);
ClassDB::bind_method(D_METHOD("get_collider"), &KinematicCollision2D::get_collider);
ClassDB::bind_method(D_METHOD("get_collider_id"), &KinematicCollision2D::get_collider_id);
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index a4daefb1e77..02c2de53ea0 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -280,6 +280,10 @@ public:
Vector2 remainder;
Vector2 travel;
int local_shape;
+
+ real_t get_angle(const Vector2 &p_up_direction) const {
+ return Math::acos(normal.dot(p_up_direction));
+ }
};
private:
@@ -299,6 +303,7 @@ private:
Ref _move(const Vector2 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false);
Ref _get_slide_collision(int p_bounce);
+ Ref _get_last_slide_collision();
Transform2D last_valid_transform;
void _direct_state_changed(Object *p_state);
@@ -325,6 +330,7 @@ public:
bool is_on_wall() const;
bool is_on_ceiling() const;
Vector2 get_floor_normal() const;
+ real_t get_floor_angle(const Vector2 &p_up_direction = Vector2(0.0, -1.0)) const;
Vector2 get_floor_velocity() const;
int get_slide_count() const;
@@ -352,6 +358,7 @@ public:
Vector2 get_normal() const;
Vector2 get_travel() const;
Vector2 get_remainder() const;
+ real_t get_angle(const Vector2 &p_up_direction = Vector2(0.0, -1.0)) const;
Object *get_local_shape() const;
Object *get_collider() const;
ObjectID get_collider_id() const;
diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp
index 1deda54a665..035928e5ec1 100644
--- a/scene/3d/physics_body.cpp
+++ b/scene/3d/physics_body.cpp
@@ -1242,6 +1242,11 @@ Vector3 KinematicBody::get_floor_normal() const {
return floor_normal;
}
+real_t KinematicBody::get_floor_angle(const Vector3 &p_up_direction) const {
+ ERR_FAIL_COND_V(p_up_direction == Vector3(), 0);
+ return Math::acos(floor_normal.dot(p_up_direction));
+}
+
Vector3 KinematicBody::get_floor_velocity() const {
return floor_velocity;
}
@@ -1328,6 +1333,13 @@ Ref KinematicBody::_get_slide_collision(int p_bounce) {
return slide_colliders[p_bounce];
}
+Ref KinematicBody::_get_last_slide_collision() {
+ if (colliders.size() == 0) {
+ return Ref();
+ }
+ return _get_slide_collision(colliders.size() - 1);
+}
+
void KinematicBody::set_sync_to_physics(bool p_enable) {
if (sync_to_physics == p_enable) {
return;
@@ -1404,6 +1416,7 @@ void KinematicBody::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_on_ceiling"), &KinematicBody::is_on_ceiling);
ClassDB::bind_method(D_METHOD("is_on_wall"), &KinematicBody::is_on_wall);
ClassDB::bind_method(D_METHOD("get_floor_normal"), &KinematicBody::get_floor_normal);
+ ClassDB::bind_method(D_METHOD("get_floor_angle", "up_direction"), &KinematicBody::get_floor_angle, DEFVAL(Vector3(0.0, 1.0, 0.0)));
ClassDB::bind_method(D_METHOD("get_floor_velocity"), &KinematicBody::get_floor_velocity);
ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &KinematicBody::set_axis_lock);
@@ -1414,6 +1427,7 @@ void KinematicBody::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_slide_count"), &KinematicBody::get_slide_count);
ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &KinematicBody::_get_slide_collision);
+ ClassDB::bind_method(D_METHOD("get_last_slide_collision"), &KinematicBody::_get_last_slide_collision);
ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &KinematicBody::set_sync_to_physics);
ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &KinematicBody::is_sync_to_physics_enabled);
@@ -1463,6 +1477,12 @@ Vector3 KinematicCollision::get_travel() const {
Vector3 KinematicCollision::get_remainder() const {
return collision.remainder;
}
+
+real_t KinematicCollision::get_angle(const Vector3 &p_up_direction) const {
+ ERR_FAIL_COND_V(p_up_direction == Vector3(), 0);
+ return collision.get_angle(p_up_direction);
+}
+
Object *KinematicCollision::get_local_shape() const {
if (!owner) {
return nullptr;
@@ -1511,6 +1531,7 @@ void KinematicCollision::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_normal"), &KinematicCollision::get_normal);
ClassDB::bind_method(D_METHOD("get_travel"), &KinematicCollision::get_travel);
ClassDB::bind_method(D_METHOD("get_remainder"), &KinematicCollision::get_remainder);
+ ClassDB::bind_method(D_METHOD("get_angle", "up_direction"), &KinematicCollision::get_angle, DEFVAL(Vector3(0.0, 1.0, 0.0)));
ClassDB::bind_method(D_METHOD("get_local_shape"), &KinematicCollision::get_local_shape);
ClassDB::bind_method(D_METHOD("get_collider"), &KinematicCollision::get_collider);
ClassDB::bind_method(D_METHOD("get_collider_id"), &KinematicCollision::get_collider_id);
diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h
index 40e8e9d3629..47636c3a1b9 100644
--- a/scene/3d/physics_body.h
+++ b/scene/3d/physics_body.h
@@ -275,6 +275,10 @@ public:
Vector3 remainder;
Vector3 travel;
int local_shape;
+
+ real_t get_angle(const Vector3 &p_up_direction) const {
+ return Math::acos(normal.dot(p_up_direction));
+ }
};
private:
@@ -295,6 +299,7 @@ private:
Ref _move(const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false);
Ref _get_slide_collision(int p_bounce);
+ Ref _get_last_slide_collision();
Transform last_valid_transform;
void _direct_state_changed(Object *p_state);
@@ -324,6 +329,7 @@ public:
bool is_on_wall() const;
bool is_on_ceiling() const;
Vector3 get_floor_normal() const;
+ real_t get_floor_angle(const Vector3 &p_up_direction = Vector3(0.0, 1.0, 0.0)) const;
Vector3 get_floor_velocity() const;
int get_slide_count() const;
@@ -351,6 +357,7 @@ public:
Vector3 get_normal() const;
Vector3 get_travel() const;
Vector3 get_remainder() const;
+ real_t get_angle(const Vector3 &p_up_direction = Vector3(0.0, 1.0, 0.0)) const;
Object *get_local_shape() const;
Object *get_collider() const;
ObjectID get_collider_id() const;