Fix joints collision exceptions

Fix 3D joint handling of collision exceptions, so that they lose effect when the joint is not valid in every case; also some redundant code removed.

Also avoid trying to create the joint when not neither body A nor body B are set.

Make 2D joints be handled like their 3D counterparts, which adds the fixes to them while also removing duplicated code.

Fixes #2383.
This commit is contained in:
Pedro J. Estébanez 2017-08-29 23:15:12 +02:00
parent 213ca00e33
commit 4a98a59aa6
3 changed files with 59 additions and 92 deletions

View File

@ -31,19 +31,49 @@
#include "physics_body_2d.h"
#include "servers/physics_2d_server.h"
void Joint2D::_update_joint() {
if (!is_inside_tree())
return;
void Joint2D::_update_joint(bool p_only_free) {
if (joint.is_valid()) {
if (ba.is_valid() && bb.is_valid())
Physics2DServer::get_singleton()->body_remove_collision_exception(ba, bb);
Physics2DServer::get_singleton()->free(joint);
joint = RID();
ba = RID();
bb = RID();
}
joint = RID();
if (p_only_free || !is_inside_tree())
return;
Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)NULL;
Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)NULL;
if (!node_a || !node_b)
return;
PhysicsBody2D *body_a = node_a ? node_a->cast_to<PhysicsBody2D>() : (PhysicsBody2D *)NULL;
PhysicsBody2D *body_b = node_b ? node_b->cast_to<PhysicsBody2D>() : (PhysicsBody2D *)NULL;
if (!body_a || !body_b)
return;
if (!body_a) {
SWAP(body_a, body_b);
}
joint = _configure_joint(body_a, body_b);
if (!joint.is_valid())
return;
joint = _configure_joint();
Physics2DServer::get_singleton()->get_singleton()->joint_set_param(joint, Physics2DServer::JOINT_PARAM_BIAS, bias);
ba = body_a->get_rid();
bb = body_b->get_rid();
if (exclude_from_collision)
Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(), body_b->get_rid());
}
void Joint2D::set_node_a(const NodePath &p_node_a) {
@ -81,9 +111,7 @@ void Joint2D::_notification(int p_what) {
} break;
case NOTIFICATION_EXIT_TREE: {
if (joint.is_valid()) {
Physics2DServer::get_singleton()->free(joint);
joint = RID();
_update_joint(true);
}
} break;
}
@ -162,29 +190,8 @@ void PinJoint2D::_notification(int p_what) {
}
}
RID PinJoint2D::_configure_joint() {
RID PinJoint2D::_configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) {
Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)NULL;
Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)NULL;
if (!node_a && !node_b)
return RID();
PhysicsBody2D *body_a = node_a ? node_a->cast_to<PhysicsBody2D>() : (PhysicsBody2D *)NULL;
PhysicsBody2D *body_b = node_b ? node_b->cast_to<PhysicsBody2D>() : (PhysicsBody2D *)NULL;
if (!body_a && !body_b)
return RID();
if (!body_a) {
SWAP(body_a, body_b);
} else if (body_b) {
//add a collision exception between both
if (get_exclude_nodes_from_collision())
Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(), body_b->get_rid());
else
Physics2DServer::get_singleton()->body_remove_collision_exception(body_a->get_rid(), body_b->get_rid());
}
RID pj = Physics2DServer::get_singleton()->pin_joint_create(get_global_transform().get_origin(), body_a->get_rid(), body_b ? body_b->get_rid() : RID());
Physics2DServer::get_singleton()->pin_joint_set_param(pj, Physics2DServer::PIN_JOINT_SOFTNESS, softness);
return pj;
@ -239,24 +246,7 @@ void GrooveJoint2D::_notification(int p_what) {
}
}
RID GrooveJoint2D::_configure_joint() {
Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)NULL;
Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)NULL;
if (!node_a || !node_b)
return RID();
PhysicsBody2D *body_a = node_a->cast_to<PhysicsBody2D>();
PhysicsBody2D *body_b = node_b->cast_to<PhysicsBody2D>();
if (!body_a || !body_b)
return RID();
if (get_exclude_nodes_from_collision())
Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(), body_b->get_rid());
else
Physics2DServer::get_singleton()->body_remove_collision_exception(body_a->get_rid(), body_b->get_rid());
RID GrooveJoint2D::_configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) {
Matrix32 gt = get_global_transform();
Vector2 groove_A1 = gt.get_origin();
@ -328,24 +318,7 @@ void DampedSpringJoint2D::_notification(int p_what) {
}
}
RID DampedSpringJoint2D::_configure_joint() {
Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)NULL;
Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)NULL;
if (!node_a || !node_b)
return RID();
PhysicsBody2D *body_a = node_a->cast_to<PhysicsBody2D>();
PhysicsBody2D *body_b = node_b->cast_to<PhysicsBody2D>();
if (!body_a || !body_b)
return RID();
if (get_exclude_nodes_from_collision())
Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(), body_b->get_rid());
else
Physics2DServer::get_singleton()->body_remove_collision_exception(body_a->get_rid(), body_b->get_rid());
RID DampedSpringJoint2D::_configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) {
Matrix32 gt = get_global_transform();
Vector2 anchor_A = gt.get_origin();

View File

@ -32,11 +32,14 @@
#include "node_2d.h"
class PhysicsBody2D;
class Joint2D : public Node2D {
OBJ_TYPE(Joint2D, Node2D);
RID joint;
RID ba, bb;
NodePath a;
NodePath b;
@ -45,10 +48,10 @@ class Joint2D : public Node2D {
bool exclude_from_collision;
protected:
void _update_joint();
void _update_joint(bool p_only_free = false);
void _notification(int p_what);
virtual RID _configure_joint() = 0;
virtual RID _configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) = 0;
static void _bind_methods();
@ -77,7 +80,7 @@ class PinJoint2D : public Joint2D {
protected:
void _notification(int p_what);
virtual RID _configure_joint();
virtual RID _configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b);
static void _bind_methods();
public:
@ -96,7 +99,7 @@ class GrooveJoint2D : public Joint2D {
protected:
void _notification(int p_what);
virtual RID _configure_joint();
virtual RID _configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b);
static void _bind_methods();
public:
@ -120,7 +123,7 @@ class DampedSpringJoint2D : public Joint2D {
protected:
void _notification(int p_what);
virtual RID _configure_joint();
virtual RID _configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b);
static void _bind_methods();
public:

View File

@ -32,13 +32,8 @@
void Joint::_update_joint(bool p_only_free) {
if (joint.is_valid()) {
if (ba.is_valid() && bb.is_valid()) {
if (exclude_from_collision)
PhysicsServer::get_singleton()->body_add_collision_exception(ba, bb);
else
PhysicsServer::get_singleton()->body_remove_collision_exception(ba, bb);
}
if (ba.is_valid() && bb.is_valid())
PhysicsServer::get_singleton()->body_remove_collision_exception(ba, bb);
PhysicsServer::get_singleton()->free(joint);
joint = RID();
@ -52,33 +47,31 @@ void Joint::_update_joint(bool p_only_free) {
Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)NULL;
Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)NULL;
if (!node_a && !node_b)
if (!node_a || !node_b)
return;
PhysicsBody *body_a = node_a ? node_a->cast_to<PhysicsBody>() : (PhysicsBody *)NULL;
PhysicsBody *body_b = node_b ? node_b->cast_to<PhysicsBody>() : (PhysicsBody *)NULL;
if (!body_a && !body_b)
if (!body_a || !body_b)
return;
if (!body_a) {
SWAP(body_a, body_b);
} else if (body_b) {
//add a collision exception between both
PhysicsServer::get_singleton()->body_add_collision_exception(body_a->get_rid(), body_b->get_rid());
}
joint = _configure_joint(body_a, body_b);
if (joint.is_valid())
PhysicsServer::get_singleton()->joint_set_solver_priority(joint, solver_priority);
if (!joint.is_valid())
return;
if (body_b && joint.is_valid()) {
PhysicsServer::get_singleton()->joint_set_solver_priority(joint, solver_priority);
ba = body_a->get_rid();
bb = body_b->get_rid();
ba = body_a->get_rid();
bb = body_b->get_rid();
if (exclude_from_collision)
PhysicsServer::get_singleton()->body_add_collision_exception(body_a->get_rid(), body_b->get_rid());
}
}
void Joint::set_node_a(const NodePath &p_node_a) {
@ -129,8 +122,6 @@ void Joint::_notification(int p_what) {
case NOTIFICATION_EXIT_TREE: {
if (joint.is_valid()) {
_update_joint(true);
//PhysicsServer::get_singleton()->free(joint);
joint = RID();
}
} break;
}