Add Editor Visualization Support for MovingHazard Nodes
Opened this issue · 0 comments
Currently, when setting up MovingHazard nodes in the editor, level designers have no visual feedback about the node's movement path, final position, rotation, or scale until they run the game. This makes it difficult to precisely position and configure these nodes. We need to implement editor visualization that shows the complete movement pattern directly in the editor viewport.
Current Behavior
MovingHazard nodes support configuration of:
- Desired position (relative to initial position)
- Desired rotation (in degrees)
- Desired scale
- Animation duration
However, these properties must be set numerically through the inspector, with no visual preview of their effects. Level designers must frequently enter play mode to verify their configurations, leading to an inefficient workflow.
Proposed Enhancement
Implement an editor visualization system for MovingHazard nodes that provides immediate visual feedback in the editor viewport. The visualization should include:
Visual Elements
-
Movement Path Indicator
- A solid yellow line showing the path from the initial position to the target position
- Only visible when desired_position is non-zero
- Updates in real-time as position values change
-
Target State Preview
- A semi-transparent yellow box showing the node's final position and scale
- Colored axis indicators (red: X, green: Y, blue: Z) showing the final orientation
- Updates dynamically with any property changes
Technical Implementation
The feature requires three main components:
- Core MovingHazard Script Enhancement
@tool
extends AnimatableBody3D
# Add @tool annotation to enable editor functionality
# Implement property change notifications
- Custom Editor Plugin
# New file: addons/moving_hazard/moving_hazard_plugin.gd
# Handles plugin initialization and cleanup
# Registers the custom gizmo
- Custom Gizmo Implementation
# New file: addons/moving_hazard/moving_hazard_gizmo.gd
# Implements the actual visualization rendering
# Handles transform calculations and updates
User Interface
The visualization should be toggleable through a new inspector property:
- Property Name: "Show Debug Path"
- Type: bool
- Default: true
- Updates visualization immediately when toggled
File Structure
addons/
moving_hazard/
moving_hazard_plugin.gd
moving_hazard_gizmo.gd
Technical Requirements
Dependencies
- Godot 4.x
- EditorNode3DGizmoPlugin system
- @tool script functionality
Performance Considerations
- Visualizations should only be computed and rendered in the editor
- Updates should be efficient and not impact editor performance
- Memory usage should be minimal, cleaning up resources when nodes are removed
Error Handling
- Properly handle edge cases like zero movement or rotation
- Provide clear warnings in the editor for invalid configurations
- Ensure visualization updates properly when undo/redo operations are performed
Benefits
-
Improved Level Design Workflow
- Immediate visual feedback for configuration changes
- Reduced need to enter play mode for verification
- More intuitive positioning and rotation setup
-
Reduced Error Potential
- Visual confirmation of movement paths
- Clear indication of final states
- Immediate feedback for unintended configurations
-
Better Editor Integration
- Consistent with Godot's built-in visualization systems
- Professional-grade development experience
- Enhanced productivity for level designers
Implementation Notes
The visualization system should be implemented using Godot's official EditorNode3DGizmoPlugin system rather than custom drawing or mesh instances. This ensures proper integration with the editor's rendering pipeline and maintains consistent behavior with other editor visualizations.
Future Enhancements
Once the basic visualization system is implemented, potential future enhancements could include:
- Interactive gizmos for direct manipulation of target states
- Animation preview in the editor
- Custom visualization colors and styles
- Multiple waypoint support
- Path curve visualization for different movement patterns
Example code
# addons/moving_hazard/moving_hazard_plugin.gd
@tool
extends EditorPlugin
var gizmo_plugin = preload("res://addons/moving_hazard/moving_hazard_gizmo.gd").new()
func _enter_tree():
add_node_3d_gizmo_plugin(gizmo_plugin)
func _exit_tree():
remove_node_3d_gizmo_plugin(gizmo_plugin)
# addons/moving_hazard/moving_hazard_gizmo.gd
@tool
extends EditorNode3DGizmoPlugin
func _init():
# Create a new gizmo plugin with default settings
create_material("path", Color(1, 1, 0, 0.3)) # Semi-transparent yellow
create_material("path_lines", Color(1, 1, 0)) # Solid yellow
create_handle_material("handles")
func _has_gizmo(node):
# Only show gizmo for MovingHazard nodes
return node is Node3D and node.get_script() and node.get("show_debug_path")
func _redraw(gizmo: EditorNode3DGizmo):
gizmo.clear()
# Get the node we're drawing for
var node = gizmo.get_node_3d()
if not node.show_debug_path:
return
# Get the transforms we need
var start_transform = node.transform
var target_transform = start_transform * node._calculate_target_transform()
# Create our visualization meshes
var path_points = PackedVector3Array()
path_points.push_back(Vector3.ZERO) # Start point
path_points.push_back(node.desired_position) # End point
# Draw the path line
if node.desired_position != Vector3.ZERO:
gizmo.add_lines(path_points, get_material("path_lines", gizmo))
# Draw target position box
var box_mesh = BoxMesh.new()
box_mesh.size = node.desired_scale
gizmo.add_mesh(box_mesh, get_material("path", gizmo), target_transform)
# Draw orientation axes at target
var axis_points = PackedVector3Array()
var axis_colors = PackedColorArray()
var axis_length = 0.5
# X axis (red)
axis_points.push_back(node.desired_position)
axis_points.push_back(node.desired_position + Vector3(axis_length, 0, 0))
axis_colors.push_back(Color(1, 0, 0))
axis_colors.push_back(Color(1, 0, 0))
# Y axis (green)
axis_points.push_back(node.desired_position)
axis_points.push_back(node.desired_position + Vector3(0, axis_length, 0))
axis_colors.push_back(Color(0, 1, 0))
axis_colors.push_back(Color(0, 1, 0))
# Z axis (blue)
axis_points.push_back(node.desired_position)
axis_points.push_back(node.desired_position + Vector3(0, 0, axis_length))
axis_colors.push_back(Color(0, 0, 1))
axis_colors.push_back(Color(0, 0, 1))
gizmo.add_lines(axis_points, get_material("path_lines", gizmo), axis_colors)