Merge pull request #64343 from TokageItLab/priority-ph
This commit is contained in:
@@ -196,6 +196,9 @@ void PhysicsServer3DExtension::_bind_methods() {
|
||||
GDVIRTUAL_BIND(_body_set_collision_mask, "body", "mask");
|
||||
GDVIRTUAL_BIND(_body_get_collision_mask, "body");
|
||||
|
||||
GDVIRTUAL_BIND(_body_set_collision_priority, "body", "priority");
|
||||
GDVIRTUAL_BIND(_body_get_collision_priority, "body");
|
||||
|
||||
GDVIRTUAL_BIND(_body_add_shape, "body", "shape", "transform", "disabled");
|
||||
GDVIRTUAL_BIND(_body_set_shape, "body", "shape_idx", "shape");
|
||||
GDVIRTUAL_BIND(_body_set_shape_transform, "body", "shape_idx", "transform");
|
||||
|
||||
@@ -319,6 +319,9 @@ public:
|
||||
EXBIND2(body_set_collision_mask, RID, uint32_t)
|
||||
EXBIND1RC(uint32_t, body_get_collision_mask, RID)
|
||||
|
||||
EXBIND2(body_set_collision_priority, RID, real_t)
|
||||
EXBIND1RC(real_t, body_get_collision_priority, RID)
|
||||
|
||||
EXBIND2(body_set_user_flags, RID, uint32_t)
|
||||
EXBIND1RC(uint32_t, body_get_user_flags, RID)
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@ private:
|
||||
Transform2D inv_transform;
|
||||
uint32_t collision_mask = 1;
|
||||
uint32_t collision_layer = 1;
|
||||
real_t collision_priority = 1.0;
|
||||
bool _static = true;
|
||||
|
||||
SelfList<GodotCollisionObject2D> pending_shape_update_list;
|
||||
@@ -166,6 +167,13 @@ public:
|
||||
}
|
||||
_FORCE_INLINE_ uint32_t get_collision_layer() const { return collision_layer; }
|
||||
|
||||
_FORCE_INLINE_ void set_collision_priority(real_t p_priority) {
|
||||
ERR_FAIL_COND_MSG(p_priority <= 0, "Priority must be greater than 0.");
|
||||
collision_priority = p_priority;
|
||||
_shape_changed();
|
||||
}
|
||||
_FORCE_INLINE_ real_t get_collision_priority() const { return collision_priority; }
|
||||
|
||||
void remove_shape(GodotShape2D *p_shape) override;
|
||||
void remove_shape(int p_index);
|
||||
|
||||
|
||||
@@ -718,6 +718,20 @@ uint32_t GodotPhysicsServer2D::body_get_collision_mask(RID p_body) const {
|
||||
return body->get_collision_mask();
|
||||
}
|
||||
|
||||
void GodotPhysicsServer2D::body_set_collision_priority(RID p_body, real_t p_priority) {
|
||||
GodotBody2D *body = body_owner.get_or_null(p_body);
|
||||
ERR_FAIL_COND(!body);
|
||||
|
||||
body->set_collision_priority(p_priority);
|
||||
}
|
||||
|
||||
real_t GodotPhysicsServer2D::body_get_collision_priority(RID p_body) const {
|
||||
const GodotBody2D *body = body_owner.get_or_null(p_body);
|
||||
ERR_FAIL_COND_V(!body, 0);
|
||||
|
||||
return body->get_collision_priority();
|
||||
}
|
||||
|
||||
void GodotPhysicsServer2D::body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) {
|
||||
GodotBody2D *body = body_owner.get_or_null(p_body);
|
||||
ERR_FAIL_COND(!body);
|
||||
|
||||
@@ -199,6 +199,9 @@ public:
|
||||
virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) override;
|
||||
virtual uint32_t body_get_collision_mask(RID p_body) const override;
|
||||
|
||||
virtual void body_set_collision_priority(RID p_body, real_t p_priority) override;
|
||||
virtual real_t body_get_collision_priority(RID p_body) const override;
|
||||
|
||||
virtual void body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) override;
|
||||
virtual Variant body_get_param(RID p_body, BodyParameter p_param) const override;
|
||||
|
||||
|
||||
@@ -594,6 +594,7 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D::
|
||||
const int max_results = 32;
|
||||
int recover_attempts = 4;
|
||||
Vector2 sr[max_results * 2];
|
||||
real_t priorities[max_results];
|
||||
|
||||
do {
|
||||
GodotPhysicsServer2D::CollCbkData cbk;
|
||||
@@ -606,6 +607,7 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D::
|
||||
|
||||
GodotPhysicsServer2D::CollCbkData *cbkptr = &cbk;
|
||||
GodotCollisionSolver2D::CallbackResult cbkres = GodotPhysicsServer2D::_shape_col_cbk;
|
||||
int priority_amount = 0;
|
||||
|
||||
bool collided = false;
|
||||
|
||||
@@ -664,6 +666,10 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D::
|
||||
if (GodotCollisionSolver2D::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, nullptr, margin)) {
|
||||
did_collide = cbk.passed > current_passed; //more passed, so collision actually existed
|
||||
}
|
||||
while (cbk.amount > priority_amount) {
|
||||
priorities[priority_amount] = col_obj->get_collision_priority();
|
||||
priority_amount++;
|
||||
}
|
||||
|
||||
if (!did_collide && cbk.invalid_by_dir > 0) {
|
||||
//this shape must be excluded
|
||||
@@ -686,6 +692,12 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D::
|
||||
break;
|
||||
}
|
||||
|
||||
real_t inv_total_weight = 0.0;
|
||||
for (int i = 0; i < cbk.amount; i++) {
|
||||
inv_total_weight += priorities[i];
|
||||
}
|
||||
inv_total_weight = Math::is_zero_approx(inv_total_weight) ? 1.0 : (real_t)cbk.amount / inv_total_weight;
|
||||
|
||||
recovered = true;
|
||||
|
||||
Vector2 recover_motion;
|
||||
@@ -701,7 +713,7 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D::
|
||||
real_t depth = n.dot(a + recover_motion) - d;
|
||||
if (depth > min_contact_depth + CMP_EPSILON) {
|
||||
// Only recover if there is penetration.
|
||||
recover_motion -= n * (depth - min_contact_depth) * 0.4;
|
||||
recover_motion -= n * (depth - min_contact_depth) * 0.4 * priorities[i] * inv_total_weight;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ private:
|
||||
ObjectID instance_id;
|
||||
uint32_t collision_layer = 1;
|
||||
uint32_t collision_mask = 1;
|
||||
real_t collision_priority = 1.0;
|
||||
|
||||
struct Shape {
|
||||
Transform3D xform;
|
||||
@@ -165,6 +166,13 @@ public:
|
||||
}
|
||||
_FORCE_INLINE_ uint32_t get_collision_mask() const { return collision_mask; }
|
||||
|
||||
_FORCE_INLINE_ void set_collision_priority(real_t p_priority) {
|
||||
ERR_FAIL_COND_MSG(p_priority <= 0, "Priority must be greater than 0.");
|
||||
collision_priority = p_priority;
|
||||
_shape_changed();
|
||||
}
|
||||
_FORCE_INLINE_ real_t get_collision_priority() const { return collision_priority; }
|
||||
|
||||
_FORCE_INLINE_ bool collides_with(GodotCollisionObject3D *p_other) const {
|
||||
return p_other->collision_layer & collision_mask;
|
||||
}
|
||||
|
||||
@@ -593,6 +593,20 @@ uint32_t GodotPhysicsServer3D::body_get_collision_mask(RID p_body) const {
|
||||
return body->get_collision_mask();
|
||||
}
|
||||
|
||||
void GodotPhysicsServer3D::body_set_collision_priority(RID p_body, real_t p_priority) {
|
||||
GodotBody3D *body = body_owner.get_or_null(p_body);
|
||||
ERR_FAIL_COND(!body);
|
||||
|
||||
body->set_collision_priority(p_priority);
|
||||
}
|
||||
|
||||
real_t GodotPhysicsServer3D::body_get_collision_priority(RID p_body) const {
|
||||
const GodotBody3D *body = body_owner.get_or_null(p_body);
|
||||
ERR_FAIL_COND_V(!body, 0);
|
||||
|
||||
return body->get_collision_priority();
|
||||
}
|
||||
|
||||
void GodotPhysicsServer3D::body_attach_object_instance_id(RID p_body, ObjectID p_id) {
|
||||
GodotBody3D *body = body_owner.get_or_null(p_body);
|
||||
if (body) {
|
||||
|
||||
@@ -192,6 +192,9 @@ public:
|
||||
virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) override;
|
||||
virtual uint32_t body_get_collision_mask(RID p_body) const override;
|
||||
|
||||
virtual void body_set_collision_priority(RID p_body, real_t p_priority) override;
|
||||
virtual real_t body_get_collision_priority(RID p_body) const override;
|
||||
|
||||
virtual void body_set_user_flags(RID p_body, uint32_t p_flags) override;
|
||||
virtual uint32_t body_get_user_flags(RID p_body) const override;
|
||||
|
||||
|
||||
@@ -701,6 +701,7 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
|
||||
const int max_results = 32;
|
||||
int recover_attempts = 4;
|
||||
Vector3 sr[max_results * 2];
|
||||
real_t priorities[max_results];
|
||||
|
||||
do {
|
||||
GodotPhysicsServer3D::CollCbkData cbk;
|
||||
@@ -710,6 +711,7 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
|
||||
|
||||
GodotPhysicsServer3D::CollCbkData *cbkptr = &cbk;
|
||||
GodotCollisionSolver3D::CallbackResult cbkres = GodotPhysicsServer3D::_shape_col_cbk;
|
||||
int priority_amount = 0;
|
||||
|
||||
bool collided = false;
|
||||
|
||||
@@ -737,6 +739,10 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
|
||||
if (GodotCollisionSolver3D::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), cbkres, cbkptr, nullptr, margin)) {
|
||||
collided = cbk.amount > 0;
|
||||
}
|
||||
while (cbk.amount > priority_amount) {
|
||||
priorities[priority_amount] = col_obj->get_collision_priority();
|
||||
priority_amount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -744,6 +750,12 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
|
||||
break;
|
||||
}
|
||||
|
||||
real_t inv_total_weight = 0.0;
|
||||
for (int i = 0; i < cbk.amount; i++) {
|
||||
inv_total_weight += priorities[i];
|
||||
}
|
||||
inv_total_weight = Math::is_zero_approx(inv_total_weight) ? 1.0 : (real_t)cbk.amount / inv_total_weight;
|
||||
|
||||
recovered = true;
|
||||
|
||||
Vector3 recover_motion;
|
||||
@@ -759,7 +771,7 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
|
||||
real_t depth = n.dot(a + recover_motion) - d;
|
||||
if (depth > min_contact_depth + CMP_EPSILON) {
|
||||
// Only recover if there is penetration.
|
||||
recover_motion -= n * (depth - min_contact_depth) * 0.4;
|
||||
recover_motion -= n * (depth - min_contact_depth) * 0.4 * priorities[i] * inv_total_weight;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -706,6 +706,9 @@ void PhysicsServer2D::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("body_set_collision_mask", "body", "mask"), &PhysicsServer2D::body_set_collision_mask);
|
||||
ClassDB::bind_method(D_METHOD("body_get_collision_mask", "body"), &PhysicsServer2D::body_get_collision_mask);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("body_set_collision_priority", "body", "priority"), &PhysicsServer2D::body_set_collision_priority);
|
||||
ClassDB::bind_method(D_METHOD("body_get_collision_priority", "body"), &PhysicsServer2D::body_get_collision_priority);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("body_set_param", "body", "param", "value"), &PhysicsServer2D::body_set_param);
|
||||
ClassDB::bind_method(D_METHOD("body_get_param", "body", "param"), &PhysicsServer2D::body_get_param);
|
||||
|
||||
|
||||
@@ -393,6 +393,9 @@ public:
|
||||
virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) = 0;
|
||||
virtual uint32_t body_get_collision_mask(RID p_body) const = 0;
|
||||
|
||||
virtual void body_set_collision_priority(RID p_body, real_t p_priority) = 0;
|
||||
virtual real_t body_get_collision_priority(RID p_body) const = 0;
|
||||
|
||||
// common body variables
|
||||
enum BodyParameter {
|
||||
BODY_PARAM_BOUNCE,
|
||||
|
||||
@@ -205,6 +205,9 @@ public:
|
||||
FUNC2(body_set_collision_mask, RID, uint32_t);
|
||||
FUNC1RC(uint32_t, body_get_collision_mask, RID);
|
||||
|
||||
FUNC2(body_set_collision_priority, RID, real_t);
|
||||
FUNC1RC(real_t, body_get_collision_priority, RID);
|
||||
|
||||
FUNC3(body_set_param, RID, BodyParameter, const Variant &);
|
||||
FUNC2RC(Variant, body_get_param, RID, BodyParameter);
|
||||
|
||||
|
||||
@@ -750,6 +750,9 @@ void PhysicsServer3D::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("body_set_collision_mask", "body", "mask"), &PhysicsServer3D::body_set_collision_mask);
|
||||
ClassDB::bind_method(D_METHOD("body_get_collision_mask", "body"), &PhysicsServer3D::body_get_collision_mask);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("body_set_collision_priority", "body", "priority"), &PhysicsServer3D::body_set_collision_priority);
|
||||
ClassDB::bind_method(D_METHOD("body_get_collision_priority", "body"), &PhysicsServer3D::body_get_collision_priority);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("body_add_shape", "body", "shape", "transform", "disabled"), &PhysicsServer3D::body_add_shape, DEFVAL(Transform3D()), DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("body_set_shape", "body", "shape_idx", "shape"), &PhysicsServer3D::body_set_shape);
|
||||
ClassDB::bind_method(D_METHOD("body_set_shape_transform", "body", "shape_idx", "transform"), &PhysicsServer3D::body_set_shape_transform);
|
||||
|
||||
@@ -421,6 +421,9 @@ public:
|
||||
virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) = 0;
|
||||
virtual uint32_t body_get_collision_mask(RID p_body) const = 0;
|
||||
|
||||
virtual void body_set_collision_priority(RID p_body, real_t p_priority) = 0;
|
||||
virtual real_t body_get_collision_priority(RID p_body) const = 0;
|
||||
|
||||
virtual void body_set_user_flags(RID p_body, uint32_t p_flags) = 0;
|
||||
virtual uint32_t body_get_user_flags(RID p_body) const = 0;
|
||||
|
||||
|
||||
@@ -202,6 +202,9 @@ public:
|
||||
FUNC2(body_set_collision_mask, RID, uint32_t);
|
||||
FUNC1RC(uint32_t, body_get_collision_mask, RID);
|
||||
|
||||
FUNC2(body_set_collision_priority, RID, real_t);
|
||||
FUNC1RC(real_t, body_get_collision_priority, RID);
|
||||
|
||||
FUNC2(body_set_user_flags, RID, uint32_t);
|
||||
FUNC1RC(uint32_t, body_get_user_flags, RID);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user