Extending the Editor with Plugins in Godot
Embark on a journey to harness the true power of Godot with editor plugins! Revolutionize your workflow with bespoke tools, efficient shortcuts, and personalized menu options. Delve deep into the art of plugin creation and unlock the boundless potential of Godot with ease. By Eric Van de Kerckhove.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Extending the Editor with Plugins in Godot
45 mins
- Getting Started
- Plugin Overview
- Creating Your First Plugin
- Scaffolding
- Taking a Closer Look
- Handling Node Selection
- Adding the Button
- Developing an Advanced Plugin
- Creating the Menu Scene
- Loading and Unloading the Menu
- Getting Selected Nodes
- 2D Physics in Godot
- Starting and Stopping Physics
- Custom Physics Spaces
- Physics Frames
- Adding Quality of Life Features
- Where to Go From Here?
Handling Node Selection
For the visibility button plugin, you won’t need the _enter_tree
and _exit_tree
functions so delete them. You’ll be handling the initialization and cleanup with other functions. Now add the function below in the place of the removed ones:
func _handles(object) -> bool:
return object is Node
Godot calls the _handles
function when you select an object. The Object
class is the base class for all other classes in Godot. This function returns true
if the selected object can be handled by your plugin. In this case, the plugin only edits nodes, so it returns true
if the selected object is a Node
class, or derives from it.
You’ll need to keep track of the selected node yourself, so add a new variable above the _handles
function named node_to_edit
:
var node_to_edit : Node
With this variable in place, add the _edit
function below the _handles
function:
func _edit(object: Object) -> void: # 1
if !object: # 2
return
node_to_edit = object # 3
The _edit
function is called by Godot right after the _handles
function returns true
. It requests the editor to edit the given object and it’s the perfect place to store a reference to the selected object. Here’s an overview of what’s happening here:
- The
_edit
function gets passed the selected object, aNode
in case of this plugin. - There’s a possibility that the selected object is null, so you need to check if it’s not. If it’s null, return from the function and don’t do anything.
- Store a reference to the selected object for later use.
To check if this code is working correctly, add a temporary print statement at the end of the _edit
function:
print(node_to_edit)
Now save the script and try selecting some nodes in the scene tree. You should see the name of the selected node in the console.
As you can see, the plugin already works!
_edit
twice. Thankfully, this won’t affect the functionality of the plugin.
Now remove or comment out the print statement you’ve added and save the script again. The last function to bring it all together is the _make_visible
function, add it below the _edit
function:
func _make_visible(visible: bool) -> void: # 1
if visible: # 2
_add_button()
else: # 3
_remove_button()
Like the _edit
function, Godot calls the _make_visible
function after the _handles
function returns true
. It handles the showing and hiding of the plugin UI. It also gets called when disabling the plugin. When showing the button, you’ll create it and add it to the toolbar. When hiding the button, you’ll remove it from the toolbar and destroy it. This is an alternative to using the _enter_tree
and _exit_tree
functions for initialization and cleanup.
Here’s the code above in more detail:
- The
_make_visible
function gets passed a boolean value,visible
to tell the UI to show or hide. - If
visible
istrue
, add the button to the toolbar via the_add_button
function. - If
visible
isfalse
, remove the button from the toolbar via the_remove_button
function.
After adding the code, you’ll get some errors as you haven’t added the _add_button
and _remove_button
functions yet. Add these empty functions to get rid of the errors:
func _add_button() -> void:
pass
func _remove_button() -> void:
pass
These will act as placeholders for now. In the next section you’ll add the logic.
Adding the Button
Instead of using the editor to create a button, you’ll do so by code. To get started, you’ll need a variable to store a reference to the button. Add a new variable below var node_to_edit : Node
:
var visibility_button : Button
With that out of the way, replace the pass
keyword in the _add_button
function with the code below:
# 1
if visibility_button:
return
# 2
visibility_button = Button.new()
visibility_button.text = "Toggle visibility"
visibility_button.focus_mode = Control.FOCUS_NONE
visibility_button.flat = true
# 3
visibility_button.pressed.connect(_on_button_pressed)
# 4
add_control_to_container(EditorPlugin.CONTAINER_CANVAS_EDITOR_MENU, \
visibility_button)
Most of the code above is creating the button and setting it up. Here’s a breakdown:
- Check if the button already exists. If it does, return and don’t do anything.
- Create a new button and set its properties:
- Set the text of the button to “Toggle visibility”
- Disable the button’s focus mode so it doesn’t steal focus from the editor
- Make the button appear flat like the other buttons in the toolbar
- Connect the button’s
pressed
signal to the_on_button_pressed
function, which doesn’t exist yet. - Add the button to the toolbar using the
add_control_to_container
function. This function takes two parameters: the container to add the button to and the button itself.
There are a lot more places you can add controls to besides the toolbar. Godot has two enums for this as part of the EditorPlugin
class: CustomControlContainer
and DockSlot
. You can find a full list in the EditorPlugin page of the documentation. You can experiment with these to find a suitable place to add your control(s).
Next up is defining what should happen when you click the button. This is the easiest part! It’s the same code as you’d expect to use in a game. Add the function below:
func _on_button_pressed() -> void:
node_to_edit.visible = !node_to_edit.visible
This changes the visible
property of the selected node to be the opposite of what it was before.
With the code you have set up now, you can already test out the plugin. Open the Project Settings menu and restart the plugin via the Plugins tab by toggling its Enable status off and on.
Next, open the 2D screen and select any node. You should see the button you defined above appear in the toolbar. When you click it, the selected node gets hidden or shown depending on its current state. Pretty neat!
Before patting yourself on the back too much, don’t forget about the cleanup. Right now, a new button will get added to the toolbar each time you restart the plugin and select a node. Deselecting a node won’t do anything either, so that’s not ideal.
A quick reload of the project fixes this, but you should probably handle this the correct way. :]
To fix this, you’ll need to implement the _remove_button
function so the button gets properly removed. Open the script again and remove the pass
keyword from the _remove_button
function. Now add the code below in its place:
# 1
if visibility_button:
# 2
remove_control_from_container(EditorPlugin.CONTAINER_CANVAS_EDITOR_MENU, \
visibility_button)
# 3
visibility_button.queue_free()
visibility_button = null
This will remove the button from the toolbar and free its memory. Here’s a more detailed look at the code:
- Check if the button exists. If there’s no button, nothing can be removed so don’t do anything.
- Remove the button from the toolbar using the
remove_control_from_container
function. - Destroy the button from memory using the
queue_free
function. Also clear the reference to it by setting it tonull
, forgetting to do this will cause a memory leak.
Save the script and try selecting and deselecting some nodes in the scene while in the 2D screen. The button appears and disappears as it should now.
Your first plugin is now complete, well done. You can adjust the code to make it do all sorts of useful things. If you want, you can add more than one control to the toolbar at once and add labels to show more information about the selected node.
While great, this way of writing plugins does come with a huge limitation: it only works with a single node at a time. If you try selecting more than one node at once, the button disappears from the toolbar. For some plugins, this won’t matter, but I bet you already have some plugin ideas whirling around in your head that require editing many nodes at the same time.
If you want to discover another way of writing plugins, read on!