From f4f997a8d2a369daebb3907a1d61646126a50010 Mon Sep 17 00:00:00 2001 From: "Andrii Doroshenko (Xrayez)" Date: Sun, 28 Jun 2020 13:45:15 +0300 Subject: [PATCH 01/11] Implement a node to draw Shape2D resources --- config.py | 1 + doc/VisualShape2D.xml | 29 ++++++++++ scene/2d/SCsub | 4 ++ scene/2d/visual_shape_2d.cpp | 98 ++++++++++++++++++++++++++++++++++ scene/2d/visual_shape_2d.h | 38 +++++++++++++ scene/3d/SCsub | 3 ++ scene/SCsub | 6 +++ scene/register_scene_types.cpp | 3 ++ 8 files changed, 182 insertions(+) create mode 100644 doc/VisualShape2D.xml create mode 100644 scene/2d/SCsub create mode 100644 scene/2d/visual_shape_2d.cpp create mode 100644 scene/2d/visual_shape_2d.h create mode 100644 scene/3d/SCsub diff --git a/config.py b/config.py index 12084aaa..947f80c6 100644 --- a/config.py +++ b/config.py @@ -51,6 +51,7 @@ def get_doc_classes(): "ImageIndexed", "ImageIndexed", "ShapeCast2D", + "VisualShape2D", ] diff --git a/doc/VisualShape2D.xml b/doc/VisualShape2D.xml new file mode 100644 index 00000000..ac2a7c4a --- /dev/null +++ b/doc/VisualShape2D.xml @@ -0,0 +1,29 @@ + + + + Draws any [Shape2D] resource. Useful for quick prototyping. + + + This is a node with the entire purpose of rendering [Shape2D] resources just like drawing collision shapes in the editor, yet it's also possible to override the color per each node rather than globally with this class. While the class supports all existing shapes, it's currently not convenient to edit polygon-based shapes, so use [Polygon2D] node which is much more superior for editing and drawing of polygons (with textures). + + + + + + + + The fill color used to draw the [member shape]. + + + If [code]true[/code], respects the "Visible Collision Shapes" option so that the shape is only drawn when the option is enabled while the game is running. + + + If [code]true[/code], this overrides the [member color] with the color used to draw the collision shapes. + + + The shape resource used as a reference to draw. The drawing method is specific for each shape and the properties must be configured per shape. + + + + + diff --git a/scene/2d/SCsub b/scene/2d/SCsub new file mode 100644 index 00000000..0bdd9c11 --- /dev/null +++ b/scene/2d/SCsub @@ -0,0 +1,4 @@ +#!/usr/bin/env python +Import("env_goost") + +env_goost.add_source_files(env_goost.modules_sources, '*.cpp') diff --git a/scene/2d/visual_shape_2d.cpp b/scene/2d/visual_shape_2d.cpp new file mode 100644 index 00000000..1db8bc77 --- /dev/null +++ b/scene/2d/visual_shape_2d.cpp @@ -0,0 +1,98 @@ +#include "visual_shape_2d.h" + +#include "core/core_string_names.h" +#include "core/engine.h" + +void VisualShape2D::set_shape(const Ref &p_shape) { + shape = p_shape; + if (p_shape.is_valid()) { + shape->connect(CoreStringNames::get_singleton()->changed, this, "update"); + } + update(); +} + +Ref VisualShape2D::get_shape() const { + return shape; +} + +void VisualShape2D::set_color(const Color &p_color) { + color = p_color; + update(); +} + +Color VisualShape2D::get_color() const { + return color; +} + +void VisualShape2D::set_debug_use_default_color(bool p_debug_use_default_color) { + debug_use_default_color = p_debug_use_default_color; + update(); +} + +bool VisualShape2D::is_using_debug_default_color() const { + return debug_use_default_color; +} + +void VisualShape2D::set_debug_sync_visible_collision_shapes(bool p_debug_sync_visible_collision_shapes) { + debug_sync_visible_collision_shapes = p_debug_sync_visible_collision_shapes; + update(); +} + +bool VisualShape2D::is_debug_sync_visible_collision_shapes() const { + return debug_sync_visible_collision_shapes; +} + +void VisualShape2D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_DRAW: { + if (shape.is_null()) { + break; + } + Color draw_color = color; +#ifdef TOOLS_ENABLED + if (debug_use_default_color) { + draw_color = get_tree()->get_debug_collisions_color(); + } + if (debug_sync_visible_collision_shapes && !Engine::get_singleton()->is_editor_hint()) { + if (!get_tree()->is_debugging_collisions_hint()) { + break; + } + } +#endif + shape->draw(get_canvas_item(), draw_color); + } break; + } +} + +String VisualShape2D::get_configuration_warning() const { + String warning = Node2D::get_configuration_warning(); + + if (shape.is_null()) { + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("Shape2D is required for this node to be drawn."); + } + + return warning; +} + +void VisualShape2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_shape", "shape"), &VisualShape2D::set_shape); + ClassDB::bind_method(D_METHOD("get_shape"), &VisualShape2D::get_shape); + + ClassDB::bind_method(D_METHOD("set_color", "color"), &VisualShape2D::set_color); + ClassDB::bind_method(D_METHOD("get_color"), &VisualShape2D::get_color); + + ClassDB::bind_method(D_METHOD("set_debug_use_default_color", "enable"), &VisualShape2D::set_debug_use_default_color); + ClassDB::bind_method(D_METHOD("is_using_debug_default_color"), &VisualShape2D::is_using_debug_default_color); + + ClassDB::bind_method(D_METHOD("set_debug_sync_visible_collision_shapes", "debug_sync_visible_collision_shapes"), &VisualShape2D::set_debug_sync_visible_collision_shapes); + ClassDB::bind_method(D_METHOD("is_debug_sync_visible_collision_shapes"), &VisualShape2D::is_debug_sync_visible_collision_shapes); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D"), "set_shape", "get_shape"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); + ADD_GROUP("Debug", "debug_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_use_default_color"), "set_debug_use_default_color", "is_using_debug_default_color"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_sync_visible_collision_shapes"), "set_debug_sync_visible_collision_shapes", "is_debug_sync_visible_collision_shapes"); +} diff --git a/scene/2d/visual_shape_2d.h b/scene/2d/visual_shape_2d.h new file mode 100644 index 00000000..a5b6e646 --- /dev/null +++ b/scene/2d/visual_shape_2d.h @@ -0,0 +1,38 @@ +#ifndef GOOST_VISUAL_SHAPE_2D_H +#define GOOST_VISUAL_SHAPE_2D_H + +#include "scene/2d/node_2d.h" +#include "scene/resources/shape_2d.h" + +class VisualShape2D : public Node2D { + GDCLASS(VisualShape2D, Node2D); + + Ref shape; + Color color = Color(1, 1, 1, 1); + + bool debug_use_default_color = false; + bool debug_sync_visible_collision_shapes = false; + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + void set_shape(const Ref &p_shape); + Ref get_shape() const; + + void set_color(const Color &p_color); + Color get_color() const; + + void set_debug_use_default_color(bool p_debug_use_default_color); + bool is_using_debug_default_color() const; + + void set_debug_sync_visible_collision_shapes(bool p_debug_sync_visible_collision_shapes); + bool is_debug_sync_visible_collision_shapes() const; + + String get_configuration_warning() const; + + VisualShape2D() {}; +}; + +#endif // GOOST_VISUAL_SHAPE_2D_H diff --git a/scene/3d/SCsub b/scene/3d/SCsub new file mode 100644 index 00000000..7e572db8 --- /dev/null +++ b/scene/3d/SCsub @@ -0,0 +1,3 @@ +#!/usr/bin/env python + +# Nothing here yet! diff --git a/scene/SCsub b/scene/SCsub index 6a120fb1..54c057b1 100644 --- a/scene/SCsub +++ b/scene/SCsub @@ -1,6 +1,12 @@ #!/usr/bin/env python +Import("env") Import("env_goost") +SConscript("2d/SCsub", exports="env_goost") + +if not env["disable_3d"]: + SConscript("3d/SCsub", exports="env_goost") + if env_goost["goost_physics_enabled"]: SConscript("physics/SCsub", exports="env_goost") diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 2c4964a2..a1650985 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -3,9 +3,12 @@ #include "physics/register_physics_types.h" #include "register_scene_types.h" +#include "2d/visual_shape_2d.h" + namespace goost { void register_scene_types() { + ClassDB::register_class(); #ifdef GOOST_PHYSICS_ENABLED register_physics_types(); #endif From 3367716db0b56cd75b5922327277d9410e6b51bf Mon Sep 17 00:00:00 2001 From: "Andrii Doroshenko (Xrayez)" Date: Sun, 28 Jun 2020 15:24:58 +0300 Subject: [PATCH 02/11] VisualShape2D: Enable support for editing polygon shapes --- editor/2d/SCsub | 4 + editor/2d/visual_shape_2d_editor_plugin.cpp | 82 +++++++++++++++++++++ editor/2d/visual_shape_2d_editor_plugin.h | 37 ++++++++++ editor/3d/SCsub | 3 + editor/SCsub | 10 ++- editor/register_editor_types.cpp | 17 +++++ editor/register_editor_types.h | 6 ++ goost.py | 1 + register_types.cpp | 4 + 9 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 editor/2d/SCsub create mode 100644 editor/2d/visual_shape_2d_editor_plugin.cpp create mode 100644 editor/2d/visual_shape_2d_editor_plugin.h create mode 100644 editor/3d/SCsub create mode 100644 editor/register_editor_types.cpp create mode 100644 editor/register_editor_types.h diff --git a/editor/2d/SCsub b/editor/2d/SCsub new file mode 100644 index 00000000..3086f853 --- /dev/null +++ b/editor/2d/SCsub @@ -0,0 +1,4 @@ +#!/usr/bin/env python +Import("env_goost") + +env_goost.add_source_files(env_goost.modules_sources, "*.cpp") diff --git a/editor/2d/visual_shape_2d_editor_plugin.cpp b/editor/2d/visual_shape_2d_editor_plugin.cpp new file mode 100644 index 00000000..90e69b4a --- /dev/null +++ b/editor/2d/visual_shape_2d_editor_plugin.cpp @@ -0,0 +1,82 @@ +#include "visual_shape_2d_editor_plugin.h" + +#include "scene/resources/concave_polygon_shape_2d.h" +#include "scene/resources/convex_polygon_shape_2d.h" + +Node2D *VisualShape2DEditor::_get_node() const { + return node; +} + +void VisualShape2DEditor::_set_node(Node *p_node) { + node = Object::cast_to(p_node); +} + +void VisualShape2DEditor::_set_polygon(int p_idx, const Variant &p_polygon) const { + VisualShape2D *n = Object::cast_to(_get_node()); + + const Ref &shape = n->get_shape(); + Ref convex = shape; + Ref concave = shape; + + if (convex.is_valid()) { + convex->set("points", p_polygon); + } else if (concave.is_valid()) { + concave->set("segments", p_polygon); + } +} + +Variant VisualShape2DEditor::_get_polygon(int p_idx) const { + VisualShape2D *n = Object::cast_to(_get_node()); + + const Ref &shape = n->get_shape(); + Ref convex = shape; + Ref concave = shape; + + if (convex.is_valid()) { + return convex->get("points"); + } else if (concave.is_valid()) { + return concave->get("segments"); + } + return Variant(); +} + +void VisualShape2DEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) { + undo_redo->add_do_method(this, "_set_polygon", 0, p_polygon); + undo_redo->add_undo_method(this, "_set_polygon", 0, p_previous); +} + +bool VisualShape2DEditor::_has_resource() const { + if (!node) { + return false; + } + const Ref &shape = node->get_shape(); + Ref convex = shape; + Ref concave = shape; + + return convex.is_valid() || concave.is_valid(); +} + +void VisualShape2DEditor::_create_resource() { + if (!node) { + return; + } + undo_redo->create_action(TTR("Create Convex Polygon Shape")); + undo_redo->add_do_method(node, "set_shape", Ref(memnew(ConvexPolygonShape2D))); + undo_redo->add_undo_method(node, "set_shape", Variant(REF())); + undo_redo->commit_action(); + + _menu_option(MODE_CREATE); +} + +void VisualShape2DEditor::_bind_methods() { + ClassDB::bind_method(D_METHOD("_set_polygon"), &VisualShape2DEditor::_set_polygon); +} + +VisualShape2DEditor::VisualShape2DEditor(EditorNode *p_editor) : + AbstractPolygon2DEditor(p_editor) { + node = nullptr; +} + +VisualShape2DEditorPlugin::VisualShape2DEditorPlugin(EditorNode *p_node) : + AbstractPolygon2DEditorPlugin(p_node, memnew(VisualShape2DEditor(p_node)), "VisualShape2D") { +} diff --git a/editor/2d/visual_shape_2d_editor_plugin.h b/editor/2d/visual_shape_2d_editor_plugin.h new file mode 100644 index 00000000..a3131afd --- /dev/null +++ b/editor/2d/visual_shape_2d_editor_plugin.h @@ -0,0 +1,37 @@ +#ifndef GOOST_VISUAL_SHAPE_2D_EDITOR_PLUGIN_H +#define GOOST_VISUAL_SHAPE_2D_EDITOR_PLUGIN_H + +#include "editor/plugins/abstract_polygon_2d_editor.h" +#include "scene/2d/visual_shape_2d.h" + +class VisualShape2DEditor : public AbstractPolygon2DEditor { + GDCLASS(VisualShape2DEditor, AbstractPolygon2DEditor); + + VisualShape2D *node; + +protected: + virtual Node2D *_get_node() const; + virtual void _set_node(Node *p_node); + + virtual void _set_polygon(int p_idx, const Variant &p_polygon) const; + virtual Variant _get_polygon(int p_idx) const; + + virtual void _action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon); + + virtual bool _has_resource() const; + virtual void _create_resource(); + + static void _bind_methods(); + +public: + VisualShape2DEditor(EditorNode *p_editor); +}; + +class VisualShape2DEditorPlugin : public AbstractPolygon2DEditorPlugin { + GDCLASS(VisualShape2DEditorPlugin, AbstractPolygon2DEditorPlugin); + +public: + VisualShape2DEditorPlugin(EditorNode *p_node); +}; + +#endif // GOOST_VISUAL_SHAPE_2D_EDITOR_PLUGIN_H diff --git a/editor/3d/SCsub b/editor/3d/SCsub new file mode 100644 index 00000000..7e572db8 --- /dev/null +++ b/editor/3d/SCsub @@ -0,0 +1,3 @@ +#!/usr/bin/env python + +# Nothing here yet! diff --git a/editor/SCsub b/editor/SCsub index 42a2eafb..5970a7bf 100644 --- a/editor/SCsub +++ b/editor/SCsub @@ -1,3 +1,11 @@ #!/usr/bin/env python +Import("env") +Import("env_goost") -# Nothing here yet! +if env_goost["goost_editor_enabled"]: + SConscript("2d/SCsub", exports="env_goost") + + if not env["disable_3d"]: + SConscript("3d/SCsub", exports="env_goost") + + env_goost.add_source_files(env_goost.modules_sources, "*.cpp") diff --git a/editor/register_editor_types.cpp b/editor/register_editor_types.cpp new file mode 100644 index 00000000..c087f929 --- /dev/null +++ b/editor/register_editor_types.cpp @@ -0,0 +1,17 @@ +#include "register_editor_types.h" + +#include "editor/2d/visual_shape_2d_editor_plugin.h" + +namespace goost { + +void register_editor_types() { +#ifdef TOOLS_ENABLED + EditorPlugins::add_by_type(); +#endif +} + +void unregister_editor_types() { + // Nothing to do. +} + +} // namespace goost diff --git a/editor/register_editor_types.h b/editor/register_editor_types.h new file mode 100644 index 00000000..5a53fd79 --- /dev/null +++ b/editor/register_editor_types.h @@ -0,0 +1,6 @@ +namespace goost { + +void register_editor_types(); +void unregister_editor_types(); + +} // namespace goost diff --git a/goost.py b/goost.py index e5f213e0..e61a34dd 100644 --- a/goost.py +++ b/goost.py @@ -9,6 +9,7 @@ "core/image", "core/math", "scene/physics", + "editor", ] def get_components(): diff --git a/register_types.cpp b/register_types.cpp index eb625bc9..ad76ddb7 100644 --- a/register_types.cpp +++ b/register_types.cpp @@ -2,6 +2,7 @@ #include "core/register_core_types.h" #include "scene/register_scene_types.h" +#include "editor/register_editor_types.h" void register_goost_types() { #ifdef GOOST_CORE_ENABLED @@ -10,6 +11,9 @@ void register_goost_types() { #ifdef GOOST_SCENE_ENABLED goost::register_scene_types(); #endif +#ifdef GOOST_EDITOR_ENABLED + goost::register_editor_types(); +#endif } void unregister_goost_types() { From e81278d8bafa68d133c5fab9622b34e1fabc9452 Mon Sep 17 00:00:00 2001 From: "Andrii Doroshenko (Xrayez)" Date: Sun, 28 Jun 2020 19:30:12 +0300 Subject: [PATCH 03/11] VisualShape2D: Properly disable polygon editing --- editor/2d/visual_shape_2d_editor_plugin.cpp | 37 ++++++++++++++++++--- editor/2d/visual_shape_2d_editor_plugin.h | 2 ++ scene/2d/visual_shape_2d.cpp | 26 ++++++++++++++- 3 files changed, 59 insertions(+), 6 deletions(-) diff --git a/editor/2d/visual_shape_2d_editor_plugin.cpp b/editor/2d/visual_shape_2d_editor_plugin.cpp index 90e69b4a..118e7551 100644 --- a/editor/2d/visual_shape_2d_editor_plugin.cpp +++ b/editor/2d/visual_shape_2d_editor_plugin.cpp @@ -1,5 +1,7 @@ #include "visual_shape_2d_editor_plugin.h" +#include "editor/plugins/canvas_item_editor_plugin.h" + #include "scene/resources/concave_polygon_shape_2d.h" #include "scene/resources/convex_polygon_shape_2d.h" @@ -8,7 +10,14 @@ Node2D *VisualShape2DEditor::_get_node() const { } void VisualShape2DEditor::_set_node(Node *p_node) { + if (node) { + node->disconnect("shape_changed", this, "_update_editing"); + } node = Object::cast_to(p_node); + if (node) { + node->connect("shape_changed", this, "_update_editing"); + } + _update_editing(); } void VisualShape2DEditor::_set_polygon(int p_idx, const Variant &p_polygon) const { @@ -40,6 +49,25 @@ Variant VisualShape2DEditor::_get_polygon(int p_idx) const { return Variant(); } +void VisualShape2DEditor::_update_editing() { + if (!node) { + return; + } + Ref shape = node->get_shape(); + Ref convex = shape; + Ref concave = shape; + + const String reason = TTR("No polygon-based shape resource is set."); + + if (shape.is_null()) { + disable_polygon_editing(true, reason); + } else if (convex.is_valid() || concave.is_valid()) { + disable_polygon_editing(false, ""); + } else { + disable_polygon_editing(true, reason); + } +} + void VisualShape2DEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) { undo_redo->add_do_method(this, "_set_polygon", 0, p_polygon); undo_redo->add_undo_method(this, "_set_polygon", 0, p_previous); @@ -49,11 +77,7 @@ bool VisualShape2DEditor::_has_resource() const { if (!node) { return false; } - const Ref &shape = node->get_shape(); - Ref convex = shape; - Ref concave = shape; - - return convex.is_valid() || concave.is_valid(); + return node->get_shape().is_valid(); } void VisualShape2DEditor::_create_resource() { @@ -66,10 +90,13 @@ void VisualShape2DEditor::_create_resource() { undo_redo->commit_action(); _menu_option(MODE_CREATE); + + EditorNode::get_singleton()->get_inspector()->refresh(); } void VisualShape2DEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_polygon"), &VisualShape2DEditor::_set_polygon); + ClassDB::bind_method(D_METHOD("_update_editing"), &VisualShape2DEditor::_update_editing); } VisualShape2DEditor::VisualShape2DEditor(EditorNode *p_editor) : diff --git a/editor/2d/visual_shape_2d_editor_plugin.h b/editor/2d/visual_shape_2d_editor_plugin.h index a3131afd..f9a49b24 100644 --- a/editor/2d/visual_shape_2d_editor_plugin.h +++ b/editor/2d/visual_shape_2d_editor_plugin.h @@ -9,6 +9,8 @@ class VisualShape2DEditor : public AbstractPolygon2DEditor { VisualShape2D *node; + void _update_editing(); + protected: virtual Node2D *_get_node() const; virtual void _set_node(Node *p_node); diff --git a/scene/2d/visual_shape_2d.cpp b/scene/2d/visual_shape_2d.cpp index 1db8bc77..85ad85ab 100644 --- a/scene/2d/visual_shape_2d.cpp +++ b/scene/2d/visual_shape_2d.cpp @@ -2,13 +2,22 @@ #include "core/core_string_names.h" #include "core/engine.h" +#include "scene/resources/concave_polygon_shape_2d.h" +#include "scene/resources/convex_polygon_shape_2d.h" void VisualShape2D::set_shape(const Ref &p_shape) { + bool shape_changed = false; + if (shape != p_shape) { + shape_changed = true; + } shape = p_shape; if (p_shape.is_valid()) { shape->connect(CoreStringNames::get_singleton()->changed, this, "update"); } update(); + if (shape_changed) { + emit_signal("shape_changed"); + } } Ref VisualShape2D::get_shape() const { @@ -49,7 +58,20 @@ void VisualShape2D::_notification(int p_what) { break; } Color draw_color = color; -#ifdef TOOLS_ENABLED +#ifdef DEBUG_ENABLED + // Avoid error messages, only in debug to save performance in release. + Ref convex = shape; + if (convex.is_valid()) { + if (convex->get_points().size() < 3) { + break; + } + } + Ref concave = shape; + if (concave.is_valid()) { + if (concave->get_segments().size() % 2) { + break; + } + } if (debug_use_default_color) { draw_color = get_tree()->get_debug_collisions_color(); } @@ -95,4 +117,6 @@ void VisualShape2D::_bind_methods() { ADD_GROUP("Debug", "debug_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_use_default_color"), "set_debug_use_default_color", "is_using_debug_default_color"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_sync_visible_collision_shapes"), "set_debug_sync_visible_collision_shapes", "is_debug_sync_visible_collision_shapes"); + + ADD_SIGNAL(MethodInfo("shape_changed")); } From f46c575933d5b0332c058137e2bbecc515f8553b Mon Sep 17 00:00:00 2001 From: "Andrii Doroshenko (Xrayez)" Date: Sun, 28 Jun 2020 19:35:42 +0300 Subject: [PATCH 04/11] VisualShape2D: make sure previous shapes do not trigger update --- scene/2d/visual_shape_2d.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scene/2d/visual_shape_2d.cpp b/scene/2d/visual_shape_2d.cpp index 85ad85ab..10227b21 100644 --- a/scene/2d/visual_shape_2d.cpp +++ b/scene/2d/visual_shape_2d.cpp @@ -10,6 +10,9 @@ void VisualShape2D::set_shape(const Ref &p_shape) { if (shape != p_shape) { shape_changed = true; } + if (shape.is_valid()) { + shape->disconnect(CoreStringNames::get_singleton()->changed, this, "update"); + } shape = p_shape; if (p_shape.is_valid()) { shape->connect(CoreStringNames::get_singleton()->changed, this, "update"); From 854408534baae6cd53e1afdc83c53aee960ec550 Mon Sep 17 00:00:00 2001 From: "Andrii Doroshenko (Xrayez)" Date: Sun, 28 Jun 2020 22:44:02 +0300 Subject: [PATCH 05/11] VisualShape2D: ability to get shape from parent --- doc/VisualShape2D.xml | 14 ++++++- scene/2d/visual_shape_2d.cpp | 71 ++++++++++++++++++++++++++++++++++-- scene/2d/visual_shape_2d.h | 25 ++++++++----- 3 files changed, 95 insertions(+), 15 deletions(-) diff --git a/doc/VisualShape2D.xml b/doc/VisualShape2D.xml index ac2a7c4a..4d319a45 100644 --- a/doc/VisualShape2D.xml +++ b/doc/VisualShape2D.xml @@ -1,10 +1,10 @@ - Draws any [Shape2D] resource. Useful for quick prototyping. + Draws any [Shape2D] resource. Useful for quick prototyping and debugging. - This is a node with the entire purpose of rendering [Shape2D] resources just like drawing collision shapes in the editor, yet it's also possible to override the color per each node rather than globally with this class. While the class supports all existing shapes, it's currently not convenient to edit polygon-based shapes, so use [Polygon2D] node which is much more superior for editing and drawing of polygons (with textures). + This is a node with the entire purpose of rendering [Shape2D] resources just like collision shapes are drawn in the editor, yet it's also possible to override the color per each node rather than globally with this class. You may use Godot's [Polygon2D] node which is much more suitable for polygon editing and drawing with textures, as any shape can be represented with it. @@ -23,7 +23,17 @@ The shape resource used as a reference to draw. The drawing method is specific for each shape and the properties must be configured per shape. + + If [code]true[/code], the shape is fetched from the parent node to draw instead of its own [member shape]. The parent node must have either [code]shape[/code] [Shape2D] property or [code]polygon[/code] [PoolVector2Array] property defined, else nothing is drawn. + + + + + Emitted when the [member shape] is changed (or cleared). + + + diff --git a/scene/2d/visual_shape_2d.cpp b/scene/2d/visual_shape_2d.cpp index 10227b21..7662beb2 100644 --- a/scene/2d/visual_shape_2d.cpp +++ b/scene/2d/visual_shape_2d.cpp @@ -14,10 +14,11 @@ void VisualShape2D::set_shape(const Ref &p_shape) { shape->disconnect(CoreStringNames::get_singleton()->changed, this, "update"); } shape = p_shape; - if (p_shape.is_valid()) { + if (shape.is_valid()) { shape->connect(CoreStringNames::get_singleton()->changed, this, "update"); } update(); + if (shape_changed) { emit_signal("shape_changed"); } @@ -27,6 +28,51 @@ Ref VisualShape2D::get_shape() const { return shape; } +void VisualShape2D::set_use_parent_shape(bool p_use_parent_shape) { + use_parent_shape = p_use_parent_shape; + _update_parent_shape(); + update(); +} + +bool VisualShape2D::is_using_parent_shape() const { + return use_parent_shape; +} + +void VisualShape2D::_update_parent_shape() { + bool valid = true; + + if (!is_inside_tree()) { + valid = false; + } + Node *parent = get_parent(); + if (!parent) { + valid = false; + } + if (parent_shape.is_valid()) { + parent_shape->disconnect(CoreStringNames::get_singleton()->changed, this, "update"); + } + if (!valid) { + parent_shape = Ref(); + return; + } + parent_shape = parent->get("shape"); + if (parent_shape.is_null()) { + const Vector &poly = parent->get("polygon", &valid); + if (valid) { + // This might be `CollisionPolygon2D` etc. + Ref convex; + convex.instance(); + convex->set_points(poly); + parent_shape = convex; + } + } + if (parent_shape.is_valid()) { + if (!parent_shape->is_connected(CoreStringNames::get_singleton()->changed, this, "update")) { + parent_shape->connect(CoreStringNames::get_singleton()->changed, this, "update"); + } + } +} + void VisualShape2D::set_color(const Color &p_color) { color = p_color; update(); @@ -56,8 +102,20 @@ bool VisualShape2D::is_debug_sync_visible_collision_shapes() const { void VisualShape2D::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_PARENTED: + case NOTIFICATION_PATH_CHANGED: { + _update_parent_shape(); + update(); + } break; + case NOTIFICATION_UNPARENTED: { + } break; case NOTIFICATION_DRAW: { - if (shape.is_null()) { + Ref draw_shape = shape; + if (use_parent_shape) { + _update_parent_shape(); + draw_shape = parent_shape; + } + if (draw_shape.is_null()) { break; } Color draw_color = color; @@ -75,6 +133,7 @@ void VisualShape2D::_notification(int p_what) { break; } } + // Only relevant in debug builds! if (debug_use_default_color) { draw_color = get_tree()->get_debug_collisions_color(); } @@ -84,7 +143,7 @@ void VisualShape2D::_notification(int p_what) { } } #endif - shape->draw(get_canvas_item(), draw_color); + draw_shape->draw(get_canvas_item(), draw_color); } break; } } @@ -92,7 +151,7 @@ void VisualShape2D::_notification(int p_what) { String VisualShape2D::get_configuration_warning() const { String warning = Node2D::get_configuration_warning(); - if (shape.is_null()) { + if (shape.is_null() && parent_shape.is_null()) { if (!warning.empty()) { warning += "\n\n"; } @@ -106,6 +165,9 @@ void VisualShape2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_shape", "shape"), &VisualShape2D::set_shape); ClassDB::bind_method(D_METHOD("get_shape"), &VisualShape2D::get_shape); + ClassDB::bind_method(D_METHOD("set_use_parent_shape", "use_parent_shape"), &VisualShape2D::set_use_parent_shape); + ClassDB::bind_method(D_METHOD("is_using_parent_shape"), &VisualShape2D::is_using_parent_shape); + ClassDB::bind_method(D_METHOD("set_color", "color"), &VisualShape2D::set_color); ClassDB::bind_method(D_METHOD("get_color"), &VisualShape2D::get_color); @@ -116,6 +178,7 @@ void VisualShape2D::_bind_methods() { ClassDB::bind_method(D_METHOD("is_debug_sync_visible_collision_shapes"), &VisualShape2D::is_debug_sync_visible_collision_shapes); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D"), "set_shape", "get_shape"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_parent_shape"), "set_use_parent_shape", "is_using_parent_shape"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); ADD_GROUP("Debug", "debug_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_use_default_color"), "set_debug_use_default_color", "is_using_debug_default_color"); diff --git a/scene/2d/visual_shape_2d.h b/scene/2d/visual_shape_2d.h index a5b6e646..83d264a5 100644 --- a/scene/2d/visual_shape_2d.h +++ b/scene/2d/visual_shape_2d.h @@ -6,33 +6,40 @@ class VisualShape2D : public Node2D { GDCLASS(VisualShape2D, Node2D); - + Ref shape; + Ref parent_shape; + bool use_parent_shape = false; Color color = Color(1, 1, 1, 1); - + bool debug_use_default_color = false; bool debug_sync_visible_collision_shapes = false; + void _update_parent_shape(); + protected: void _notification(int p_what); static void _bind_methods(); - + public: void set_shape(const Ref &p_shape); Ref get_shape() const; - + + void set_use_parent_shape(bool p_use_parent_shape); + bool is_using_parent_shape() const; + void set_color(const Color &p_color); Color get_color() const; - + void set_debug_use_default_color(bool p_debug_use_default_color); bool is_using_debug_default_color() const; - + void set_debug_sync_visible_collision_shapes(bool p_debug_sync_visible_collision_shapes); bool is_debug_sync_visible_collision_shapes() const; - + String get_configuration_warning() const; - - VisualShape2D() {}; + + VisualShape2D(){}; }; #endif // GOOST_VISUAL_SHAPE_2D_H From 7fb9ade6a2c3100784503949365a2a3f3542b429 Mon Sep 17 00:00:00 2001 From: "Andrii Doroshenko (Xrayez)" Date: Mon, 29 Jun 2020 12:25:57 +0300 Subject: [PATCH 06/11] VisualShape2D: properly update configuration warning --- scene/2d/visual_shape_2d.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scene/2d/visual_shape_2d.cpp b/scene/2d/visual_shape_2d.cpp index 7662beb2..ec8a3d37 100644 --- a/scene/2d/visual_shape_2d.cpp +++ b/scene/2d/visual_shape_2d.cpp @@ -22,6 +22,7 @@ void VisualShape2D::set_shape(const Ref &p_shape) { if (shape_changed) { emit_signal("shape_changed"); } + update_configuration_warning(); } Ref VisualShape2D::get_shape() const { @@ -31,6 +32,7 @@ Ref VisualShape2D::get_shape() const { void VisualShape2D::set_use_parent_shape(bool p_use_parent_shape) { use_parent_shape = p_use_parent_shape; _update_parent_shape(); + update_configuration_warning(); update(); } @@ -39,7 +41,7 @@ bool VisualShape2D::is_using_parent_shape() const { } void VisualShape2D::_update_parent_shape() { - bool valid = true; + bool valid = use_parent_shape; if (!is_inside_tree()) { valid = false; From 7f90c3176e51f68237eebe607a717439448a7d1c Mon Sep 17 00:00:00 2001 From: "Andrii Doroshenko (Xrayez)" Date: Mon, 29 Jun 2020 13:16:24 +0300 Subject: [PATCH 07/11] VisualShape2D: make sure parent node's shape is updated --- doc/VisualShape2D.xml | 9 +++++++++ scene/2d/visual_shape_2d.cpp | 30 +++++++++++++++++++++++------- scene/2d/visual_shape_2d.h | 6 ++++-- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/doc/VisualShape2D.xml b/doc/VisualShape2D.xml index 4d319a45..1db40496 100644 --- a/doc/VisualShape2D.xml +++ b/doc/VisualShape2D.xml @@ -9,6 +9,13 @@ + + + + + Forces to update the shape from parent node. This is called automatically each [b]idle frame[/b] if [member use_parent_shape] is enabled. Updating the shape each frame may be costly, so you can disable this behavior with [code]set_process(false)[/code] on this node, and update the shape manually with this method when needed. + + @@ -16,9 +23,11 @@ If [code]true[/code], respects the "Visible Collision Shapes" option so that the shape is only drawn when the option is enabled while the game is running. + [b]Note:[/b] available in debug builds only. If [code]true[/code], this overrides the [member color] with the color used to draw the collision shapes. + [b]Note:[/b] available in debug builds only. The shape resource used as a reference to draw. The drawing method is specific for each shape and the properties must be configured per shape. diff --git a/scene/2d/visual_shape_2d.cpp b/scene/2d/visual_shape_2d.cpp index ec8a3d37..266f1f1c 100644 --- a/scene/2d/visual_shape_2d.cpp +++ b/scene/2d/visual_shape_2d.cpp @@ -31,7 +31,7 @@ Ref VisualShape2D::get_shape() const { void VisualShape2D::set_use_parent_shape(bool p_use_parent_shape) { use_parent_shape = p_use_parent_shape; - _update_parent_shape(); + update_parent_shape(); update_configuration_warning(); update(); } @@ -40,7 +40,7 @@ bool VisualShape2D::is_using_parent_shape() const { return use_parent_shape; } -void VisualShape2D::_update_parent_shape() { +bool VisualShape2D::update_parent_shape() { bool valid = use_parent_shape; if (!is_inside_tree()) { @@ -53,9 +53,11 @@ void VisualShape2D::_update_parent_shape() { if (parent_shape.is_valid()) { parent_shape->disconnect(CoreStringNames::get_singleton()->changed, this, "update"); } + Ref previous = parent_shape; + if (!valid) { parent_shape = Ref(); - return; + return parent_shape != previous; } parent_shape = parent->get("shape"); if (parent_shape.is_null()) { @@ -73,6 +75,7 @@ void VisualShape2D::_update_parent_shape() { parent_shape->connect(CoreStringNames::get_singleton()->changed, this, "update"); } } + return parent_shape != previous; } void VisualShape2D::set_color(const Color &p_color) { @@ -104,17 +107,22 @@ bool VisualShape2D::is_debug_sync_visible_collision_shapes() const { void VisualShape2D::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + set_process(true); + } break; + case NOTIFICATION_EXIT_TREE: { + set_process(false); + } break; case NOTIFICATION_PARENTED: case NOTIFICATION_PATH_CHANGED: { - _update_parent_shape(); + update_parent_shape(); update(); } break; - case NOTIFICATION_UNPARENTED: { - } break; case NOTIFICATION_DRAW: { Ref draw_shape = shape; if (use_parent_shape) { - _update_parent_shape(); + // May still need to update the shape if _process() is disabled. + update_parent_shape(); draw_shape = parent_shape; } if (draw_shape.is_null()) { @@ -147,6 +155,13 @@ void VisualShape2D::_notification(int p_what) { #endif draw_shape->draw(get_canvas_item(), draw_color); } break; + case NOTIFICATION_PROCESS: { + if (use_parent_shape) { + if (update_parent_shape()) { + update(); + } + } + } break; } } @@ -169,6 +184,7 @@ void VisualShape2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_use_parent_shape", "use_parent_shape"), &VisualShape2D::set_use_parent_shape); ClassDB::bind_method(D_METHOD("is_using_parent_shape"), &VisualShape2D::is_using_parent_shape); + ClassDB::bind_method(D_METHOD("update_parent_shape"), &VisualShape2D::update_parent_shape); ClassDB::bind_method(D_METHOD("set_color", "color"), &VisualShape2D::set_color); ClassDB::bind_method(D_METHOD("get_color"), &VisualShape2D::get_color); diff --git a/scene/2d/visual_shape_2d.h b/scene/2d/visual_shape_2d.h index 83d264a5..9f91061c 100644 --- a/scene/2d/visual_shape_2d.h +++ b/scene/2d/visual_shape_2d.h @@ -14,8 +14,8 @@ class VisualShape2D : public Node2D { bool debug_use_default_color = false; bool debug_sync_visible_collision_shapes = false; - - void _update_parent_shape(); + + bool _parent_shape_changed = false; protected: void _notification(int p_what); @@ -27,6 +27,8 @@ class VisualShape2D : public Node2D { void set_use_parent_shape(bool p_use_parent_shape); bool is_using_parent_shape() const; + // Returns `true` if parent shape is changed. + bool update_parent_shape(); void set_color(const Color &p_color); Color get_color() const; From 9f116c68a9c31441a4812b884a17e1e2060459eb Mon Sep 17 00:00:00 2001 From: "Andrii Doroshenko (Xrayez)" Date: Mon, 29 Jun 2020 14:07:33 +0300 Subject: [PATCH 08/11] VisualShape2D: cache polygon-based parent geometry --- doc/VisualShape2D.xml | 2 +- scene/2d/visual_shape_2d.cpp | 27 ++++++++++++++++++++------- scene/2d/visual_shape_2d.h | 9 +++++++-- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/doc/VisualShape2D.xml b/doc/VisualShape2D.xml index 1db40496..3696d698 100644 --- a/doc/VisualShape2D.xml +++ b/doc/VisualShape2D.xml @@ -33,7 +33,7 @@ The shape resource used as a reference to draw. The drawing method is specific for each shape and the properties must be configured per shape. - If [code]true[/code], the shape is fetched from the parent node to draw instead of its own [member shape]. The parent node must have either [code]shape[/code] [Shape2D] property or [code]polygon[/code] [PoolVector2Array] property defined, else nothing is drawn. + If [code]true[/code], the shape is fetched from the parent node to draw instead of its own [member shape]. The parent node must have either [code]shape[/code] as [Shape2D] property or [code]points[/code], [code]polygon[/code] as [PoolVector2Array] property defined, else nothing is drawn. diff --git a/scene/2d/visual_shape_2d.cpp b/scene/2d/visual_shape_2d.cpp index 266f1f1c..dde053c6 100644 --- a/scene/2d/visual_shape_2d.cpp +++ b/scene/2d/visual_shape_2d.cpp @@ -2,8 +2,6 @@ #include "core/core_string_names.h" #include "core/engine.h" -#include "scene/resources/concave_polygon_shape_2d.h" -#include "scene/resources/convex_polygon_shape_2d.h" void VisualShape2D::set_shape(const Ref &p_shape) { bool shape_changed = false; @@ -42,6 +40,7 @@ bool VisualShape2D::is_using_parent_shape() const { bool VisualShape2D::update_parent_shape() { bool valid = use_parent_shape; + bool got_polygon_shape = false; if (!is_inside_tree()) { valid = false; @@ -60,20 +59,34 @@ bool VisualShape2D::update_parent_shape() { return parent_shape != previous; } parent_shape = parent->get("shape"); + Vector points; if (parent_shape.is_null()) { - const Vector &poly = parent->get("polygon", &valid); + points = parent->get("points", &valid); + if (!valid) { + points = parent->get("polygon", &valid); + } if (valid) { // This might be `CollisionPolygon2D` etc. - Ref convex; - convex.instance(); - convex->set_points(poly); - parent_shape = convex; + got_polygon_shape = true; + if (polygon_shape.is_null()) { + polygon_shape.instance(); + } + parent_shape = polygon_shape; } } if (parent_shape.is_valid()) { if (!parent_shape->is_connected(CoreStringNames::get_singleton()->changed, this, "update")) { parent_shape->connect(CoreStringNames::get_singleton()->changed, this, "update"); } + // This needs to be set after the shape `changed` signal is connected, + // so that the polygon shape can be drawn even if `_process` is disabled. + if (got_polygon_shape) { + if (points.size() >= 3) { + polygon_shape->set_points(points); + } else { + parent_shape = Ref(); + } + } } return parent_shape != previous; } diff --git a/scene/2d/visual_shape_2d.h b/scene/2d/visual_shape_2d.h index 9f91061c..1f4ea4e5 100644 --- a/scene/2d/visual_shape_2d.h +++ b/scene/2d/visual_shape_2d.h @@ -2,20 +2,25 @@ #define GOOST_VISUAL_SHAPE_2D_H #include "scene/2d/node_2d.h" +#include "scene/resources/concave_polygon_shape_2d.h" +#include "scene/resources/convex_polygon_shape_2d.h" #include "scene/resources/shape_2d.h" class VisualShape2D : public Node2D { GDCLASS(VisualShape2D, Node2D); Ref shape; + Ref parent_shape; bool use_parent_shape = false; + + // Cache polygon-based parent geometry with this instance. + Ref polygon_shape; + Color color = Color(1, 1, 1, 1); bool debug_use_default_color = false; bool debug_sync_visible_collision_shapes = false; - - bool _parent_shape_changed = false; protected: void _notification(int p_what); From c203e866780d5093161bea131addeed5948f9349 Mon Sep 17 00:00:00 2001 From: "Andrii Doroshenko (Xrayez)" Date: Mon, 29 Jun 2020 14:43:05 +0300 Subject: [PATCH 09/11] VisualShape2D: fix include paths --- editor/2d/visual_shape_2d_editor_plugin.h | 2 +- editor/register_editor_types.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/editor/2d/visual_shape_2d_editor_plugin.h b/editor/2d/visual_shape_2d_editor_plugin.h index f9a49b24..279a6ea7 100644 --- a/editor/2d/visual_shape_2d_editor_plugin.h +++ b/editor/2d/visual_shape_2d_editor_plugin.h @@ -2,7 +2,7 @@ #define GOOST_VISUAL_SHAPE_2D_EDITOR_PLUGIN_H #include "editor/plugins/abstract_polygon_2d_editor.h" -#include "scene/2d/visual_shape_2d.h" +#include "goost/scene/2d/visual_shape_2d.h" class VisualShape2DEditor : public AbstractPolygon2DEditor { GDCLASS(VisualShape2DEditor, AbstractPolygon2DEditor); diff --git a/editor/register_editor_types.cpp b/editor/register_editor_types.cpp index c087f929..cbe133db 100644 --- a/editor/register_editor_types.cpp +++ b/editor/register_editor_types.cpp @@ -1,6 +1,6 @@ #include "register_editor_types.h" -#include "editor/2d/visual_shape_2d_editor_plugin.h" +#include "2d/visual_shape_2d_editor_plugin.h" namespace goost { From 7b4cb793baec4b63097767e72e6e796678b566be Mon Sep 17 00:00:00 2001 From: "Andrii Doroshenko (Xrayez)" Date: Mon, 29 Jun 2020 17:11:23 +0300 Subject: [PATCH 10/11] VisualShape2D: add editor icon --- editor/icons/README.md | 2 +- editor/icons/icon_visual_shape_2d.svg | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 editor/icons/icon_visual_shape_2d.svg diff --git a/editor/icons/README.md b/editor/icons/README.md index 758492f4..9bbb2382 100644 --- a/editor/icons/README.md +++ b/editor/icons/README.md @@ -2,6 +2,6 @@ This directory contains icons for classes provided by Goost. -See official +See official Godot Engine's [Editor icons](https://docs.godotengine.org/en/latest/development/editor/creating_icons.html) documentation page on how to create them. diff --git a/editor/icons/icon_visual_shape_2d.svg b/editor/icons/icon_visual_shape_2d.svg new file mode 100644 index 00000000..9bc89327 --- /dev/null +++ b/editor/icons/icon_visual_shape_2d.svg @@ -0,0 +1,5 @@ + + + + + From a84b550c36e45bcf64d8b46c5051d005fff6c420 Mon Sep 17 00:00:00 2001 From: "Andrii Doroshenko (Xrayez)" Date: Thu, 2 Jul 2020 00:51:28 +0300 Subject: [PATCH 11/11] VisualShape2D: support editing concave shapes --- editor/2d/visual_shape_2d_editor_plugin.cpp | 23 +++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/editor/2d/visual_shape_2d_editor_plugin.cpp b/editor/2d/visual_shape_2d_editor_plugin.cpp index 118e7551..679c6cf3 100644 --- a/editor/2d/visual_shape_2d_editor_plugin.cpp +++ b/editor/2d/visual_shape_2d_editor_plugin.cpp @@ -29,8 +29,19 @@ void VisualShape2DEditor::_set_polygon(int p_idx, const Variant &p_polygon) cons if (convex.is_valid()) { convex->set("points", p_polygon); + } else if (concave.is_valid()) { - concave->set("segments", p_polygon); + const Vector &polygon = p_polygon; + + Vector segments; + segments.resize(polygon.size() * 2); + Vector2 *w = segments.ptrw(); + + for (int i = 0; i < polygon.size(); ++i) { + w[(i << 1) + 0] = polygon[i]; + w[(i << 1) + 1] = polygon[(i + 1) % polygon.size()]; + } + concave->set("segments", segments); } } @@ -43,8 +54,16 @@ Variant VisualShape2DEditor::_get_polygon(int p_idx) const { if (convex.is_valid()) { return convex->get("points"); + } else if (concave.is_valid()) { - return concave->get("segments"); + Vector polygon; + const Vector &segments = concave->get("segments"); + const Vector2 *r = segments.ptr(); + + for (int i = 0; i < segments.size(); i += 2) { + polygon.push_back(r[i]); + } + return polygon; } return Variant(); }