Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
Plugins do Inspetor
O dock do inspetor permite criar widgets personalizados para editar propriedades através de plugins. Isso pode ser benéfico ao trabalhar com tipos de dados e recursos personalizados, embora você possa usar o recurso para alterar os widgets do inspetor para tipos integrados. Você pode projetar controles personalizados para propriedades específicas, objetos inteiros e até mesmo controles separados associados a tipos de dados particulares.
Este guia explica como usar as classes EditorInspectorPlugin e EditorProperty para criar uma interface personalizada para números inteiros, substituindo o comportamento padrão por um botão que gera valores aleatórios entre 0 e 99.
O comportamento padrão à esquerda e o resultado final à direita.
Configurando seu plugin
Crie um novo plugin vazio para começar.
Ver também
Veja o guia Criando plugins para configurar seu novo plugin.
Vamos assumir que você chamou a pasta do seu plugin de my_inspector_plugin. Se for o caso, você deve terminar com uma nova pasta addons/my_inspector_plugin contendo dois arquivos: plugin.cfg e plugin.gd.
Como antes, plugin.gd é um script que estende EditorPlugin e você precisa introduzir um novo código para seus métodos _enter_tree e _exit_tree. Para configurar seu plugin do inspetor, você deve carregar o script dele, depois criar e adicionar a instância chamando add_inspector_plugin(). Se o plugin for desativado, você deve remover a instância que adicionou chamando remove_inspector_plugin().
Nota
Aqui, você está carregando um script e não uma cena compactada. Portanto, você deve usar new() em vez de instantiate().
# plugin.gd
@tool
extends EditorPlugin
var plugin
func _enter_tree():
plugin = preload("res://addons/my_inspector_plugin/my_inspector_plugin.gd").new()
add_inspector_plugin(plugin)
func _exit_tree():
remove_inspector_plugin(plugin)
// Plugin.cs
#if TOOLS
using Godot;
[Tool]
public partial class Plugin : EditorPlugin
{
private MyInspectorPlugin _plugin;
public override void _EnterTree()
{
_plugin = new MyInspectorPlugin();
AddInspectorPlugin(_plugin);
}
public override void _ExitTree()
{
RemoveInspectorPlugin(_plugin);
}
}
#endif
Interagindo com o inspetor
Para interagir com o painel do inspetor, seu script my_inspector_plugin.gd deve estender a classe EditorInspectorPlugin. Essa classe fornece vários métodos virtuais que afetam como o inspetor lida com as propriedades.
Para ter qualquer efeito, o script deve implementar o método _can_handle(). Esta função é chamada para cada Object editado e deve retornar true se este plugin deve lidar com o objeto ou suas propriedades.
Nota
Isso inclui qualquer Resource anexado ao objeto.
Você pode implementar outros quatro métodos para adicionar controles ao inspetor em posições específicas. Os métodos _parse_begin() e _parse_end() são chamados apenas uma vez no início e no fim da análise para cada objeto, respectivamente. Eles podem adicionar controles no topo ou na parte inferior do layout do inspetor chamando add_custom_control().
À medida que o editor analisa o objeto, ele chama os métodos _parse_category() e _parse_property(). Neles, além de add_custom_control(), você pode chamar tanto add_property_editor() quanto add_property_editor_for_multiple_properties(). Use esses dois últimos métodos para adicionar especificamente controles baseados em EditorProperty.
# my_inspector_plugin.gd
@tool
extends EditorInspectorPlugin
var RandomIntEditor = preload("res://addons/my_inspector_plugin/random_int_editor.gd")
func _can_handle(object):
# We support all objects in this example.
return true
func _parse_property(object, type, name, hint_type, hint_string, usage_flags, wide):
# We handle properties of type integer.
if type == TYPE_INT:
# Create an instance of the custom property editor and register
# it to a specific property path.
add_property_editor(name, RandomIntEditor.new())
# Inform the editor to remove the default property editor for
# this property type.
return true
else:
return false
// MyInspectorPlugin.cs
#if TOOLS
using Godot;
[Tool]
public partial class MyInspectorPlugin : EditorInspectorPlugin
{
public override bool _CanHandle(GodotObject @object)
{
// We support all objects in this example.
return true;
}
public override bool _ParseProperty(GodotObject @object, Variant.Type type,
string name, PropertyHint hintType, string hintString,
PropertyUsageFlags usageFlags, bool wide)
{
// We handle properties of type integer.
if (type == Variant.Type.Int)
{
// Create an instance of the custom property editor and register
// it to a specific property path.
AddPropertyEditor(name, new RandomIntEditor());
// Inform the editor to remove the default property editor for
// this property type.
return true;
}
return false;
}
}
#endif
Adicionando uma interface para editar propriedades
A classe EditorProperty é um tipo especial de Control que pode interagir com os objetos editados do painel do inspetor. Ela não exibe nada por si só, mas pode abrigar quaisquer outros nós de controle, incluindo cenas complexas.
Existem três partes essenciais no script que estende EditorProperty:
Você deve definir o método
_init()para configurar a estrutura dos nós de controle.Você deve implementar o
_update_property()para lidar com alterações nos dados vindas de fora.Um sinal deve ser emitido em algum momento para informar ao inspetor que o controle alterou a propriedade usando
emit_changed.
Você pode exibir seu widget personalizado de duas maneiras. Use apenas o método padrão add_child() para exibi-lo à direita do nome da propriedade, ou use add_child() seguido de set_bottom_editor() para posicioná-lo abaixo do nome.
# random_int_editor.gd
@tool
extends EditorProperty
# The main control for editing the property.
var property_control = Button.new()
# An internal value of the property.
var current_value = 0
# A guard against internal changes when the property is updated.
var updating = false
func _init():
# Add the control as a direct child of EditorProperty node.
add_child(property_control)
# Make sure the control is able to retain the focus.
add_focusable(property_control)
# Setup the initial state and connect to the signal to track changes.
refresh_control_text()
property_control.pressed.connect(_on_button_pressed)
func _on_button_pressed():
# Ignore the signal if the property is currently being updated.
if (updating):
return
# Generate a new random integer between 0 and 99.
current_value = randi() % 100
refresh_control_text()
emit_changed(get_edited_property(), current_value)
func _update_property():
# Read the current value from the property.
var new_value = get_edited_object()[get_edited_property()]
if (new_value == current_value):
return
# Update the control with the new value.
updating = true
current_value = new_value
refresh_control_text()
updating = false
func refresh_control_text():
property_control.text = "Value: " + str(current_value)
// RandomIntEditor.cs
#if TOOLS
using Godot;
[Tool]
public partial class RandomIntEditor : EditorProperty
{
// The main control for editing the property.
private Button _propertyControl = new Button();
// An internal value of the property.
private int _currentValue = 0;
// A guard against internal changes when the property is updated.
private bool _updating = false;
public RandomIntEditor()
{
// Add the control as a direct child of EditorProperty node.
AddChild(_propertyControl);
// Make sure the control is able to retain the focus.
AddFocusable(_propertyControl);
// Setup the initial state and connect to the signal to track changes.
RefreshControlText();
_propertyControl.Pressed += OnButtonPressed;
}
private void OnButtonPressed()
{
// Ignore the signal if the property is currently being updated.
if (_updating)
{
return;
}
// Generate a new random integer between 0 and 99.
_currentValue = (int)GD.Randi() % 100;
RefreshControlText();
EmitChanged(GetEditedProperty(), _currentValue);
}
public override void _UpdateProperty()
{
// Read the current value from the property.
var newValue = (int)GetEditedObject().Get(GetEditedProperty());
if (newValue == _currentValue)
{
return;
}
// Update the control with the new value.
_updating = true;
_currentValue = newValue;
RefreshControlText();
_updating = false;
}
private void RefreshControlText()
{
_propertyControl.Text = $"Value: {_currentValue}";
}
}
#endif
Usando o código de exemplo acima, você deve ser capaz de fazer um widget personalizado que substitui o controle padrão SpinBox para inteiros por um Button que gera valores aleatórios.