Browse Source

Improve ShapeCast2D editor and debug drawing
- Rename RayCast2DEditorPlugin to Cast2DEditorPlugin and make it also support editing ShapeCast2D.
- Apply RayCast2D debug drawing improvements from #46675 to ShapeCast2D.

FireForge 3 năm trước cách đây
mục cha
commit
7cfa9ae539

+ 2 - 2
editor/editor_node.cpp

@@ -140,6 +140,7 @@
 #include "editor/plugins/bone_map_editor_plugin.h"
 #include "editor/plugins/camera_3d_editor_plugin.h"
 #include "editor/plugins/canvas_item_editor_plugin.h"
+#include "editor/plugins/cast_2d_editor_plugin.h"
 #include "editor/plugins/collision_polygon_2d_editor_plugin.h"
 #include "editor/plugins/collision_shape_2d_editor_plugin.h"
 #include "editor/plugins/control_editor_plugin.h"
@@ -174,7 +175,6 @@
 #include "editor/plugins/physical_bone_3d_editor_plugin.h"
 #include "editor/plugins/polygon_2d_editor_plugin.h"
 #include "editor/plugins/polygon_3d_editor_plugin.h"
-#include "editor/plugins/ray_cast_2d_editor_plugin.h"
 #include "editor/plugins/resource_preloader_editor_plugin.h"
 #include "editor/plugins/root_motion_editor_plugin.h"
 #include "editor/plugins/script_editor_plugin.h"
@@ -7190,7 +7190,7 @@ EditorNode::EditorNode() {
 	add_editor_plugin(memnew(NavigationPolygonEditorPlugin));
 	add_editor_plugin(memnew(Path2DEditorPlugin));
 	add_editor_plugin(memnew(Polygon2DEditorPlugin));
-	add_editor_plugin(memnew(RayCast2DEditorPlugin));
+	add_editor_plugin(memnew(Cast2DEditorPlugin));
 	add_editor_plugin(memnew(Skeleton2DEditorPlugin));
 	add_editor_plugin(memnew(Sprite2DEditorPlugin));
 	add_editor_plugin(memnew(TilesEditorPlugin));

+ 30 - 26
editor/plugins/ray_cast_2d_editor_plugin.cpp → editor/plugins/cast_2d_editor_plugin.cpp

@@ -1,5 +1,5 @@
 /*************************************************************************/
-/*  ray_cast_2d_editor_plugin.cpp                                        */
+/*  cast_2d_editor_plugin.cpp                                            */
 /*************************************************************************/
 /*                       This file is part of:                           */
 /*                           GODOT ENGINE                                */
@@ -28,30 +28,32 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 
-#include "ray_cast_2d_editor_plugin.h"
+#include "cast_2d_editor_plugin.h"
 
 #include "canvas_item_editor_plugin.h"
 #include "editor/editor_node.h"
+#include "scene/2d/ray_cast_2d.h"
+#include "scene/2d/shape_cast_2d.h"
 
-void RayCast2DEditor::_notification(int p_what) {
+void Cast2DEditor::_notification(int p_what) {
 	switch (p_what) {
 		case NOTIFICATION_ENTER_TREE: {
-			get_tree()->connect("node_removed", callable_mp(this, &RayCast2DEditor::_node_removed));
+			get_tree()->connect("node_removed", callable_mp(this, &Cast2DEditor::_node_removed));
 		} break;
 
 		case NOTIFICATION_EXIT_TREE: {
-			get_tree()->disconnect("node_removed", callable_mp(this, &RayCast2DEditor::_node_removed));
+			get_tree()->disconnect("node_removed", callable_mp(this, &Cast2DEditor::_node_removed));
 		} break;
 	}
 }
 
-void RayCast2DEditor::_node_removed(Node *p_node) {
+void Cast2DEditor::_node_removed(Node *p_node) {
 	if (p_node == node) {
 		node = nullptr;
 	}
 }
 
-bool RayCast2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
+bool Cast2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
 	if (!node || !node->is_visible_in_tree()) {
 		return false;
 	}
@@ -60,10 +62,12 @@ bool RayCast2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
 
 	Ref<InputEventMouseButton> mb = p_event;
 	if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) {
+		Vector2 target_position = node->get("target_position");
+
 		if (mb->is_pressed()) {
-			if (xform.xform(node->get_target_position()).distance_to(mb->get_position()) < 8) {
+			if (xform.xform(target_position).distance_to(mb->get_position()) < 8) {
 				pressed = true;
-				original_target_position = node->get_target_position();
+				original_target_position = target_position;
 
 				return true;
 			} else {
@@ -73,9 +77,9 @@ bool RayCast2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
 			}
 		} else if (pressed) {
 			undo_redo->create_action(TTR("Set target_position"));
-			undo_redo->add_do_method(node, "set_target_position", node->get_target_position());
+			undo_redo->add_do_property(node, "target_position", target_position);
 			undo_redo->add_do_method(canvas_item_editor, "update_viewport");
-			undo_redo->add_undo_method(node, "set_target_position", original_target_position);
+			undo_redo->add_undo_property(node, "target_position", original_target_position);
 			undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
 			undo_redo->commit_action();
 
@@ -90,7 +94,7 @@ bool RayCast2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
 		Vector2 point = canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mm->get_position()));
 		point = node->get_global_transform().affine_inverse().xform(point);
 
-		node->set_target_position(point);
+		node->set("target_position", point);
 		canvas_item_editor->update_viewport();
 		node->notify_property_list_changed();
 
@@ -100,7 +104,7 @@ bool RayCast2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
 	return false;
 }
 
-void RayCast2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
+void Cast2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
 	if (!node || !node->is_visible_in_tree()) {
 		return;
 	}
@@ -108,16 +112,16 @@ void RayCast2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
 	Transform2D gt = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
 
 	const Ref<Texture2D> handle = get_theme_icon(SNAME("EditorHandle"), SNAME("EditorIcons"));
-	p_overlay->draw_texture(handle, gt.xform(node->get_target_position()) - handle->get_size() / 2);
+	p_overlay->draw_texture(handle, gt.xform((Vector2)node->get("target_position")) - handle->get_size() / 2);
 }
 
-void RayCast2DEditor::edit(Node *p_node) {
+void Cast2DEditor::edit(Node2D *p_node) {
 	if (!canvas_item_editor) {
 		canvas_item_editor = CanvasItemEditor::get_singleton();
 	}
 
-	if (p_node) {
-		node = Object::cast_to<RayCast2D>(p_node);
+	if (Object::cast_to<RayCast2D>(p_node) || Object::cast_to<ShapeCast2D>(p_node)) {
+		node = p_node;
 	} else {
 		node = nullptr;
 	}
@@ -125,27 +129,27 @@ void RayCast2DEditor::edit(Node *p_node) {
 	canvas_item_editor->update_viewport();
 }
 
-RayCast2DEditor::RayCast2DEditor() {
+Cast2DEditor::Cast2DEditor() {
 	undo_redo = EditorNode::get_singleton()->get_undo_redo();
 }
 
 ///////////////////////
 
-void RayCast2DEditorPlugin::edit(Object *p_object) {
-	ray_cast_2d_editor->edit(Object::cast_to<RayCast2D>(p_object));
+void Cast2DEditorPlugin::edit(Object *p_object) {
+	cast_2d_editor->edit(Object::cast_to<Node2D>(p_object));
 }
 
-bool RayCast2DEditorPlugin::handles(Object *p_object) const {
-	return Object::cast_to<RayCast2D>(p_object) != nullptr;
+bool Cast2DEditorPlugin::handles(Object *p_object) const {
+	return Object::cast_to<RayCast2D>(p_object) != nullptr || Object::cast_to<ShapeCast2D>(p_object) != nullptr;
 }
 
-void RayCast2DEditorPlugin::make_visible(bool p_visible) {
+void Cast2DEditorPlugin::make_visible(bool p_visible) {
 	if (!p_visible) {
 		edit(nullptr);
 	}
 }
 
-RayCast2DEditorPlugin::RayCast2DEditorPlugin() {
-	ray_cast_2d_editor = memnew(RayCast2DEditor);
-	EditorNode::get_singleton()->get_gui_base()->add_child(ray_cast_2d_editor);
+Cast2DEditorPlugin::Cast2DEditorPlugin() {
+	cast_2d_editor = memnew(Cast2DEditor);
+	EditorNode::get_singleton()->get_gui_base()->add_child(cast_2d_editor);
 }

+ 17 - 17
editor/plugins/ray_cast_2d_editor_plugin.h → editor/plugins/cast_2d_editor_plugin.h

@@ -1,5 +1,5 @@
 /*************************************************************************/
-/*  ray_cast_2d_editor_plugin.h                                          */
+/*  cast_2d_editor_plugin.h                                              */
 /*************************************************************************/
 /*                       This file is part of:                           */
 /*                           GODOT ENGINE                                */
@@ -28,20 +28,20 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 
-#ifndef RAY_CAST_2D_EDITOR_PLUGIN_H
-#define RAY_CAST_2D_EDITOR_PLUGIN_H
+#ifndef CAST_2D_EDITOR_PLUGIN_H
+#define CAST_2D_EDITOR_PLUGIN_H
 
 #include "editor/editor_plugin.h"
-#include "scene/2d/ray_cast_2d.h"
+#include "scene/2d/node_2d.h"
 
 class CanvasItemEditor;
 
-class RayCast2DEditor : public Control {
-	GDCLASS(RayCast2DEditor, Control);
+class Cast2DEditor : public Control {
+	GDCLASS(Cast2DEditor, Control);
 
 	UndoRedo *undo_redo = nullptr;
 	CanvasItemEditor *canvas_item_editor = nullptr;
-	RayCast2D *node;
+	Node2D *node;
 
 	bool pressed = false;
 	Point2 original_target_position;
@@ -53,27 +53,27 @@ protected:
 public:
 	bool forward_canvas_gui_input(const Ref<InputEvent> &p_event);
 	void forward_canvas_draw_over_viewport(Control *p_overlay);
-	void edit(Node *p_node);
+	void edit(Node2D *p_node);
 
-	RayCast2DEditor();
+	Cast2DEditor();
 };
 
-class RayCast2DEditorPlugin : public EditorPlugin {
-	GDCLASS(RayCast2DEditorPlugin, EditorPlugin);
+class Cast2DEditorPlugin : public EditorPlugin {
+	GDCLASS(Cast2DEditorPlugin, EditorPlugin);
 
-	RayCast2DEditor *ray_cast_2d_editor = nullptr;
+	Cast2DEditor *cast_2d_editor = nullptr;
 
 public:
-	virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override { return ray_cast_2d_editor->forward_canvas_gui_input(p_event); }
-	virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override { ray_cast_2d_editor->forward_canvas_draw_over_viewport(p_overlay); }
+	virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override { return cast_2d_editor->forward_canvas_gui_input(p_event); }
+	virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override { cast_2d_editor->forward_canvas_draw_over_viewport(p_overlay); }
 
-	virtual String get_name() const override { return "RayCast2D"; }
+	virtual String get_name() const override { return "Cast2D"; }
 	bool has_main_screen() const override { return false; }
 	virtual void edit(Object *p_object) override;
 	virtual bool handles(Object *p_object) const override;
 	virtual void make_visible(bool visible) override;
 
-	RayCast2DEditorPlugin();
+	Cast2DEditorPlugin();
 };
 
-#endif // RAY_CAST_2D_EDITOR_PLUGIN_H
+#endif // CAST_2D_EDITOR_PLUGIN_H

+ 22 - 9
scene/2d/shape_cast_2d.cpp

@@ -217,7 +217,7 @@ void ShapeCast2D::_notification(int p_what) {
 			if (shape.is_null()) {
 				break;
 			}
-			Color draw_col = get_tree()->get_debug_collisions_color();
+			Color draw_col = collided ? Color(1.0, 0.01, 0) : get_tree()->get_debug_collisions_color();
 			if (!enabled) {
 				float g = draw_col.get_v();
 				draw_col.r = g;
@@ -235,18 +235,25 @@ void ShapeCast2D::_notification(int p_what) {
 
 			// Draw an arrow indicating where the ShapeCast is pointing to.
 			if (target_position != Vector2()) {
-				Transform2D xf;
-				xf.rotate(target_position.angle());
-				xf.translate_local(Vector2(target_position.length(), 0));
+				const real_t max_arrow_size = 6;
+				const real_t line_width = 1.4;
+				bool no_line = target_position.length() < line_width;
+				real_t arrow_size = CLAMP(target_position.length() * 2 / 3, line_width, max_arrow_size);
 
-				draw_line(Vector2(), target_position, draw_col, 2);
+				if (no_line) {
+					arrow_size = target_position.length();
+				} else {
+					draw_line(Vector2(), target_position - target_position.normalized() * arrow_size, draw_col, line_width);
+				}
 
-				float tsize = 8;
+				Transform2D xf;
+				xf.rotate(target_position.angle());
+				xf.translate_local(Vector2(no_line ? 0 : target_position.length() - arrow_size, 0));
 
 				Vector<Vector2> pts = {
-					xf.xform(Vector2(tsize, 0)),
-					xf.xform(Vector2(0, Math_SQRT12 * tsize)),
-					xf.xform(Vector2(0, -Math_SQRT12 * tsize))
+					xf.xform(Vector2(arrow_size, 0)),
+					xf.xform(Vector2(0, 0.5 * arrow_size)),
+					xf.xform(Vector2(0, -0.5 * arrow_size))
 				};
 
 				Vector<Color> cols = { draw_col, draw_col, draw_col };
@@ -291,6 +298,8 @@ void ShapeCast2D::_update_shapecast_state() {
 	collision_safe_fraction = 0.0;
 	collision_unsafe_fraction = 0.0;
 
+	bool prev_collision_state = collided;
+
 	if (target_position != Vector2()) {
 		dss->cast_motion(params, collision_safe_fraction, collision_unsafe_fraction);
 		if (collision_unsafe_fraction < 1.0) {
@@ -314,6 +323,10 @@ void ShapeCast2D::_update_shapecast_state() {
 		}
 	}
 	collided = !result.is_empty();
+
+	if (prev_collision_state != collided) {
+		update();
+	}
 }
 
 void ShapeCast2D::force_shapecast_update() {