diff --git a/modules/props/SCsub b/modules/props/SCsub index 6ea2fea19..d25ced7e7 100644 --- a/modules/props/SCsub +++ b/modules/props/SCsub @@ -21,6 +21,8 @@ sources = [ "props/prop_data_light.cpp", "props/prop_data_prop.cpp", "props/prop_data_tiled_wall.cpp", + "props/prop_data_collision_object.cpp", + "props/prop_data_static_body.cpp", "clutter/ground_clutter.cpp", "clutter/ground_clutter_foliage.cpp", diff --git a/modules/props/config.py b/modules/props/config.py index ff76bfb39..4d62fe4b2 100644 --- a/modules/props/config.py +++ b/modules/props/config.py @@ -17,6 +17,8 @@ def get_doc_classes(): "PropDataPortal", "PropDataTiledWall", "PropData", + "PropDataCollisionObject", + "PropDataStaticBody", "TiledWall", "TiledWallData", diff --git a/modules/props/props/prop_data_collision_object.cpp b/modules/props/props/prop_data_collision_object.cpp new file mode 100644 index 000000000..56b84e290 --- /dev/null +++ b/modules/props/props/prop_data_collision_object.cpp @@ -0,0 +1,205 @@ +/* +Copyright (c) 2019-2023 Péter Magyar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "prop_data_collision_object.h" + +#include "prop_data.h" + +#include "scene/3d/collision_shape.h" +#include "scene/3d/physics_body.h" + +uint32_t PropDataCollisionObject::get_collision_layer() const { + return _collision_layer; +} +void PropDataCollisionObject::set_collision_layer(const uint32_t p_layer) { + _collision_layer = p_layer; +} + +uint32_t PropDataCollisionObject::get_collision_mask() const { + return _collision_mask; +} +void PropDataCollisionObject::set_collision_mask(const uint32_t p_mask) { + _collision_mask = p_mask; +} + +int PropDataCollisionObject::get_collision_shape_count() const { + return _shapes.size(); +} +void PropDataCollisionObject::set_collision_shape_count(const int p_count) { + _shapes.resize(p_count); +} + +Transform PropDataCollisionObject::get_collision_shape_transform(const int p_index) const { + ERR_FAIL_INDEX_V(p_index, _shapes.size(), Transform()); + + return _shapes[p_index].transform; +} +void PropDataCollisionObject::set_collision_shape_transform(const int p_index, const Transform &p_transform) { + ERR_FAIL_INDEX(p_index, _shapes.size()); + + _shapes.write[p_index].transform = p_transform; +} + +Ref PropDataCollisionObject::get_collision_shape(const int p_index) const { + ERR_FAIL_INDEX_V(p_index, _shapes.size(), Ref()); + + return _shapes[p_index].shape; +} +void PropDataCollisionObject::set_collision_shape(const int p_index, const Ref &p_shape) { + ERR_FAIL_INDEX(p_index, _shapes.size()); + + _shapes.write[p_index].shape = p_shape; +} + +void PropDataCollisionObject::add_collision_shape(const Transform &p_transform, const Ref &p_shape) { + ShapeEntry e; + e.transform = p_transform; + e.shape = p_shape; + _shapes.push_back(e); +} +void PropDataCollisionObject::remove_collision_shape(const int p_index) { + ERR_FAIL_INDEX(p_index, _shapes.size()); + + _shapes.remove(p_index); +} + +bool PropDataCollisionObject::_processor_evaluate_children() { + return false; +} + +void PropDataCollisionObject::processor_process_collision_objects(Node *node, const Transform &transform) { + int cc = node->get_child_count(); + for (int i = 0; i < cc; ++i) { + Node *c = node->get_child(i); + + CollisionShape *cs = Object::cast_to(c); + + if (!cs) { + continue; + } + + Transform current_transform = transform * cs->get_transform(); + Ref shape = cs->get_shape(); + + if (shape.is_valid()) { + add_collision_shape(current_transform, shape); + } + + if (c->get_child_count() > 0) { + processor_process_collision_objects(c, current_transform); + } + } +} + +void PropDataCollisionObject::processor_create_shapes_for(Node *root) { + for (int i = 0; i < _shapes.size(); ++i) { + const ShapeEntry &e = _shapes[i]; + + if (!e.shape.is_valid()) { + continue; + } + + CollisionShape *cs = memnew(CollisionShape); + cs->set_transform(e.transform); + cs->set_shape(e.shape); + root->add_child(cs); + } +} + +PropDataCollisionObject::PropDataCollisionObject() { + _collision_layer = 0; + _collision_mask = 0; +} +PropDataCollisionObject::~PropDataCollisionObject() { +} + +bool PropDataCollisionObject::_set(const StringName &p_name, const Variant &p_value) { + String p = p_name; + + if (!p.begins_with("shapes/")) { + return false; + } + + int index = p.get_slicec('/', 1).to_int(); + + String prop = p.get_slicec('/', 2); + + if (prop == "transform") { + _shapes.write[index].transform = p_value; + return true; + } else if (prop == "shape") { + _shapes.write[index].shape = p_value; + return true; + } + + return false; +} +bool PropDataCollisionObject::_get(const StringName &p_name, Variant &r_ret) const { + String p = p_name; + + if (!p.begins_with("shapes/")) { + return false; + } + + int index = p.get_slicec('/', 1).to_int(); + + String prop = p.get_slicec('/', 2); + + if (prop == "transform") { + r_ret = _shapes[index].transform; + return true; + } else if (prop == "shape") { + r_ret = _shapes[index].shape; + return true; + } + + return false; +} +void PropDataCollisionObject::_get_property_list(List *p_list) const { + for (int i = 0; i < _shapes.size(); ++i) { + p_list->push_back(PropertyInfo(Variant::TRANSFORM, "shapes/" + itos(i) + "/transform")); + p_list->push_back(PropertyInfo(Variant::OBJECT, "shapes/" + itos(i) + "/shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape")); + } +} + +void PropDataCollisionObject::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_collision_layer"), &PropDataCollisionObject::get_collision_layer); + ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &PropDataCollisionObject::set_collision_layer); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer"); + + ClassDB::bind_method(D_METHOD("get_collision_mask"), &PropDataCollisionObject::get_collision_mask); + ClassDB::bind_method(D_METHOD("set_collision_mask", "value"), &PropDataCollisionObject::set_collision_mask); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); + + ClassDB::bind_method(D_METHOD("get_collision_shape_count"), &PropDataCollisionObject::get_collision_shape_count); + ClassDB::bind_method(D_METHOD("set_collision_shape_count", "value"), &PropDataCollisionObject::set_collision_shape_count); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_shape_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_collision_shape_count", "get_collision_shape_count"); + + ClassDB::bind_method(D_METHOD("get_collision_shape_transform"), &PropDataCollisionObject::get_collision_shape_transform); + ClassDB::bind_method(D_METHOD("set_collision_shape_transform", "index", "transform"), &PropDataCollisionObject::set_collision_shape_transform); + + ClassDB::bind_method(D_METHOD("get_collision_shape"), &PropDataCollisionObject::get_collision_shape); + ClassDB::bind_method(D_METHOD("set_collision_shape", "index", "shape"), &PropDataCollisionObject::set_collision_shape); + + ClassDB::bind_method(D_METHOD("add_collision_shape", "transform", "shape"), &PropDataCollisionObject::add_collision_shape); + ClassDB::bind_method(D_METHOD("remove_collision_shape", "index"), &PropDataCollisionObject::remove_collision_shape); +} diff --git a/modules/props/props/prop_data_collision_object.h b/modules/props/props/prop_data_collision_object.h new file mode 100644 index 000000000..dcc94638b --- /dev/null +++ b/modules/props/props/prop_data_collision_object.h @@ -0,0 +1,77 @@ +#ifndef PROP_DATA_COLLISION_OBJECT_H +#define PROP_DATA_COLLISION_OBJECT_H + +/* +Copyright (c) 2023-present Péter Magyar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "prop_data_entry.h" + +class Shape; + +class PropDataCollisionObject : public PropDataEntry { + GDCLASS(PropDataCollisionObject, PropDataEntry); + +public: + uint32_t get_collision_layer() const; + void set_collision_layer(const uint32_t p_layer); + + uint32_t get_collision_mask() const; + void set_collision_mask(const uint32_t p_mask); + + int get_collision_shape_count() const; + void set_collision_shape_count(const int p_count); + + Transform get_collision_shape_transform(const int p_index) const; + void set_collision_shape_transform(const int p_index, const Transform &p_transform); + + Ref get_collision_shape(const int p_index) const; + void set_collision_shape(const int p_index, const Ref &p_shape); + + void add_collision_shape(const Transform &p_transform, const Ref &p_shape); + void remove_collision_shape(const int p_index); + + bool _processor_evaluate_children(); + + void processor_process_collision_objects(Node *node, const Transform &transform); + void processor_create_shapes_for(Node *root); + + PropDataCollisionObject(); + ~PropDataCollisionObject(); + +protected: + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List *p_list) const; + + static void _bind_methods(); + + struct ShapeEntry { + Transform transform; + Ref shape; + }; + + uint32_t _collision_layer; + uint32_t _collision_mask; + Vector _shapes; +}; + +#endif diff --git a/modules/props/props/prop_data_static_body.cpp b/modules/props/props/prop_data_static_body.cpp new file mode 100644 index 000000000..1a1477d37 --- /dev/null +++ b/modules/props/props/prop_data_static_body.cpp @@ -0,0 +1,103 @@ +/* +Copyright (c) 2019-2023 Péter Magyar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "prop_data_static_body.h" + +#include "prop_data.h" + +#include "scene/3d/physics_body.h" +#include "scene/resources/physics_material.h" + +Ref PropDataStaticBody::get_physics_material_override() const { + return _physics_material_override; +} +void PropDataStaticBody::set_physics_material_override(const Ref &p_material) { + _physics_material_override = p_material; +} + +Vector3 PropDataStaticBody::get_constant_linear_velocity() const { + return _constant_linear_velocity; +} +void PropDataStaticBody::set_constant_linear_velocity(const Vector3 &p_value) { + _constant_linear_velocity = p_value; +} + +Vector3 PropDataStaticBody::get_constant_angular_velocity() const { + return _constant_angular_velocity; +} +void PropDataStaticBody::set_constant_angular_velocity(const Vector3 &p_value) { + _constant_angular_velocity = p_value; +} + +bool PropDataStaticBody::_processor_handles(Node *node) { + return Object::cast_to(node); +} + +void PropDataStaticBody::_processor_process(Ref prop_data, Node *node, const Transform &transform) { + StaticBody *sb = Object::cast_to(node); + + Ref c; + c.instance(); + + c->set_physics_material_override(sb->get_physics_material_override()); + c->set_constant_linear_velocity(sb->get_constant_linear_velocity()); + c->set_constant_angular_velocity(sb->get_constant_angular_velocity()); + c->set_transform(transform); + + c->set_collision_layer(sb->get_collision_layer()); + c->set_collision_mask(sb->get_collision_mask()); + + processor_process_collision_objects(node, Transform()); + + prop_data->add_prop(c); +} + +Node *PropDataStaticBody::_processor_get_node_for(const Transform &transform) { + StaticBody *sb = memnew(StaticBody); + sb->set_transform(get_transform()); + sb->set_physics_material_override(_physics_material_override); + sb->set_constant_linear_velocity(_constant_linear_velocity); + sb->set_constant_angular_velocity(_constant_angular_velocity); + + processor_create_shapes_for(sb); + + return sb; +} + +PropDataStaticBody::PropDataStaticBody() { +} +PropDataStaticBody::~PropDataStaticBody() { +} + +void PropDataStaticBody::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_physics_material_override"), &PropDataStaticBody::get_physics_material_override); + ClassDB::bind_method(D_METHOD("set_physics_material_override", "material"), &PropDataStaticBody::set_physics_material_override); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); + + ClassDB::bind_method(D_METHOD("get_constant_linear_velocity"), &PropDataStaticBody::get_constant_linear_velocity); + ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "layer"), &PropDataStaticBody::set_constant_linear_velocity); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity"); + + ClassDB::bind_method(D_METHOD("get_constant_angular_velocity"), &PropDataStaticBody::get_constant_angular_velocity); + ClassDB::bind_method(D_METHOD("set_constant_angular_velocity", "layer"), &PropDataStaticBody::set_constant_angular_velocity); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity"); +} diff --git a/modules/props/props/prop_data_static_body.h b/modules/props/props/prop_data_static_body.h new file mode 100644 index 000000000..6373d53f2 --- /dev/null +++ b/modules/props/props/prop_data_static_body.h @@ -0,0 +1,58 @@ +#ifndef PROP_DATA_STATIC_BODY_H +#define PROP_DATA_STATIC_BODY_H + +/* +Copyright (c) 2023-present Péter Magyar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "prop_data_collision_object.h" + +class PhysicsMaterial; + +class PropDataStaticBody : public PropDataCollisionObject { + GDCLASS(PropDataStaticBody, PropDataCollisionObject); + +public: + Ref get_physics_material_override() const; + void set_physics_material_override(const Ref &p_material); + + Vector3 get_constant_linear_velocity() const; + void set_constant_linear_velocity(const Vector3 &p_value); + + Vector3 get_constant_angular_velocity() const; + void set_constant_angular_velocity(const Vector3 &p_value); + + bool _processor_handles(Node *node); + void _processor_process(Ref prop_data, Node *node, const Transform &transform); + Node *_processor_get_node_for(const Transform &transform); + + PropDataStaticBody(); + ~PropDataStaticBody(); + +protected: + static void _bind_methods(); + + Ref _physics_material_override; + Vector3 _constant_linear_velocity; + Vector3 _constant_angular_velocity; +}; + +#endif diff --git a/modules/props/register_types.cpp b/modules/props/register_types.cpp index 6a1ab686b..51a43d9d1 100644 --- a/modules/props/register_types.cpp +++ b/modules/props/register_types.cpp @@ -33,6 +33,8 @@ SOFTWARE. #include "props/prop_data_prop.h" #include "props/prop_data_scene.h" #include "props/prop_data_tiled_wall.h" +#include "props/prop_data_collision_object.h" +#include "props/prop_data_static_body.h" #include "props/prop_data_portal.h" @@ -94,6 +96,8 @@ void register_props_types(ModuleRegistrationLevel p_level) { ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); ClassDB::register_class(); @@ -135,6 +139,9 @@ void register_props_types(ModuleRegistrationLevel p_level) { Ref tiled_wall_processor = Ref(memnew(PropDataTiledWall)); PropUtils::add_processor(tiled_wall_processor); + + Ref static_body_processor = Ref(memnew(PropDataStaticBody)); + PropUtils::add_processor(static_body_processor); } #ifdef TOOLS_ENABLED