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.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 2 of 5 of this article. Click here to view the first page.

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:

  • 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
  1. Check if the button already exists. If it does, return and don’t do anything.
  2. Create a new button and set its properties:
  3. Connect the button’s pressed signal to the _on_button_pressed function, which doesn’t exist yet.
  4. 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.

Toggle plugin enable checkbox

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!

Button can hide nodes

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.

Way too many buttons

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:

  1. Check if the button exists. If there’s no button, nothing can be removed so don’t do anything.
  2. Remove the button from the toolbar using the remove_control_from_container function.
  3. Destroy the button from memory using the queue_free function. Also clear the reference to it by setting it to null, 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.

The button appears when a node is selected

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!

Developing an Advanced Plugin

For your next plugin, you’ll create a menu with buttons that allows you to simulate 2D gravity in the editor. Along the way, you’ll learn how physics work in Godot and how you can let the physics engine only affect selected nodes.

Physics buttons menu

To start, you’ll need to create a new plugin. In the Project Settings menu, select the Plugins tab and click the Create New Plugin button. Fill in the following information:

  • Plugin Name: Physics Menu
  • Subfolder: physics_menu
  • Description: Run physics on selected objects in the editor.
  • Author: Your name or username
  • Script Name: physics_menu.gd

Here’s what it should look like:

Physics menu plugin info

Next, click the Create button to create the new plugin. The physics_menu.gd script will automatically open in the script editor. You won’t be coding yet though; unlike the first plugin you’ve created, you’re going to create a new scene first to hold the menu.

Creating the Menu Scene

By creating a scene, you can easily customize the menu to your liking. While it’s possible to do this via code like you did above, creating UI via the editor is more streamlined and allows for quick tweaks.
First up, create a new scene in the addons/physics_menu folder and name it menu_ui.tscn. You can do this by right-clicking the folder and selecting Create New ▸ Scene….

Create a new scene

Make this new scene have an VBoxContainer as its root node and name this root node Menu. Here’s what this looks like in the dialog:

New scene properties

Once you’ve filled in the scene properties, click the OK button to create the scene. Now make the Menu node take up the full viewport by selecting it and selecting the Full Rect anchor preset in the toolbar.

Full rect

Doing this ensures that the menu will use all available space in whichever container you add it to.
Now all that’s left is to add the buttons to the menu. Add a new Button node as a child node of Menu and name it ShowSelectionButton. Change its Text property to “Show selection”.

Show selection button

Now repeat the steps above (or duplicate the button) and add these other buttons:

  • StartPhysicsButton: “Start physics”
  • StopPhysicsButton: “Stop physics”
  • TenFramesButton: “Simulate 10 physics frames”
  • ResetVelocityButton: “Reset velocity”

All buttons

Each of these buttons will have a specific function:

  • ShowSelectionButton will show the selected nodes in the console.
  • StartPhysicsButton will start physics on the selected nodes in the editor.
  • StopPhysicsButton will stop physics for the selected nodes.
  • TenFramesButton will simulate 10 physics frames, which is useful for a quick test.
  • ResetVelocityButton will reset the linear and angular velocity of the selected nodes. This makes it so they don’t immediately start moving or spinning when you start the project.

That’s it for the scene! If you want to be fancy, you can add an icon to each button, maybe a kitten or a puppy? At any rate, you don’t need to attach a script here, as all logic will be handled by the plugin script.