Fix applied rotation from moving platforms in move_and_slide

When synchronizing CharacterBody motion with moving the platform using
direct body state, only the linear velocity was taken into account.

This change exposes velocity at local point in direct body state and
uses it in move_and_slide to get the proper velocity that includes
rotations.
This commit is contained in:
PouleyKetchoupp 2021-08-09 12:14:24 -07:00
parent 0cee8831b2
commit 5650c83e4b
12 changed files with 48 additions and 2 deletions

View file

@ -137,6 +137,13 @@
Returns the current state of the space, useful for queries.
</description>
</method>
<method name="get_velocity_at_local_position" qualifiers="const">
<return type="Vector2" />
<argument index="0" name="local_position" type="Vector2" />
<description>
Returns the body's velocity at the given relative position, including both translation and rotation.
</description>
</method>
<method name="integrate_forces">
<return type="void" />
<description>

View file

@ -138,6 +138,13 @@
Returns the current state of the space, useful for queries.
</description>
</method>
<method name="get_velocity_at_local_position" qualifiers="const">
<return type="Vector3" />
<argument index="0" name="local_position" type="Vector3" />
<description>
Returns the body's velocity at the given relative position, including both translation and rotation.
</description>
</method>
<method name="integrate_forces">
<return type="void" />
<description>

View file

@ -114,6 +114,16 @@ Transform3D BulletPhysicsDirectBodyState3D::get_transform() const {
return body->get_transform();
}
Vector3 BulletPhysicsDirectBodyState3D::get_velocity_at_local_position(const Vector3 &p_position) const {
btVector3 local_position;
G_TO_B(p_position, local_position);
Vector3 velocity;
B_TO_G(body->btBody->getVelocityInLocalPoint(local_position), velocity);
return velocity;
}
void BulletPhysicsDirectBodyState3D::add_central_force(const Vector3 &p_force) {
body->apply_central_force(p_force);
}

View file

@ -110,6 +110,8 @@ public:
virtual void set_transform(const Transform3D &p_transform) override;
virtual Transform3D get_transform() const override;
virtual Vector3 get_velocity_at_local_position(const Vector3 &p_position) const override;
virtual void add_central_force(const Vector3 &p_force) override;
virtual void add_force(const Vector3 &p_force, const Vector3 &p_position = Vector3()) override;
virtual void add_torque(const Vector3 &p_torque) override;

View file

@ -1062,7 +1062,9 @@ void CharacterBody2D::move_and_slide() {
//this approach makes sure there is less delay between the actual body velocity and the one we saved
PhysicsDirectBodyState2D *bs = PhysicsServer2D::get_singleton()->body_get_direct_state(on_floor_body);
if (bs) {
current_floor_velocity = bs->get_linear_velocity();
Transform2D gt = get_global_transform();
Vector2 local_position = gt.elements[2] - bs->get_transform().elements[2];
current_floor_velocity = bs->get_velocity_at_local_position(local_position);
}
}

View file

@ -1101,7 +1101,9 @@ void CharacterBody3D::move_and_slide() {
//this approach makes sure there is less delay between the actual body velocity and the one we saved
PhysicsDirectBodyState3D *bs = PhysicsServer3D::get_singleton()->body_get_direct_state(on_floor_body);
if (bs) {
current_floor_velocity = bs->get_linear_velocity();
Transform3D gt = get_global_transform();
Vector3 local_position = gt.origin - bs->get_transform().origin;
current_floor_velocity = bs->get_velocity_at_local_position(local_position);
}
}

View file

@ -266,6 +266,10 @@ public:
void integrate_forces(real_t p_step);
void integrate_velocities(real_t p_step);
_FORCE_INLINE_ Vector2 get_velocity_in_local_point(const Vector2 &rel_pos) const {
return linear_velocity + Vector2(-angular_velocity * rel_pos.y, angular_velocity * rel_pos.x);
}
_FORCE_INLINE_ Vector2 get_motion() const {
if (mode > PhysicsServer2D::BODY_MODE_KINEMATIC) {
return new_transform.get_origin() - get_transform().get_origin();
@ -352,6 +356,8 @@ public:
virtual void set_transform(const Transform2D &p_transform) override { body->set_state(PhysicsServer2D::BODY_STATE_TRANSFORM, p_transform); }
virtual Transform2D get_transform() const override { return body->get_transform(); }
virtual Vector2 get_velocity_at_local_position(const Vector2 &p_position) const override { return body->get_velocity_in_local_point(p_position); }
virtual void add_central_force(const Vector2 &p_force) override { body->add_central_force(p_force); }
virtual void add_force(const Vector2 &p_force, const Vector2 &p_position = Vector2()) override { body->add_force(p_force, p_position); }
virtual void add_torque(real_t p_torque) override { body->add_torque(p_torque); }

View file

@ -389,6 +389,8 @@ public:
virtual void set_transform(const Transform3D &p_transform) override { body->set_state(PhysicsServer3D::BODY_STATE_TRANSFORM, p_transform); }
virtual Transform3D get_transform() const override { return body->get_transform(); }
virtual Vector3 get_velocity_at_local_position(const Vector3 &p_position) const override { return body->get_velocity_in_local_point(p_position); }
virtual void add_central_force(const Vector3 &p_force) override { body->add_central_force(p_force); }
virtual void add_force(const Vector3 &p_force, const Vector3 &p_position = Vector3()) override {
body->add_force(p_force, p_position);

View file

@ -89,6 +89,8 @@ void PhysicsDirectBodyState2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_transform", "transform"), &PhysicsDirectBodyState2D::set_transform);
ClassDB::bind_method(D_METHOD("get_transform"), &PhysicsDirectBodyState2D::get_transform);
ClassDB::bind_method(D_METHOD("get_velocity_at_local_position", "local_position"), &PhysicsDirectBodyState2D::get_velocity_at_local_position);
ClassDB::bind_method(D_METHOD("add_central_force", "force"), &PhysicsDirectBodyState2D::add_central_force);
ClassDB::bind_method(D_METHOD("add_force", "force", "position"), &PhysicsDirectBodyState2D::add_force, Vector2());
ClassDB::bind_method(D_METHOD("add_torque", "torque"), &PhysicsDirectBodyState2D::add_torque);

View file

@ -60,6 +60,8 @@ public:
virtual void set_transform(const Transform2D &p_transform) = 0;
virtual Transform2D get_transform() const = 0;
virtual Vector2 get_velocity_at_local_position(const Vector2 &p_position) const = 0;
virtual void add_central_force(const Vector2 &p_force) = 0;
virtual void add_force(const Vector2 &p_force, const Vector2 &p_position = Vector2()) = 0;
virtual void add_torque(real_t p_torque) = 0;

View file

@ -91,6 +91,8 @@ void PhysicsDirectBodyState3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_transform", "transform"), &PhysicsDirectBodyState3D::set_transform);
ClassDB::bind_method(D_METHOD("get_transform"), &PhysicsDirectBodyState3D::get_transform);
ClassDB::bind_method(D_METHOD("get_velocity_at_local_position", "local_position"), &PhysicsDirectBodyState3D::get_velocity_at_local_position);
ClassDB::bind_method(D_METHOD("add_central_force", "force"), &PhysicsDirectBodyState3D::add_central_force, Vector3());
ClassDB::bind_method(D_METHOD("add_force", "force", "position"), &PhysicsDirectBodyState3D::add_force, Vector3());
ClassDB::bind_method(D_METHOD("add_torque", "torque"), &PhysicsDirectBodyState3D::add_torque);

View file

@ -62,6 +62,8 @@ public:
virtual void set_transform(const Transform3D &p_transform) = 0;
virtual Transform3D get_transform() const = 0;
virtual Vector3 get_velocity_at_local_position(const Vector3 &p_position) const = 0;
virtual void add_central_force(const Vector3 &p_force) = 0;
virtual void add_force(const Vector3 &p_force, const Vector3 &p_position = Vector3()) = 0;
virtual void add_torque(const Vector3 &p_torque) = 0;