EditorNode3DGizmoPlugin in Godot – Complete Guide

Creating custom gizmos within the world editor can be a game-changer for level design and can think of them as the ultimate tools for manipulation and interaction with 3D nodes within Godot. If you’ve felt that the standard gizmos aren’t quite cutting it for your customized nodes or you want to enhance the workflow for your level design team, mastering EditorNode3DGizmoPlugin is your next step.

Understanding this powerful class can help you tailor the Godot editor to fit your unique project needs, elevating your development process to new heights. Let’s dive in and explore what this class is all about, its applications, and how it can empower you to craft intuitive and robust tools for game development.

What Is EditorNode3DGizmoPlugin?

EditorNode3DGizmoPlugin is a class in the Godot engine that allows developers to create and define their own types of 3D gizmos. For those unfamiliar with gizmos, these are the interactive tools you see in the editor space that allow you to manipulate nodes. They are the move, rotate, and scale tools that you interact with when positioning your objects in 3D space.

What Is It For?

The utility of the EditorNode3DGizmoPlugin extends to the creation of specialized gizmos geared towards your project’s particular nodes. Imagine designing a game where you have dynamic bridges that can extend or retract. With a custom gizmo, you could interactively adjust the length of the bridge right in the editor, seeing real-time changes without tweaking numbers in a dialog box or adjusting code. This direct interaction can make the design process more intuitive and visual.

Why Should I Learn It?

Learning how to use EditorNode3DGizmoPlugin can significantly improve the workflow for anyone involved in the 3D design process within Godot. It’s not just about creating convenience; it’s about implementing precise control over custom features of your game’s assets straight from the editor. This knowledge is invaluable for:

– Increasing efficiency in level design
– Reducing the need to jump in and out of script files for minor adjustments
– Providing visual and interactive feedback that accelerates the design process

By creating custom gizmos, your editor can become more than just a workspace; it transforms into a powerful and bespoke toolkit tailored to your game’s specific needs.

CTA Small Image
FREE COURSES AT ZENVA
LEARN GAME DEVELOPMENT, PYTHON AND MORE
ACCESS FOR FREE
AVAILABLE FOR A LIMITED TIME ONLY

Getting Started with EditorNode3DGizmoPlugin

To begin, you need to create a new script that extends the EditorNode3DGizmoPlugin class. This is where you will define the functionalities of your custom gizmo.

extends EditorSpatialGizmoPlugin

func _can_be_hidden() -> bool:
    return false

func _has_gizmo(spatial: Spatial) -> bool:
    return spatial is YourCustomNode3D # Replace with your own condition.

func _create_gizmos(spatial: Spatial) -> EditorSpatialGizmo:
    var gizmo = EditorSpatialGizmo.new()
    gizmo.set_spatial_node(spatial)
    # Add gizmo meshes, materials, and handles here!
    return gizmo

It’s time to create the visual representation for your gizmo. This typically involves defining meshes and materials which make up the visual tools that will appear in the godot editor.

func _create_gizmos(spatial: Spatial) -> EditorSpatialGizmo:
    var gizmo = EditorSpatialGizmo.new()
    gizmo.set_spatial_node(spatial)
    
    # Create a simple material for the gizmo
    var unselected_material = create_material("GizmoMaterialUnselected",
        Color(1, 0, 0), false, true)

    # Set gizmo meshes here. For example, creating a sphere handle:
    gizmo.add_handles(Array([Vector3(0, 0, 1)]), unselected_material)
    
    return gizmo

Interacting with the Gizmo

To interact with the gizmo, you need to implement the following:

– `_commit_handle` is called when the user releases the handle after modifying it.
– `_set_handle` is another function to define how the property of the node is updated when the handle is moved.

Below is an example of how these functions could be implemented for a simple transformation gizmo:

var edited_spatial: Spatial # The spatial node being edited.

func _commit_handle(for_gizmo: EditorSpatialGizmo,
                    index: int, restore: Variant, cancel: bool):
    if cancel:
        edited_spatial.set_transform(restore)
    else:
        emit_signal("scene_changed", edited_spatial, "Transform")
        
func _set_handle(for_gizmo: EditorSpatialGizmo,
                 index: int, camera: Camera, point: Vector2):
    var transform = edited_spatial.transform
    # assuming we're moving along z-axis
    transform.origin.z = some_calculation_with_point(point)
    edited_spatial.set_transform(transform)

Updating the Gizmo Based on the Node’s State

You can update your gizmo based on changes to the node by overriding the `_redraw` method:

func _redraw(for_gizmo: EditorSpatialGizmo):
    var spatial = for_gizmo.get_spatial_node()
    
    # Update the gizmo's position here according to spatial's state
    # For example, replicating the spatial's transform:
    var new_transform = spatial.get_global_transform()
    for_gizmo.clear()
    for_gizmo.add_mesh( some_mesh_resource, false, new_transform )

Custom gizmos can also have selectable handles to allow for precise manipulation. To enable this feature, use the `add_handles` function:

func _create_gizmos(spatial: Spatial) -> EditorSpatialGizmo:
    ...
    
    # If you have move handles
    gizmo.add_handles(Array([Vector3(1, 0, 0), Vector3(0, 1, 0), Vector3(0, 0, 1)]),
                      unselected_material, true, true)
    
    return gizmo

Remember, when working with visual interaction in the editor, it’s crucial to rigorously test the gizmo to ensure that its handles map correctly to the node’s properties and behaviors. This ensures a smooth and intuitive editing experience for you or any other developer working within Godot’s 3D environment.

Handling Custom Gizmo States

It’s essential to handle different states of the gizmo to provide appropriate feedback to the user. For instance, changing the material of the gizmo when it’s selected can improve visibility and user experience.

var unselected_material = create_material("GizmoMaterialUnselected", Color(1, 0, 0), false, true)
var selected_material = create_material("GizmoMaterialSelected", Color(0, 1, 0), false, true)

func _create_gizmos(spatial: Spatial) -> EditorSpatialGizmo:
    ...
    
    if is_selected(spatial):
        gizmo.add_mesh(some_mesh_resource, false, spatial.global_transform, selected_material)
    else:
        gizmo.add_mesh(some_mesh_resource, false, spatial.global_transform, unselected_material)
    
    ...

In the example above, the `is_selected` function checks whether the gizmo should be in the selected state and applies the appropriate material accordingly.

Customizing Handle Interaction

Gizmos usually have handles that can be dragged to manipulate the node’s properties. You can customize these interactions to match your custom node’s behavior. Below is an example of how to handle a custom scaling handle:

func _get_handle_name(gizmo: EditorSpatialGizmo, index: int) -> String:
    return "Scale"

func _get_handle_value(gizmo: EditorSpatialGizmo, index: int):
    return edited_spatial.scale

func _set_handle(gizmo: EditorSpatialGizmo, index: int, value: Variant):
    edited_spatial.scale = value

These functions define the name and value of the handle, as well as how to update the spatial node when the handle is moved.

Implementing Custom Properties on Handles

If your node’s gizmo requires interaction beyond the basic transformation handles, you may need to define custom properties or behaviors for your handles:

func _get_handle_name(gizmo: EditorSpatialGizmo, index: int) -> String:
    match index:
        0: 
            return "CustomPropertyX"
        1: 
            return "CustomPropertyY"
        2: 
            return "CustomPropertyZ"

In this example, each handle is associated with a different custom property of the node (e.g., ‘CustomPropertyX’, ‘CustomPropertyY’, ‘CustomPropertyZ’).

Using the Right Appearance for Gizmos

To enhance the clarity and usability of your gizmo, you may need to define different visual aspects.

var custom_handle_material = create_handle_material("CustomHandleMat", Color(1, 1, 0))

func _create_gizmos(spatial: Spatial) -> EditorSpatialGizmo:
    ...
    
    gizmo.add_handles(Array([Vector3(0, 0, 1)]), custom_handle_material)
    
    ...

Here, a custom material is created specifically for the handles, with a distinctive color to make it stand out from other elements in the editor.

Scripting Gizmo Visibility and Selectivity

Sometimes, you may want to program the conditions under which a gizmo is visible or selectable:

func _is_handle_highlighted(gizmo: EditorSpatialGizmo, index: int) -> bool:
    # implement logic to decide if the handle is highlighted
    return should_highlight_handle

func _can_select_handle(gizmo: EditorSpatialGizmo, index: int) -> bool:
    # implement logic to decide if the handle can be selected
    return can_select_handle

In these methods, custom logic can be implemented to control handle highlighting and selection, respectively.

By exploring these aspects of the EditorNode3DGizmoPlugin, you can fully customize your Godot editor’s 3D interaction to suit your unique development needs. With practice and experimentation, creating custom gizmos will become second nature, allowing you to craft an efficient, powerful, and personalized level designing experience.Customizing the gizmo’s appearance and functionality might require more complex code snippets that toggle display features or handle advanced interactions. Let’s look at some additional examples to expand the possibilities you have with EditorNode3DGizmoPlugin.

Implementing Advanced Gizmo Functions

Sometimes, your gizmo may need to respond to specific editor interactions other than just selection and movement:

func _intersect_ray(gizmo: EditorSpatialGizmo, ray_origin: Vector3, ray_dir: Vector3) -> int:
    # Here you would put logic to check if and where a ray intersects the gizmo.
    var handle_idx = -1  # If no intersection, return -1
    # Perform the intersection logic
    return handle_idx  # Return the index of the intersecting handle

This function is used to detect when an interaction ray, such as a mouse click, intersects with the gizmo.

Additionally, custom gizmos might need to change appearance when hovered or selected. This can be achieved with different materials when the state changes.

func _is_handle_highlighted(gizmo: EditorSpatialGizmo, index: int) -> bool:
    var is_hovered = determine_if_handle_is_hovered(index)  # Replace with your logic
    return is_hovered

Implementing this function can give live feedback when a handle is hovered over, which is important for user experience.

Custom gizmos may provide abilities beyond just selecting handles. You can define a function for activating an “auxiliary” feature of the gizmo when the user presses a key or clicks an on-screen button.

func _activate_auxiliary_function(index: int):
    # You could initiate a special action linked to the gizmo here.
    if index == 1:
        perform_special_action()

This method allows you to add shortcuts or special triggers to your gizmo for more complex interactions.

Handling multiple gizmos might require a way to define if and how these should rotate with the node they are attached to:

func _can_gizmo_rotate_with_node(gizmo: EditorSpatialGizmo) -> bool:
    return should_rotate_with_node  # Return your boolean condition here

By overwriting this method, you ensure that the gizmo alignment behaves in sync with the node’s rotation where needed.

Code Snippets for Manipulating Handles

Here’s how you can manage the manipulation of handles that control specific properties.

func _get_handle_name(gizmo: EditorSpatialGizmo, index: int) -> String:
    return "Length"

func _set_handle(gizmo: EditorSpatialGizmo, index: int, camera: Camera, point: Vector2):
    # Assuming the gizmo modifies the length of a custom mesh
    var new_length = some_calculation_with_camera_and_point(camera, point)
    edited_spatial.set("length", new_length)  # Update the property directly.targeted_property(new_value)

This code provides a way to set the name of a handle and define the updating behavior based on user interaction.

Finalizing Your Gizmo

Once you have defined how your gizmo will appear and act within the Godot Editor, you must register it so that it can be used with your custom nodes:

func _enter_tree():
    add_gizmo_plugin(self)

func _exit_tree():
    remove_gizmo_plugin(self)

These two methods ensure that your gizmo plugin is registered when the script is loaded and removed when it’s no longer in use.

As you integrate these examples into your project, you will see how versatile and powerful EditorNode3DGizmoPlugin can be, enabling you to create helpful visual aids and tools within the Godot editor. This can make complex 3D node manipulation much more intuitive and save developers time, thus resulting in a smoother game development process. Remember to test each new functionality thoroughly to ensure it behaves as expected and provides a helpful addition to your 3D editing workflow.

Continue Your Game Development Journey with Zenva

Embarking on your gizmo-creating adventure in Godot is just the beginning. To deepen your mastery over game development, our Godot Game Development Mini-Degree offers an extensive collection of courses designed to take your skills to the next level. Whether you’re curious about 2D and 3D game mechanics, or you want to delve into the intricacies of GDScript, you’ll find a structured learning path waiting for you.

Not only will you build real games from scratch, but you’ll also gain hands-on experience applying your knowledge in a variety of genres. With Zenva, you learn at your own pace, and upon completion, you’ll have certificates to showcase your newly acquired expertise. Our Godot courses are tailored to suit both beginners and more experienced developers, ensuring there is valuable content for every learner.

If you’re eager to explore a broader spectrum of topics or find courses that match your current proficiency, our full range of Godot courses is at your fingertips. Start with the basics or challenge yourself with advanced projects – with Zenva, your journey is what you make of it. We’re excited to see the amazing games you’ll create!

Conclusion

Delving into the power of Godot’s EditorNode3DGizmoPlugin is just a slice of the immense world of game development – a world that we at Zenva are passionate about guiding you through. Crafting custom gizmos is a testament to your growing expertise and creativity in game creation. It’s these nuanced skills that can truly differentiate your projects, streamline your workflows, and bring your imaginative worlds to life with precision and flair.

But why stop here? Continue to sharpen your skills and expand your knowledge with our comprehensive Godot Game Development Mini-Degree. Each lesson is a stepping stone towards becoming the game developer you aspire to be, and we’re here to support you at every turn. So buckle up—your game development journey is bound for remarkable places, and it’s our privilege to help you get there!

FREE COURSES
Python Blog Image

FINAL DAYS: Unlock coding courses in Unity, Godot, Unreal, Python and more.