diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 9782b9d1f4c..cd10dca0457 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -5187,9 +5187,10 @@ void SpatialEditor::_register_all_gizmos() { register_gizmo_plugin(Ref(memnew(MeshInstanceSpatialGizmoPlugin))); register_gizmo_plugin(Ref(memnew(SoftBodySpatialGizmoPlugin))); register_gizmo_plugin(Ref(memnew(Sprite3DSpatialGizmoPlugin))); - register_gizmo_plugin(Ref(memnew(Position3DSpatialGizmoPlugin))); register_gizmo_plugin(Ref(memnew(SkeletonSpatialGizmoPlugin))); + register_gizmo_plugin(Ref(memnew(Position3DSpatialGizmoPlugin))); register_gizmo_plugin(Ref(memnew(RayCastSpatialGizmoPlugin))); + register_gizmo_plugin(Ref(memnew(SpringArmSpatialGizmoPlugin))); register_gizmo_plugin(Ref(memnew(VehicleWheelSpatialGizmoPlugin))); register_gizmo_plugin(Ref(memnew(VisibilityNotifierGizmoPlugin))); register_gizmo_plugin(Ref(memnew(ParticlesGizmoPlugin))); diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index 64fdc778d04..2635b722e50 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -1920,6 +1920,38 @@ void RayCastSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { ///// +void SpringArmSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + SpringArm *spring_arm = Object::cast_to(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); + + Vector lines; + + lines.push_back(Vector3()); + lines.push_back(Vector3(0, 0, 1.0) * spring_arm->get_length()); + + Ref material = get_material("shape_material", p_gizmo); + + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); +} + +SpringArmSpatialGizmoPlugin::SpringArmSpatialGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1)); + create_material("shape_material", gizmo_color); +} + +bool SpringArmSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to(p_spatial) != NULL; +} + +String SpringArmSpatialGizmoPlugin::get_name() const { + return "SpringArm"; +} + +///// + VehicleWheelSpatialGizmoPlugin::VehicleWheelSpatialGizmoPlugin() { Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1)); diff --git a/editor/spatial_editor_gizmos.h b/editor/spatial_editor_gizmos.h index 877590b91d6..6f29e9d9990 100644 --- a/editor/spatial_editor_gizmos.h +++ b/editor/spatial_editor_gizmos.h @@ -49,6 +49,7 @@ #include "scene/3d/ray_cast.h" #include "scene/3d/reflection_probe.h" #include "scene/3d/room_instance.h" +#include "scene/3d/spring_arm.h" #include "scene/3d/sprite_3d.h" #include "scene/3d/vehicle_body.h" #include "scene/3d/visibility_notifier.h" @@ -196,6 +197,18 @@ public: RayCastSpatialGizmoPlugin(); }; +class SpringArmSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { + + GDCLASS(SpringArmSpatialGizmoPlugin, EditorSpatialGizmoPlugin); + +public: + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); + + SpringArmSpatialGizmoPlugin(); +}; + class VehicleWheelSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { GDCLASS(VehicleWheelSpatialGizmoPlugin, EditorSpatialGizmoPlugin); @@ -330,14 +343,12 @@ public: }; class CollisionPolygonSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - GDCLASS(CollisionPolygonSpatialGizmoPlugin, EditorSpatialGizmoPlugin); public: bool has_gizmo(Spatial *p_spatial); String get_name() const; void redraw(EditorSpatialGizmo *p_gizmo); - CollisionPolygonSpatialGizmoPlugin(); }; diff --git a/scene/3d/spring_arm.cpp b/scene/3d/spring_arm.cpp new file mode 100644 index 00000000000..492c6b806e2 --- /dev/null +++ b/scene/3d/spring_arm.cpp @@ -0,0 +1,172 @@ +/*************************************************************************/ +/* spring_arm.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* 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 "spring_arm.h" +#include "engine.h" +#include "scene/3d/collision_object.h" +#include "scene/resources/sphere_shape.h" +#include "servers/physics_server.h" + +SpringArm::SpringArm() : + spring_length(1), + mask(1), + current_spring_length(0), + margin(0.01) {} + +void SpringArm::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + if (!Engine::get_singleton()->is_editor_hint()) { + set_process_internal(true); + } + break; + case NOTIFICATION_EXIT_TREE: + if (!Engine::get_singleton()->is_editor_hint()) { + set_process_internal(false); + } + break; + case NOTIFICATION_INTERNAL_PROCESS: + process_spring(); + break; + } +} + +void SpringArm::_bind_methods() { + + ClassDB::bind_method(D_METHOD("get_hit_length"), &SpringArm::get_hit_length); + + ClassDB::bind_method(D_METHOD("set_length", "length"), &SpringArm::set_length); + ClassDB::bind_method(D_METHOD("get_length"), &SpringArm::get_length); + + ClassDB::bind_method(D_METHOD("set_shape", "shape"), &SpringArm::set_shape); + ClassDB::bind_method(D_METHOD("get_shape"), &SpringArm::get_shape); + + ClassDB::bind_method(D_METHOD("add_excluded_object", "RID"), &SpringArm::add_excluded_object); + ClassDB::bind_method(D_METHOD("remove_excluded_object", "RID"), &SpringArm::remove_excluded_object); + ClassDB::bind_method(D_METHOD("clear_excluded_objects"), &SpringArm::clear_excluded_objects); + + ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &SpringArm::set_mask); + ClassDB::bind_method(D_METHOD("get_collision_mask"), &SpringArm::get_mask); + + ClassDB::bind_method(D_METHOD("set_margin", "margin"), &SpringArm::set_margin); + ClassDB::bind_method(D_METHOD("get_margin"), &SpringArm::get_margin); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape"), "set_shape", "get_shape"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "spring_length"), "set_length", "get_length"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "margin"), "set_margin", "get_margin"); +} + +float SpringArm::get_length() const { + return spring_length; +} + +void SpringArm::set_length(float p_length) { + if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_collisions_hint())) + update_gizmo(); + + spring_length = p_length; +} + +void SpringArm::set_shape(Ref p_shape) { + shape = p_shape; +} + +Ref SpringArm::get_shape() const { + return shape; +} + +void SpringArm::set_mask(uint32_t p_mask) { + mask = p_mask; +} + +uint32_t SpringArm::get_mask() { + return mask; +} + +float SpringArm::get_margin() { + return margin; +} + +void SpringArm::set_margin(float p_margin) { + margin = p_margin; +} + +void SpringArm::add_excluded_object(RID p_rid) { + excluded_objects.insert(p_rid); +} + +bool SpringArm::remove_excluded_object(RID p_rid) { + return excluded_objects.erase(p_rid); +} + +void SpringArm::clear_excluded_objects() { + excluded_objects.clear(); +} + +float SpringArm::get_hit_length() { + return current_spring_length; +} + +void SpringArm::process_spring() { + // From + real_t motion_delta(1); + real_t motion_delta_unsafe(1); + + Vector3 motion; + const Vector3 cast_direction(get_global_transform().basis.xform(Vector3(0, 0, 1))); + + if (shape.is_null()) { + motion = Vector3(cast_direction * (spring_length)); + PhysicsDirectSpaceState::RayResult r; + bool intersected = get_world()->get_direct_space_state()->intersect_ray(get_global_transform().origin, get_global_transform().origin + motion, r, excluded_objects, mask); + if (intersected) { + float dist = get_global_transform().origin.distance_to(r.position); + dist -= margin; + motion_delta = dist / (spring_length); + } + } else { + motion = Vector3(cast_direction * spring_length); + get_world()->get_direct_space_state()->cast_motion(shape->get_rid(), get_global_transform(), motion, 0, motion_delta, motion_delta_unsafe, excluded_objects, mask); + } + + current_spring_length = spring_length * motion_delta; + Transform childs_transform; + childs_transform.origin = get_global_transform().origin + cast_direction * (spring_length * motion_delta); + + for (int i = get_child_count() - 1; 0 <= i; --i) { + + Spatial *child = Object::cast_to(get_child(i)); + if (child) { + childs_transform.basis = child->get_global_transform().basis; + child->set_global_transform(childs_transform); + } + } +} diff --git a/scene/3d/spring_arm.h b/scene/3d/spring_arm.h new file mode 100644 index 00000000000..24d912d371f --- /dev/null +++ b/scene/3d/spring_arm.h @@ -0,0 +1,71 @@ +/*************************************************************************/ +/* spring_arm.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef SPRING_ARM_H +#define SPRING_ARM_H + +#include "scene/3d/spatial.h" + +class SpringArm : public Spatial { + GDCLASS(SpringArm, Spatial); + + Ref shape; + Set excluded_objects; + float spring_length; + bool keep_child_basis; + float current_spring_length; + uint32_t mask; + float margin; + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + void set_length(float p_length); + float get_length() const; + void set_shape(Ref p_shape); + Ref get_shape() const; + void set_mask(uint32_t p_mask); + uint32_t get_mask(); + void add_excluded_object(RID p_rid); + bool remove_excluded_object(RID p_rid); + void clear_excluded_objects(); + float get_hit_length(); + void set_margin(float p_margin); + float get_margin(); + + SpringArm(); + +private: + void process_spring(); +}; + +#endif diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 382bddfb4e2..40134a2480a 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -201,6 +201,7 @@ #include "scene/3d/room_instance.h" #include "scene/3d/skeleton.h" #include "scene/3d/soft_body.h" +#include "scene/3d/spring_arm.h" #include "scene/3d/sprite_3d.h" #include "scene/3d/vehicle_body.h" #include "scene/3d/visibility_notifier.h" @@ -435,6 +436,8 @@ void register_scene_types() { ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); ClassDB::register_class();