Add support for collision layers and masks in CSG shapes

This commit is contained in:
meditator 2018-10-12 19:58:58 -04:00 committed by Rémi Verschelde
parent cf124b1415
commit 0059930644
3 changed files with 154 additions and 10 deletions

View file

@ -48,18 +48,76 @@ void CSGShape::set_use_collision(bool p_enable) {
PhysicsServer::get_singleton()->body_add_shape(root_collision_instance, root_collision_shape->get_rid());
PhysicsServer::get_singleton()->body_set_space(root_collision_instance, get_world()->get_space());
PhysicsServer::get_singleton()->body_attach_object_instance_id(root_collision_instance, get_instance_id());
set_collision_layer(collision_layer);
set_collision_mask(collision_mask);
_make_dirty(); //force update
} else {
PhysicsServer::get_singleton()->free(root_collision_instance);
root_collision_instance = RID();
root_collision_shape.unref();
}
_change_notify();
}
bool CSGShape::is_using_collision() const {
return use_collision;
}
void CSGShape::set_collision_layer(uint32_t p_layer) {
collision_layer = p_layer;
if (root_collision_instance.is_valid()) {
PhysicsServer::get_singleton()->body_set_collision_layer(root_collision_instance, p_layer);
}
}
uint32_t CSGShape::get_collision_layer() const {
return collision_layer;
}
void CSGShape::set_collision_mask(uint32_t p_mask) {
collision_mask = p_mask;
if (root_collision_instance.is_valid()) {
PhysicsServer::get_singleton()->body_set_collision_mask(root_collision_instance, p_mask);
}
}
uint32_t CSGShape::get_collision_mask() const {
return collision_mask;
}
void CSGShape::set_collision_mask_bit(int p_bit, bool p_value) {
uint32_t mask = get_collision_mask();
if (p_value)
mask |= 1 << p_bit;
else
mask &= ~(1 << p_bit);
set_collision_mask(mask);
}
bool CSGShape::get_collision_mask_bit(int p_bit) const {
return get_collision_mask() & (1 << p_bit);
}
void CSGShape::set_collision_layer_bit(int p_bit, bool p_value) {
uint32_t mask = get_collision_layer();
if (p_value)
mask |= 1 << p_bit;
else
mask &= ~(1 << p_bit);
set_collision_layer(mask);
}
bool CSGShape::get_collision_layer_bit(int p_bit) const {
return get_collision_layer() & (1 << p_bit);
}
bool CSGShape::is_root_shape() const {
return !parent;
@ -459,6 +517,8 @@ void CSGShape::_notification(int p_what) {
PhysicsServer::get_singleton()->body_add_shape(root_collision_instance, root_collision_shape->get_rid());
PhysicsServer::get_singleton()->body_set_space(root_collision_instance, get_world()->get_space());
PhysicsServer::get_singleton()->body_attach_object_instance_id(root_collision_instance, get_instance_id());
set_collision_layer(collision_layer);
set_collision_mask(collision_mask);
}
_make_dirty();
@ -477,7 +537,7 @@ void CSGShape::_notification(int p_what) {
parent->_make_dirty();
parent = NULL;
if (use_collision && is_root_shape()) {
if (use_collision && is_root_shape() && root_collision_instance.is_valid()) {
PhysicsServer::get_singleton()->free(root_collision_instance);
root_collision_instance = RID();
root_collision_shape.unref();
@ -506,9 +566,12 @@ bool CSGShape::is_calculating_tangents() const {
}
void CSGShape::_validate_property(PropertyInfo &property) const {
if (is_inside_tree() && property.name.begins_with("use_collision") && !is_root_shape()) {
bool is_collision_prefixed = property.name.begins_with("collision_");
if ((is_collision_prefixed || property.name.begins_with("use_collision")) && is_inside_tree() && !is_root_shape()) {
//hide collision if not root
property.usage = PROPERTY_USAGE_NOEDITOR;
} else if (is_collision_prefixed && !bool(get("use_collision"))) {
property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
}
}
@ -520,34 +583,52 @@ void CSGShape::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_operation", "operation"), &CSGShape::set_operation);
ClassDB::bind_method(D_METHOD("get_operation"), &CSGShape::get_operation);
ClassDB::bind_method(D_METHOD("set_snap", "snap"), &CSGShape::set_snap);
ClassDB::bind_method(D_METHOD("get_snap"), &CSGShape::get_snap);
ClassDB::bind_method(D_METHOD("set_use_collision", "operation"), &CSGShape::set_use_collision);
ClassDB::bind_method(D_METHOD("is_using_collision"), &CSGShape::is_using_collision);
ClassDB::bind_method(D_METHOD("set_snap", "snap"), &CSGShape::set_snap);
ClassDB::bind_method(D_METHOD("get_snap"), &CSGShape::get_snap);
ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &CSGShape::set_collision_layer);
ClassDB::bind_method(D_METHOD("get_collision_layer"), &CSGShape::get_collision_layer);
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &CSGShape::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &CSGShape::get_collision_mask);
ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &CSGShape::set_collision_mask_bit);
ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &CSGShape::get_collision_mask_bit);
ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &CSGShape::set_collision_layer_bit);
ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &CSGShape::get_collision_layer_bit);
ClassDB::bind_method(D_METHOD("set_calculate_tangents", "enabled"), &CSGShape::set_calculate_tangents);
ClassDB::bind_method(D_METHOD("is_calculating_tangents"), &CSGShape::is_calculating_tangents);
ADD_PROPERTY(PropertyInfo(Variant::INT, "operation", PROPERTY_HINT_ENUM, "Union,Intersection,Subtraction"), "set_operation", "get_operation");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_collision"), "set_use_collision", "is_using_collision");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "snap", PROPERTY_HINT_RANGE, "0.0001,1,0.001"), "set_snap", "get_snap");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "calculate_tangents"), "set_calculate_tangents", "is_calculating_tangents");
ADD_GROUP("Collision", "collision_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_collision"), "set_use_collision", "is_using_collision");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
BIND_ENUM_CONSTANT(OPERATION_UNION);
BIND_ENUM_CONSTANT(OPERATION_INTERSECTION);
BIND_ENUM_CONSTANT(OPERATION_SUBTRACTION);
}
CSGShape::CSGShape() {
brush = NULL;
set_notify_local_transform(true);
dirty = false;
parent = NULL;
use_collision = false;
operation = OPERATION_UNION;
parent = NULL;
brush = NULL;
dirty = false;
snap = 0.001;
use_collision = false;
collision_layer = 1;
collision_mask = 1;
calculate_tangents = true;
set_notify_local_transform(true);
}
CSGShape::~CSGShape() {

View file

@ -61,6 +61,8 @@ private:
float snap;
bool use_collision;
uint32_t collision_layer;
uint32_t collision_mask;
Ref<ConcavePolygonShape> root_collision_shape;
RID root_collision_instance;
@ -126,6 +128,18 @@ public:
void set_use_collision(bool p_enable);
bool is_using_collision() const;
void set_collision_layer(uint32_t p_layer);
uint32_t get_collision_layer() const;
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
void set_collision_layer_bit(int p_bit, bool p_value);
bool get_collision_layer_bit(int p_bit) const;
void set_collision_mask_bit(int p_bit, bool p_value);
bool get_collision_mask_bit(int p_bit) const;
void set_snap(float p_snap);
float get_snap() const;

View file

@ -18,6 +18,46 @@
Returns true if this is a root shape and is thus the object that is rendered.
</description>
</method>
<method name="get_collision_layer_bit" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="bit" type="int">
</argument>
<description>
Returns an individual bit on the collision mask.
</description>
</method>
<method name="get_collision_mask_bit" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="bit" type="int">
</argument>
<description>
Returns an individual bit on the collision mask.
</description>
</method>
<method name="set_collision_layer_bit">
<return type="void">
</return>
<argument index="0" name="bit" type="int">
</argument>
<argument index="1" name="value" type="bool">
</argument>
<description>
Sets individual bits on the layer mask. Use this if you only need to change one layer's value.
</description>
</method>
<method name="set_collision_mask_bit">
<return type="void">
</return>
<argument index="0" name="bit" type="int">
</argument>
<argument index="1" name="value" type="bool">
</argument>
<description>
Sets individual bits on the collision mask. Use this if you only need to change one layer's value.
</description>
</method>
</methods>
<members>
<member name="calculate_tangents" type="bool" setter="set_calculate_tangents" getter="is_calculating_tangents">
@ -31,6 +71,15 @@
<member name="use_collision" type="bool" setter="set_use_collision" getter="is_using_collision">
Adds a collision shape to the physics engine for our CSG shape. This will always act like a static body. Note that the collision shape is still active even if the CSG shape itself is hidden.
</member>
<member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer">
The physics layers this area is in.
Collidable objects can exist in any of 32 different layers. These layers work like a tagging system, and are not visual. A collidable can use these layers to select with which objects it can collide, using the collision_mask property.
A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A.
</member>
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask">
The physics layers this CSG shape scans for collisions.
</member>
</members>
</members>
<constants>
<constant name="OPERATION_UNION" value="0" enum="Operation">