+6 votes

Ok, so here's the situation:

I'd like to create a custom node which is really similar to polygon2d node, but with some additional features. The thing is, I need to be able to do editing of this polygon in editor- adding, moving and removing points, but I can't figure out from the source code of the actual polygon2deditor_plugin.cpp how to handle the input. How can I make other nodes ignore the input- stop them from being selected while adding points?

I checked out that the plugin shouldn't be using simply func _input(event) but instead there should be func forwardinputevent(event), however it doesn't seem to be doing anything when added just like that. I mean I added print function with some text under forward_input, but it doesn't appear. Obviously I'm doing something wrong and I need your help to figure out how to do it properly, so that it works.

I'd really appreciate just a simple example, just a few lines of code or a fairly good explanation how this thing could be achieved.

in Engine by (52 points)

I think forward_input_event(event) is a virtual method of EditorPlugin.

Yes, I saw that in the class reference, but I'm not familiar of the meaning of it. I will have to read and learn about this topic, but in the meantime- why did you point out that this is a virtual method- do you have an idea on how to solve the problem or is this just a small lead?

Ok, I read about virtual methods- I kinda have a vague understanding of that now, but I still have no clue how that matters in solving this problem.

You said forward_input_event(event) was not being called (or that's what I understood :P ). That's because it's a virtual method of EditorPlugin, so it will only be called if you add it to a class that extends EditorPlugin. Polygon2DEditorPlugin overrides this method and passes the event to Polygon2DEditor. You can return true from this method to capture the event, making the other nodes ignore it.

Thanks for the info! However, may I ask you to create a small preview of how this is done properly?

Shouldn't this code print line if mouse button is clicked while the according node is selected and block other nodes from being selected if the cursor is over?

tool

extends EditorPlugin

func _ready():
    pass

func forward_input_event(event):
    if event.type == InputEvent.MOUSE_BUTTON:
        if event.button_index == BUTTON_LEFT:
            if get_selection().get_selected_nodes().size() == 1:
                if get_selection().get_selected_nodes()[0].is_type("Sprite"):
                    print("Sprite is selected")
                    return true
                else:
                    return false

That's not how it works. You must override method bool handles(object) for the editor to know if your plugin can edit the selected node:

func handles(object):
    return object.is_type("Sprite")

I'll try to make a proper answer with an example tomorrow.

Thanks, mate, looking forward to it!

Hey @neikeq, maybe you had some time to spare on this?

1 Answer

+3 votes

First you need to create a plugin. In version 2.0.x the plugins directory is ~/.godot/plugins/ ($APPDATA/Godot/plugins/ on Windows) and the plugin must be activated from Editor Settings->Plugins. In greater versions (master branch) the directory is res://addons/ and the plugin must be activated from Project Settings->Plugins.

A plugin consists of a directory with a plugin.cfg file and a main script which must extend EditorPlugin and have tool enabled. This is an example plugin.cfg:

[plugin]
name="PluginName"
description="Best plugin ever"
author="neikeq"
version="1.0.0"
installs=false
script="path/to/main_script.gd"

EditorPlugin class has some useful methods you can override. One of them is handles(object) which is called by the editor when editing a object/node to determine if your plugin can edit it. Here are bad news though: Currently there is no way to set a plugin's priority, so you can't create a plugin to edit TileMap (for example) because it's already edited by the built-in TileMapEditorPlugin.

EditorPlugin also has the methods forward_input_event(event) for input events in the canvas editor and forward_spatial_input_event(camera, event) for the spatial editor. This methods are called only if your plugin is the one editing the current object (must be the first to return true from handles(object)).

With all the above in mind, this is an example EditorPlugin script that handles KinematicBody2D objects and translates them when the canvas editor is clicked, capturing the event to avoid selecting other nodes:

tool
extends EditorPlugin

var current_object

func _enter_tree():
    pass

func edit(object):
    current_object = object

func handles(object):
    return object.is_type("KinematicBody2D")

func forward_input_event(event):
    var captured_event = false
    if event.type == InputEvent.MOUSE_BUTTON:
        if event.button_index == BUTTON_LEFT and event.is_pressed():
            # current_object = get_selection().get_selected_nodes()[0]
            current_object.translate(Vector2(10, 10))
            captured_event = true
    return captured_event
by (488 points)

Sorry for the delay. The lack of plugin priority may be a problem for you if the node you want to edit extends Polygon2D or another node that already has a plugin to edit it. I'll make a pull request to add priorities to plugins on 2.1 (already created). Let's see if it's accepted :)

Thanks! I actually wrote similar code that would've worked if I'd only used different node type- as in your example KinematicBody2D, but since it failed because of the issue you mentioned, I thought it's my fault. Anyway, thanks for clearing things up!

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.