EditorProperty in Godot – Complete Guide

Creating unique and robust user interfaces is a key aspect of game development, especially when it comes to creating custom property editors in game engines. Godot 4 introduces a powerful feature for developers: the EditorProperty class, which allows for the seamless extension and customization of the built-in EditorInspector. Understanding and utilizing EditorProperty can significantly elevate your game development process, providing you with the tools to craft detailed and specific property editing experiences in the Godot editor.

What is EditorProperty?

EditorProperty is a custom control class within Godot 4’s engine that developers can use to create tailored property editors. These custom editors are then integrated into the main engine’s inspector, allowing for a unified and interactive development environment.

What is it for?

The primary purpose of the EditorProperty class is to enable the customization of property editing within the Godot editor itself. This means you can create specific controls for making tweaks and changes to a game’s properties efficiently, all while working within the editor’s ecosystem.

Why Should I Learn It?

Learning how to implement and use the EditorProperty class is critical for developers who want to create an efficient workflow and enhance the user experience for anyone interacting with their game within Godot’s editor. It unlocks the ability to manipulate custom property additions and allows for a more dynamic and intuitive interface when configuring game aspects like objects, animations, and scripts.

Armed with this understanding, let’s delve into the powerful capabilities of the EditorProperty class and learn how to harness its features to upgrade your Godot game development skills.

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 EditorProperty

Before diving into specific examples, we must understand how to set up an EditorProperty. We’ll start by subclassing the EditorProperty and then overriding its essential methods to create our custom property editor.

extends EditorProperty
func _init():
    # Initialize your custom EditorProperty here.

func _update_property():
    # This function is called to update the property's value.

func _get_property():
    # Override this method to return the current value of your property.

This template provides the groundwork for your EditorProperty. The `_init()` function is where your property editor’s initialization code will reside. The `_update_property()` method allows for updates to your property, while the `_get_property()` will enable you to retrieve the current value.

Creating Custom Numeric Input

Let’s create a custom editor property to handle numeric input in a unique way. For instance, if you’d like to have an input field only for prime numbers, you could write:

extends EditorProperty
var prime_number = 2

func _init():
    add_child(LineEdit.new())

func _update_property():
    prime_number = get_object().get(get_property())
    get_child(0).text = str(prime_number)

func _get_property():
    return prime_number

These snippets give you a basic line edit that displays a prime number. However, this implementation does not include the logic to check if a number is prime. You would need to add additional functionality to your `_update_property()` method to ensure that non-prime numbers cannot be entered.

Integrating a Custom Range Slider

Alternatively, you may want to create a slider that only accepts a specific range of values, such as a slider that goes from 0 to 100 but only in increments of 10:

extends EditorProperty
var range_value = 0

func _init():
    var hslider = HSlider.new()
    hslider.min_value = 0
    hslider.max_value = 100
    hslider.step = 10
    hslider.connect("value_changed", self, "_on_value_changed")
    add_child(hslider)

func _update_property():
    range_value = get_object().get(get_property())
    get_child(0).value = range_value

func _get_property():
    return range_value

func _on_value_changed(value):
    range_value = value
    _change_notify() # Notifies the inspector that the value has changed

This custom EditorProperty contains a horizontal slider, which we’ve set up to only accept values multiple of 10. It’s crucial that any changes in the slider’s value get correctly communicated back to the object and the inspector, which we handle in the `_on_value_changed` method.

Handling Vector Properties

Godot’s EditorProperties are incredibly versatile and can be applied to complex data types like vectors. For instance, a custom EditorProperty for `Vector2` might look like this:

extends EditorProperty
var vector_value = Vector2()

func _init():
    var spinbox_x = SpinBox.new()
    var spinbox_y = SpinBox.new()

    spinbox_x.connect("value_changed", self, "_on_spinbox_x_changed")
    spinbox_y.connect("value_changed", self, "_on_spinbox_y_changed")

    add_child(spinbox_x)
    add_child(spinbox_y)

func _update_property():
    vector_value = get_object().get(get_property())
    get_child(0).value = vector_value.x
    get_child(1).value = vector_value.y

func _on_spinbox_x_changed(value):
    vector_value.x = value
    _change_notify()

func _on_spinbox_y_changed(value):
    vector_value.y = value
    _change_notify()

This example would give you two SpinBoxes, one for each `x` and `y` component of your vector. This allows for fine-tuned control over Vector2 properties in the inspector.

These examples should get you started on creating your custom EditorProperty controls in Godot. Always remember to connect your UI elements to change events and notify the inspector, ensuring that changes are saved and undoable within Godot’s robust editor environment.Manipulating Colors with a Custom Color Picker
For a game where the aesthetics heavily rely on color customization, a bespoke color picker could be instrumental. Let’s construct an EditorProperty that uses Godot’s built-in ColorPicker, but with constraints that we design for our game’s specific needs:

extends EditorProperty
var color_value = Color(1, 1, 1, 1) # default white color

func _init():
    var color_picker = ColorPicker.new()
    # Customize your ColorPicker, for example:
    color_picker.edit_alpha = false
    color_picker.connect("color_changed", self, "_on_color_changed")
    add_child(color_picker)

func _update_property():
    color_value = get_object().get(get_property())
    get_child(0).color = color_value  # Assumes ColorPicker is first child

func _on_color_changed(new_color):
    color_value = new_color
    _change_notify()

In this code snippet, we leave out alpha editing by setting `edit_alpha` to false, allowing the user to select only solid colors without transparency. You can adapt further by restricting color choices or modifying the layout for your specific use-case.

Implementing an Asset Selection EditorProperty
In a situation where you need a custom asset selector for a particular type of asset, for example, a sprite sheet, you might write something like this:

extends EditorProperty
var selected_asset

func _init():
    var file_dialog = FileDialog.new()
    file_dialog.mode = FileDialog.MODE_OPEN_FILE
    file_dialog.connect("file_selected", self, "_on_file_selected")
    add_child(file_dialog)
    var button = Button.new()
    button.text = "Select Sprite Sheet"
    button.connect("pressed", file_dialog, "popup_centered")
    add_child(button)

func _update_property():
    selected_asset = get_object().get(get_property())

func _on_file_selected(path):
    selected_asset = path
    _change_notify()

The above example uses a `FileDialog` connected to a button for user interaction, which allows for selecting a file from the filesystem that matches our specific requirements. Again, connecting the relevant signals ensures that any changes are registered by the editor.

Enhancing Enum Property Representation
Godot allows the use of enums in GDScript, but sometimes representing these enums in the editor requires more intuitive interfaces. For example, let’s define a custom editor for an enum property:

extends EditorProperty
enum CharacterClasses { Mage, Warrior, Rogue }

var character_class = CharacterClasses.Warrior

func _init():
    var option_button = OptionButton.new()
    for cls in CharacterClasses.values():
        option_button.add_item(str(cls), cls)
    option_button.connect("item_selected", self, "_on_item_selected")
    add_child(option_button)

func _update_property():
    character_class = CharacterClasses(get_object().get(get_property()))
    get_child(0).selected = character_class

func _on_item_selected(index):
    character_class = CharacterClasses(index)
    _change_notify()

This code snippet creatively uses an `OptionButton` to allow the game developer to select a character class from predefined enums.

Visualizing and Controlling Arrays
When dealing with properties that are arrays, a list representation could streamline item management. We could create a control to add, remove, and visualize elements in an array:

extends EditorProperty
var items = []

func _init():
    var item_list = ItemList.new()
    item_list.allow_reselect = true
    item_list.allow_rmb_select = true
    item_list.connect("item_selected", self, "_on_item_selected")
    add_child(item_list)
    var add_button = Button.new()
    add_button.text = "Add"
    add_button.connect("pressed", self, "_on_add_pressed")
    add_child(add_button)
    var remove_button = Button.new()
    remove_button.text = "Remove"
    remove_button.connect("pressed", self, "_on_remove_pressed")
    add_child(remove_button)

func _update_property():
    items = get_object().get(get_property())
    get_child(0).clear()
    for item in items:
        get_child(0).add_item(str(item))

func _on_item_selected(index):
    # Code to handle item selection

func _on_add_pressed():
    items.append("New Item")
    _change_notify()
    _update_property()

func _on_remove_pressed():
    var item_list = get_child(0)
    var selected_items = item_list.get_selected_items()
    for index in selected_items:
        items.remove(index)
    _change_notify()
    _update_property()

These controls provide an easy way to manipulate array properties, with buttons linked to functions to add and remove items.

By harnessing and extending the functionality of EditorProperty in Godot 4, you can craft a user experience in the editor that is highly tailored to the specific needs of your game project. This bespoke touch can significantly streamline the development process, making your workflow faster and more efficient.Let’s look at how we can continue to enhance the Godot 4 editor with custom EditorProperty implementations. These examples focus on providing practical solutions for common development needs.

Enhancing Experience with Tooltips
Sometimes, properties benefit from additional context or instructions. Implementing tooltips over your EditorProperty can clarify their purpose to developers using your tools:

extends EditorProperty
func _init():
    var button = Button.new()
    button.text = "Hover Over Me"
    button.hint_tooltip = "Clicking this button will do something special."
    add_child(button)

The `hint_tooltip` attribute on the button control ensures that whenever the user hovers over the button, they receive a useful piece of information.

Adding Preview Capabilities
When dealing with assets like texture or audio files, presenting a thumbnail or a play button directly in the property editor is immensely helpful:

extends EditorProperty
var texture_resource: Texture

func _init():
    var texture_button = TextureButton.new()
    texture_button.connect("pressed", self, "_on_texture_button_pressed")
    add_child(texture_button)

func _update_property():
    texture_resource = get_object().get(get_property())
    get_child(0).texture = texture_resource

func _on_texture_button_pressed():
    # You could add behavior here to open up a larger preview or similar actions.

This example creates a simple `TextureButton` that shows the currently assigned texture and can be expanded to enable larger previews or other actions upon button press.

Implementing Conditional Visibility
Sometimes properties should only be visible under certain conditions or based on other property values. The following example demonstrates how to toggle property visibility:

extends EditorProperty
var is_visible = true

func _init():
    var checkbox = CheckBox.new()
    checkbox.text = "Toggle Property Visibility"
    checkbox.connect("toggled", self, "_on_checkbox_toggled")
    add_child(checkbox)

func _on_checkbox_toggled(toggled):
    is_visible = toggled
    # Assuming the property to be toggled is the first added child after the checkbox.
    get_child(1).visible = is_visible

func _update_property():
    # Update the property considering the is_visible flag.

This control uses a checkbox to toggle the visible status of another property. This approach could be used to clean up the inspector by only showing relevant properties.

Handling Dynamic Enum Properties
For properties that are enums where the range of values can change at runtime, you’d want to be able to update the list dynamically:

extends EditorProperty
var enum_values = ["Apple", "Banana", "Cherry"]

func _init():
    var option_button = OptionButton.new()
    _populate_option_button(option_button)
    option_button.connect("item_selected", self, "_on_item_selected")
    add_child(option_button)

func _populate_option_button(option_button: OptionButton):
    option_button.clear()
    for value in enum_values:
        option_button.add_item(value)

func _on_item_selected(index):
    # Handle the selection change.

func _update_property():
    # Update the enum property from the node and adjust button display.

The `_populate_option_button` method allows you to dynamically update the items in the `OptionButton`, and is called both during initialization and whenever the enum needs to be refreshed.

Creating Property Groups
You might want to organize related properties together visually to enhance usability. This can be achieved by grouping them under a collapsible panel:

extends EditorProperty
func _init():
    var vbox = VBoxContainer.new()
    var collapse_button = Button.new()
    collapse_button.toggle_mode = true
    collapse_button.text = "Toggle Group"
    var property_group = VBoxContainer.new()
    # Add your nested properties here to property_group.
    collapse_button.connect("toggled", property_group, "set_visible")
    
    vbox.add_child(collapse_button)
    vbox.add_child(property_group)
    add_child(vbox)

Here, pressing the `collapse_button` will show or hide `property_group`, allowing you to manage the accessibility of property clusters conveniently.

These snippets demonstrate various ways to enrich the Godot 4 editor with custom property editors. Tailoring EditorProperty controls not only makes the editor more intuitive and efficient for game developers but also allows for a more refined and controlled asset management system within your projects. These enhanced interactions can significantly contribute to the overall quality and robustness of game development within Godot.

Next Steps in Your Game Development Journey

Armed with knowledge about custom property editors in Godot 4, you’re well on your way to becoming a more proficient game developer. However, this is just the beginning—there’s a whole world of Godot insights and development skills waiting for you to explore. To continue your journey, our Godot Game Development Mini-Degree is the perfect next step to further enhance your game creation abilities.

This comprehensive program covers a wide range of topics, from the fundamentals of 2D and 3D game creation to more complex systems such as UI design and gameplay control flow. The courses in this Mini-Degree are self-paced and project-based, providing you with a flexible learning structure that allows for hands-on experience as you build your professional portfolio.

For those looking for even more Godot content, our full collection of Godot courses covers various aspects of game development, catering to both beginners and experienced learners alike. With Zenva, you’ll have all the resources you need to transition from a beginner to a professional game developer. So why wait? Take the next step and elevate your game development skills with us today!

Conclusion

Mastering the art of creating custom property editors in Godot 4 with the EditorProperty class opens up a new realm of possibilities for your game development process. By personalizing the Godot editor, not only can you optimize your workflow, but you can also provide a level of custom interaction that traditional tools can’t match. Whether it’s through fine-tuning numeric inputs, crafting intuitive color pickers, or arranging property groups for better organization, you have the power to shape the editor to fit your game’s unique needs and artistic vision.

Remember, this is only one facet of game development with Godot. There is so much more to learn and explore. Dive deeper into the world of game creation with our Godot Game Development Mini-Degree and unlock the full potential of this powerful engine. With Zenva, you can transform your ideas into reality and forge your path in the gaming industry. Start with us today, and take your first steps towards publishing your very own game!

FREE COURSES
Python Blog Image

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