Fix 3D moving platform logic
Same thing that was already done in 2D, applies moving platform motion by using a call to move_and_collide that excludes the platform itself, instead of making it part of the body motion. Helps with handling walls and slopes correctly when the character walks on the moving platform. Also made some minor adjustments to the 2D version and documentation. Co-authored-by: fabriceci <fabricecipolla@gmail.com>
This commit is contained in:
parent
f3ddc14d38
commit
ec9fed69f4
20 changed files with 118 additions and 61 deletions
|
@ -79,6 +79,7 @@
|
|||
Moves the body based on [member linear_velocity]. If the body collides with another, it will slide along the other body rather than stop immediately. If the other body is a [CharacterBody2D] or [RigidBody2D], it will also be affected by the motion of the other body. You can use this to make moving and rotating platforms, or to make nodes push other nodes.
|
||||
This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed.
|
||||
Modifies [member linear_velocity] if a slide collision occurred. To get detailed information about collisions that occurred, use [method get_slide_collision].
|
||||
When the body touches a moving platform, the platform's velocity is automatically added to the body motion. If a collision occurs due to the platform's motion, it will always be first in the slide collisions.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
Moves the body based on [member linear_velocity]. If the body collides with another, it will slide along the other body rather than stop immediately. If the other body is a [CharacterBody3D] or [RigidBody3D], it will also be affected by the motion of the other body. You can use this to make moving and rotating platforms, or to make nodes push other nodes.
|
||||
This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed.
|
||||
Modifies [member linear_velocity] if a slide collision occurred. To get detailed information about collisions that occurred, use [method get_slide_collision].
|
||||
When the body touches a moving platform, the platform's velocity is automatically added to the body motion. If a collision occurs due to the platform's motion, it will always be first in the slide collisions.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
|
|
|
@ -572,6 +572,8 @@
|
|||
<argument index="3" name="infinite_inertia" type="bool" />
|
||||
<argument index="4" name="margin" type="float" default="0.001" />
|
||||
<argument index="5" name="result" type="PhysicsTestMotionResult3D" default="null" />
|
||||
<argument index="6" name="exclude_raycast_shapes" type="bool" default="true" />
|
||||
<argument index="7" name="exclude" type="Array" default="[]" />
|
||||
<description>
|
||||
Returns [code]true[/code] if a collision would result from moving in the given direction from a given point in space. Margin increases the size of the shapes involved in the collision detection. [PhysicsTestMotionResult3D] can be passed to return additional information in.
|
||||
</description>
|
||||
|
|
|
@ -842,12 +842,12 @@ PhysicsDirectBodyState3D *BulletPhysicsServer3D::body_get_direct_state(RID p_bod
|
|||
return BulletPhysicsDirectBodyState3D::get_singleton(body);
|
||||
}
|
||||
|
||||
bool BulletPhysicsServer3D::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result, bool p_exclude_raycast_shapes) {
|
||||
bool BulletPhysicsServer3D::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude) {
|
||||
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
|
||||
ERR_FAIL_COND_V(!body, false);
|
||||
ERR_FAIL_COND_V(!body->get_space(), false);
|
||||
|
||||
return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, r_result, p_exclude_raycast_shapes);
|
||||
return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, r_result, p_exclude_raycast_shapes, p_exclude);
|
||||
}
|
||||
|
||||
int BulletPhysicsServer3D::body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin) {
|
||||
|
|
|
@ -253,7 +253,7 @@ public:
|
|||
// this function only works on physics process, errors and returns null otherwise
|
||||
virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override;
|
||||
|
||||
virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override;
|
||||
virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true, const Set<RID> &p_exclude = Set<RID>()) override;
|
||||
virtual int body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override;
|
||||
|
||||
/* SOFT BODY API */
|
||||
|
|
|
@ -135,6 +135,10 @@ bool GodotKinClosestConvexResultCallback::needsCollision(btBroadphaseProxy *prox
|
|||
if (m_self_object->has_collision_exception(gObj) || gObj->has_collision_exception(m_self_object)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_exclude->has(gObj->get_self())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
|
|
|
@ -100,11 +100,13 @@ public:
|
|||
struct GodotKinClosestConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback {
|
||||
public:
|
||||
const RigidBodyBullet *m_self_object;
|
||||
const Set<RID> *m_exclude;
|
||||
const bool m_infinite_inertia;
|
||||
|
||||
GodotKinClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const RigidBodyBullet *p_self_object, bool p_infinite_inertia) :
|
||||
GodotKinClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const RigidBodyBullet *p_self_object, bool p_infinite_inertia, const Set<RID> *p_exclude) :
|
||||
btCollisionWorld::ClosestConvexResultCallback(convexFromWorld, convexToWorld),
|
||||
m_self_object(p_self_object),
|
||||
m_exclude(p_exclude),
|
||||
m_infinite_inertia(p_infinite_inertia) {}
|
||||
|
||||
virtual bool needsCollision(btBroadphaseProxy *proxy0) const;
|
||||
|
|
|
@ -908,7 +908,7 @@ static Ref<StandardMaterial3D> red_mat;
|
|||
static Ref<StandardMaterial3D> blue_mat;
|
||||
#endif
|
||||
|
||||
bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes) {
|
||||
bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude) {
|
||||
#if debug_test_motion
|
||||
/// Yes I know this is not good, but I've used it as fast debugging hack.
|
||||
/// I'm leaving it here just for speedup the other eventual debugs
|
||||
|
@ -948,7 +948,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p
|
|||
btVector3 initial_recover_motion(0, 0, 0);
|
||||
{ /// Phase one - multi shapes depenetration using margin
|
||||
for (int t(RECOVERING_MOVEMENT_CYCLES); 0 < t; --t) {
|
||||
if (!recover_from_penetration(p_body, body_transform, RECOVERING_MOVEMENT_SCALE, p_infinite_inertia, initial_recover_motion)) {
|
||||
if (!recover_from_penetration(p_body, body_transform, RECOVERING_MOVEMENT_SCALE, p_infinite_inertia, initial_recover_motion, nullptr, p_exclude)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1000,7 +1000,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p
|
|||
break;
|
||||
}
|
||||
|
||||
GodotKinClosestConvexResultCallback btResult(shape_world_from.getOrigin(), shape_world_to.getOrigin(), p_body, p_infinite_inertia);
|
||||
GodotKinClosestConvexResultCallback btResult(shape_world_from.getOrigin(), shape_world_to.getOrigin(), p_body, p_infinite_inertia, &p_exclude);
|
||||
btResult.m_collisionFilterGroup = p_body->get_collision_layer();
|
||||
btResult.m_collisionFilterMask = p_body->get_collision_mask();
|
||||
|
||||
|
@ -1023,7 +1023,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p
|
|||
btVector3 __rec(0, 0, 0);
|
||||
RecoverResult r_recover_result;
|
||||
|
||||
has_penetration = recover_from_penetration(p_body, body_transform, 1, p_infinite_inertia, __rec, &r_recover_result);
|
||||
has_penetration = recover_from_penetration(p_body, body_transform, 1, p_infinite_inertia, __rec, &r_recover_result, p_exclude);
|
||||
|
||||
// Parse results
|
||||
if (r_result) {
|
||||
|
@ -1173,7 +1173,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result) {
|
||||
bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result, const Set<RID> &p_exclude) {
|
||||
// Calculate the cumulative AABB of all shapes of the kinematic body
|
||||
btVector3 aabb_min, aabb_max;
|
||||
bool shapes_found = false;
|
||||
|
@ -1242,6 +1242,12 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran
|
|||
|
||||
for (int i = recover_broad_result.results.size() - 1; 0 <= i; --i) {
|
||||
btCollisionObject *otherObject = recover_broad_result.results[i].collision_object;
|
||||
|
||||
CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(otherObject->getUserPointer());
|
||||
if (p_exclude.has(gObj->get_self())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p_infinite_inertia && !otherObject->isStaticOrKinematicObject()) {
|
||||
otherObject->activate(); // Force activation of hitten rigid, soft body
|
||||
continue;
|
||||
|
|
|
@ -188,7 +188,7 @@ public:
|
|||
real_t get_linear_damp() const { return linear_damp; }
|
||||
real_t get_angular_damp() const { return angular_damp; }
|
||||
|
||||
bool test_body_motion(RigidBodyBullet *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes);
|
||||
bool test_body_motion(RigidBodyBullet *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude = Set<RID>());
|
||||
int test_ray_separation(RigidBodyBullet *p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin);
|
||||
|
||||
private:
|
||||
|
@ -209,7 +209,7 @@ private:
|
|||
RecoverResult() {}
|
||||
};
|
||||
|
||||
bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = nullptr);
|
||||
bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = nullptr, const Set<RID> &p_exclude = Set<RID>());
|
||||
/// This is an API that recover a kinematic object from penetration
|
||||
/// This allow only Convex Convex test and it always use GJK algorithm, With this API we don't benefit of Bullet special accelerated functions
|
||||
bool RFP_convex_convex_test(const btConvexShape *p_shapeA, const btConvexShape *p_shapeB, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = nullptr);
|
||||
|
|
|
@ -1075,7 +1075,7 @@ void CharacterBody2D::move_and_slide() {
|
|||
floor_normal = Vector2();
|
||||
floor_velocity = Vector2();
|
||||
|
||||
if (current_floor_velocity != Vector2()) {
|
||||
if (current_floor_velocity != Vector2() && on_floor_body.is_valid()) {
|
||||
PhysicsServer2D::MotionResult floor_result;
|
||||
Set<RID> exclude;
|
||||
exclude.insert(on_floor_body);
|
||||
|
|
|
@ -292,6 +292,8 @@ private:
|
|||
|
||||
Ref<KinematicCollision2D> _get_slide_collision(int p_bounce);
|
||||
|
||||
void _set_collision_direction(const PhysicsServer2D::MotionResult &p_result);
|
||||
|
||||
bool separate_raycast_shapes(PhysicsServer2D::MotionResult &r_result);
|
||||
|
||||
void set_safe_margin(real_t p_margin);
|
||||
|
@ -314,7 +316,6 @@ private:
|
|||
|
||||
const Vector2 &get_up_direction() const;
|
||||
void set_up_direction(const Vector2 &p_up_direction);
|
||||
void _set_collision_direction(const PhysicsServer2D::MotionResult &p_result);
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
|
|
|
@ -117,9 +117,9 @@ Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_motion, bool p_i
|
|||
return Ref<KinematicCollision3D>();
|
||||
}
|
||||
|
||||
bool PhysicsBody3D::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes, bool p_test_only, bool p_cancel_sliding) {
|
||||
bool PhysicsBody3D::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes, bool p_test_only, bool p_cancel_sliding, const Set<RID> &p_exclude) {
|
||||
Transform3D gt = get_global_transform();
|
||||
bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, p_margin, &r_result, p_exclude_raycast_shapes);
|
||||
bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, p_margin, &r_result, p_exclude_raycast_shapes, p_exclude);
|
||||
|
||||
// Restore direction of motion to be along original motion,
|
||||
// in order to avoid sliding due to recovery,
|
||||
|
@ -1090,6 +1090,9 @@ void CharacterBody3D::move_and_slide() {
|
|||
|
||||
bool was_on_floor = on_floor;
|
||||
|
||||
// Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky
|
||||
float delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time();
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (locked_axis & (1 << i)) {
|
||||
linear_velocity[i] = 0.0;
|
||||
|
@ -1097,7 +1100,7 @@ void CharacterBody3D::move_and_slide() {
|
|||
}
|
||||
|
||||
Vector3 current_floor_velocity = floor_velocity;
|
||||
if (on_floor && on_floor_body.is_valid()) {
|
||||
if ((on_floor || on_wall) && on_floor_body.is_valid()) {
|
||||
//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) {
|
||||
|
@ -1107,20 +1110,30 @@ void CharacterBody3D::move_and_slide() {
|
|||
}
|
||||
}
|
||||
|
||||
// Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky
|
||||
Vector3 motion = (floor_velocity + linear_velocity) * (Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time());
|
||||
|
||||
motion_results.clear();
|
||||
on_floor = false;
|
||||
on_floor_body = RID();
|
||||
on_ceiling = false;
|
||||
on_wall = false;
|
||||
motion_results.clear();
|
||||
floor_normal = Vector3();
|
||||
floor_velocity = Vector3();
|
||||
|
||||
if (current_floor_velocity != Vector3() && on_floor_body.is_valid()) {
|
||||
PhysicsServer3D::MotionResult floor_result;
|
||||
Set<RID> exclude;
|
||||
exclude.insert(on_floor_body);
|
||||
if (move_and_collide(current_floor_velocity * delta, infinite_inertia, floor_result, true, false, false, false, exclude)) {
|
||||
motion_results.push_back(floor_result);
|
||||
_set_collision_direction(floor_result);
|
||||
}
|
||||
}
|
||||
|
||||
on_floor_body = RID();
|
||||
Vector3 motion = linear_velocity * delta;
|
||||
|
||||
// No sliding on first attempt to keep floor motion stable when possible,
|
||||
// when stop on slope is enabled.
|
||||
bool sliding_enabled = !stop_on_slope;
|
||||
|
||||
for (int iteration = 0; iteration < max_slides; ++iteration) {
|
||||
PhysicsServer3D::MotionResult result;
|
||||
bool found_collision = false;
|
||||
|
@ -1144,35 +1157,19 @@ void CharacterBody3D::move_and_slide() {
|
|||
found_collision = true;
|
||||
|
||||
motion_results.push_back(result);
|
||||
_set_collision_direction(result);
|
||||
|
||||
if (up_direction == Vector3()) {
|
||||
//all is a wall
|
||||
on_wall = true;
|
||||
} else {
|
||||
if (Math::acos(result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor
|
||||
|
||||
on_floor = true;
|
||||
floor_normal = result.collision_normal;
|
||||
on_floor_body = result.collider;
|
||||
floor_velocity = result.collider_velocity;
|
||||
|
||||
if (stop_on_slope) {
|
||||
if ((body_velocity_normal + up_direction).length() < 0.01) {
|
||||
Transform3D gt = get_global_transform();
|
||||
if (result.motion.length() > margin) {
|
||||
gt.origin -= result.motion.slide(up_direction);
|
||||
} else {
|
||||
gt.origin -= result.motion;
|
||||
}
|
||||
set_global_transform(gt);
|
||||
linear_velocity = Vector3();
|
||||
return;
|
||||
}
|
||||
if (on_floor && stop_on_slope) {
|
||||
if ((body_velocity_normal + up_direction).length() < 0.01) {
|
||||
Transform3D gt = get_global_transform();
|
||||
if (result.motion.length() > margin) {
|
||||
gt.origin -= result.motion.slide(up_direction);
|
||||
} else {
|
||||
gt.origin -= result.motion;
|
||||
}
|
||||
} else if (Math::acos(result.collision_normal.dot(-up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling
|
||||
on_ceiling = true;
|
||||
} else {
|
||||
on_wall = true;
|
||||
set_global_transform(gt);
|
||||
linear_velocity = Vector3();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1198,6 +1195,11 @@ void CharacterBody3D::move_and_slide() {
|
|||
}
|
||||
}
|
||||
|
||||
if (!on_floor && !on_wall) {
|
||||
// Add last platform velocity when just left a moving platform.
|
||||
linear_velocity += current_floor_velocity;
|
||||
}
|
||||
|
||||
if (!was_on_floor || snap == Vector3()) {
|
||||
return;
|
||||
}
|
||||
|
@ -1233,6 +1235,29 @@ void CharacterBody3D::move_and_slide() {
|
|||
}
|
||||
}
|
||||
|
||||
void CharacterBody3D::_set_collision_direction(const PhysicsServer3D::MotionResult &p_result) {
|
||||
on_floor = false;
|
||||
on_ceiling = false;
|
||||
on_wall = false;
|
||||
if (up_direction == Vector3()) {
|
||||
//all is a wall
|
||||
on_wall = true;
|
||||
} else {
|
||||
if (Math::acos(p_result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor
|
||||
on_floor = true;
|
||||
floor_normal = p_result.collision_normal;
|
||||
on_floor_body = p_result.collider;
|
||||
floor_velocity = p_result.collider_velocity;
|
||||
} else if (Math::acos(p_result.collision_normal.dot(-up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling
|
||||
on_ceiling = true;
|
||||
} else {
|
||||
on_wall = true;
|
||||
on_floor_body = p_result.collider;
|
||||
floor_velocity = p_result.collider_velocity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CharacterBody3D::separate_raycast_shapes(PhysicsServer3D::MotionResult &r_result) {
|
||||
PhysicsServer3D::SeparationResult sep_res[8]; //max 8 rays
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ protected:
|
|||
Ref<KinematicCollision3D> _move(const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false, real_t p_margin = 0.001);
|
||||
|
||||
public:
|
||||
bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes = true, bool p_test_only = false, bool p_cancel_sliding = true);
|
||||
bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes = true, bool p_test_only = false, bool p_cancel_sliding = true, const Set<RID> &p_exclude = Set<RID>());
|
||||
bool test_move(const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001);
|
||||
|
||||
void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock);
|
||||
|
@ -298,6 +298,8 @@ private:
|
|||
|
||||
Ref<KinematicCollision3D> _get_slide_collision(int p_bounce);
|
||||
|
||||
void _set_collision_direction(const PhysicsServer3D::MotionResult &p_result);
|
||||
|
||||
bool separate_raycast_shapes(PhysicsServer3D::MotionResult &r_result);
|
||||
|
||||
void set_safe_margin(real_t p_margin);
|
||||
|
|
|
@ -854,7 +854,7 @@ void PhysicsServer3DSW::body_set_ray_pickable(RID p_body, bool p_enable) {
|
|||
body->set_ray_pickable(p_enable);
|
||||
}
|
||||
|
||||
bool PhysicsServer3DSW::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, MotionResult *r_result, bool p_exclude_raycast_shapes) {
|
||||
bool PhysicsServer3DSW::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude) {
|
||||
Body3DSW *body = body_owner.getornull(p_body);
|
||||
ERR_FAIL_COND_V(!body, false);
|
||||
ERR_FAIL_COND_V(!body->get_space(), false);
|
||||
|
@ -862,7 +862,7 @@ bool PhysicsServer3DSW::body_test_motion(RID p_body, const Transform3D &p_from,
|
|||
|
||||
_update_shapes();
|
||||
|
||||
return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes);
|
||||
return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes, p_exclude);
|
||||
}
|
||||
|
||||
int PhysicsServer3DSW::body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin) {
|
||||
|
|
|
@ -242,7 +242,7 @@ public:
|
|||
|
||||
virtual void body_set_ray_pickable(RID p_body, bool p_enable) override;
|
||||
|
||||
virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override;
|
||||
virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true, const Set<RID> &p_exclude = Set<RID>()) override;
|
||||
virtual int body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override;
|
||||
|
||||
// this function only works on physics process, errors and returns null otherwise
|
||||
|
|
|
@ -250,9 +250,9 @@ public:
|
|||
|
||||
FUNC2(body_set_ray_pickable, RID, bool);
|
||||
|
||||
bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override {
|
||||
bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true, const Set<RID> &p_exclude = Set<RID>()) override {
|
||||
ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false);
|
||||
return physics_3d_server->body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes);
|
||||
return physics_3d_server->body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes, p_exclude);
|
||||
}
|
||||
|
||||
int body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override {
|
||||
|
|
|
@ -720,7 +720,7 @@ int Space3DSW::test_body_ray_separation(Body3DSW *p_body, const Transform3D &p_t
|
|||
return rays_found;
|
||||
}
|
||||
|
||||
bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes) {
|
||||
bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude) {
|
||||
//give me back regular physics engine logic
|
||||
//this is madness
|
||||
//and most people using this function will think
|
||||
|
@ -801,6 +801,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
|
|||
|
||||
for (int i = 0; i < amount; i++) {
|
||||
const CollisionObject3DSW *col_obj = intersection_query_results[i];
|
||||
if (p_exclude.has(col_obj->get_self())) {
|
||||
continue;
|
||||
}
|
||||
int shape_idx = intersection_query_subindex_results[i];
|
||||
|
||||
if (CollisionObject3DSW::TYPE_BODY == col_obj->get_type()) {
|
||||
|
@ -890,6 +893,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
|
|||
|
||||
for (int i = 0; i < amount; i++) {
|
||||
const CollisionObject3DSW *col_obj = intersection_query_results[i];
|
||||
if (p_exclude.has(col_obj->get_self())) {
|
||||
continue;
|
||||
}
|
||||
int shape_idx = intersection_query_subindex_results[i];
|
||||
|
||||
if (CollisionObject3DSW::TYPE_BODY == col_obj->get_type()) {
|
||||
|
@ -1015,6 +1021,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
|
|||
|
||||
for (int i = 0; i < amount; i++) {
|
||||
const CollisionObject3DSW *col_obj = intersection_query_results[i];
|
||||
if (p_exclude.has(col_obj->get_self())) {
|
||||
continue;
|
||||
}
|
||||
int shape_idx = intersection_query_subindex_results[i];
|
||||
|
||||
if (CollisionObject3DSW::TYPE_BODY == col_obj->get_type()) {
|
||||
|
|
|
@ -204,7 +204,7 @@ public:
|
|||
uint64_t get_elapsed_time(ElapsedTime p_time) const { return elapsed_time[p_time]; }
|
||||
|
||||
int test_body_ray_separation(Body3DSW *p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin);
|
||||
bool test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes);
|
||||
bool test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude = Set<RID>());
|
||||
|
||||
Space3DSW();
|
||||
~Space3DSW();
|
||||
|
|
|
@ -447,12 +447,16 @@ void PhysicsTestMotionResult3D::_bind_methods() {
|
|||
|
||||
///////////////////////////////////////
|
||||
|
||||
bool PhysicsServer3D::_body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, const Ref<PhysicsTestMotionResult3D> &p_result) {
|
||||
bool PhysicsServer3D::_body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, const Ref<PhysicsTestMotionResult3D> &p_result, bool p_exclude_raycast_shapes, const Vector<RID> &p_exclude) {
|
||||
MotionResult *r = nullptr;
|
||||
if (p_result.is_valid()) {
|
||||
r = p_result->get_result_ptr();
|
||||
}
|
||||
return body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, p_margin, r);
|
||||
Set<RID> exclude;
|
||||
for (int i = 0; i < p_exclude.size(); i++) {
|
||||
exclude.insert(p_exclude[i]);
|
||||
}
|
||||
return body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, p_margin, r, p_exclude_raycast_shapes, exclude);
|
||||
}
|
||||
|
||||
RID PhysicsServer3D::shape_create(ShapeType p_shape) {
|
||||
|
@ -608,7 +612,7 @@ void PhysicsServer3D::_bind_methods() {
|
|||
|
||||
ClassDB::bind_method(D_METHOD("body_set_ray_pickable", "body", "enable"), &PhysicsServer3D::body_set_ray_pickable);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("body_test_motion", "body", "from", "motion", "infinite_inertia", "margin", "result"), &PhysicsServer3D::_body_test_motion, DEFVAL(0.001), DEFVAL(Variant()));
|
||||
ClassDB::bind_method(D_METHOD("body_test_motion", "body", "from", "motion", "infinite_inertia", "margin", "result", "exclude_raycast_shapes", "exclude"), &PhysicsServer3D::_body_test_motion, DEFVAL(0.001), DEFVAL(Variant()), DEFVAL(true), DEFVAL(Array()));
|
||||
|
||||
ClassDB::bind_method(D_METHOD("body_get_direct_state", "body"), &PhysicsServer3D::body_get_direct_state);
|
||||
|
||||
|
|
|
@ -212,7 +212,7 @@ class PhysicsServer3D : public Object {
|
|||
|
||||
static PhysicsServer3D *singleton;
|
||||
|
||||
virtual bool _body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, const Ref<PhysicsTestMotionResult3D> &p_result = Ref<PhysicsTestMotionResult3D>());
|
||||
virtual bool _body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, const Ref<PhysicsTestMotionResult3D> &p_result = Ref<PhysicsTestMotionResult3D>(), bool p_exclude_raycast_shapes = true, const Vector<RID> &p_exclude = Vector<RID>());
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
@ -491,7 +491,7 @@ public:
|
|||
Variant collider_metadata;
|
||||
};
|
||||
|
||||
virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) = 0;
|
||||
virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true, const Set<RID> &p_exclude = Set<RID>()) = 0;
|
||||
|
||||
struct SeparationResult {
|
||||
real_t collision_depth;
|
||||
|
|
Loading…
Reference in a new issue