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...
Estensioni di gizmo 3D
Introduzione
Le estensioni dei gizmo 3D sono utilizzate dall'editor e dalle estensioni personalizzate per definire i gizmo collegati a qualsiasi tipo di nodo Node3D.
Questo tutorial illustra i due approcci principali per definire i propri gizmo personalizzati. La prima opzione è ideale per gizmo semplici e crea meno ingombro nella struttura delle proprie estensione, mentre la seconda consente di memorizzare alcuni dati per ogni gizmo.
Nota
Questo tutorial presuppone che si sappia già come creare estensioni generiche. Se in dubbio, consultare la pagina Creare estenzioni.
L'EditorNode3DGizmoPlugin
A prescindere dall'approccio scelto, dovremo creare un nuovo EditorNode3DGizmoPlugin. Questo ci permetterà di impostare un nome per il nuovo tipo di gizmo e di definire altri comportamenti, come ad esempio se il gizmo può essere nascosto o meno.
Questa sarebbe una configurazione basilare:
# my_custom_gizmo_plugin.gd
extends EditorNode3DGizmoPlugin
func _get_gizmo_name():
return "CustomNode"
# MyCustomEditorPlugin.gd
@tool
extends EditorPlugin
const MyCustomGizmoPlugin = preload("res://addons/my-addon/my_custom_gizmo_plugin.gd")
var gizmo_plugin = MyCustomGizmoPlugin.new()
func _enter_tree():
add_node_3d_gizmo_plugin(gizmo_plugin)
func _exit_tree():
remove_node_3d_gizmo_plugin(gizmo_plugin)
Per i gizmo più semplici, basta ereditare EditorNode3DGizmoPlugin. Se si desidera memorizzare dati per ogni gizmo, è consigliabile adottare il secondo approccio.
Approccio semplice
Il primo passo è quello di sovrascrivere il metodo _has_gizmo() nella nostra estensione gizmo personalizzata in modo che restituisca true quando il parametro node è del nostro tipo da influenzare.
# ...
func _has_gizmo(node):
return node is MyCustomNode3D
# ...
Successivamente possiamo sovrascrivere metodi come _redraw() o tutti quelli che riguardano gli handle.
# ...
func _init():
create_material("main", Color(1, 0, 0))
create_handle_material("handles")
func _redraw(gizmo):
gizmo.clear()
var node3d = gizmo.get_node_3d()
var lines = PackedVector3Array()
lines.push_back(Vector3(0, 1, 0))
lines.push_back(Vector3(0, node3d.my_custom_value, 0))
var handles = PackedVector3Array()
handles.push_back(Vector3(0, 1, 0))
handles.push_back(Vector3(0, node3d.my_custom_value, 0))
gizmo.add_lines(lines, get_material("main", gizmo), false)
gizmo.add_handles(handles, get_material("handles", gizmo), [])
# ...
Si noti che abbiamo creato un materiale nel metodo _init e lo abbiamo recuperato nel metodo _redraw tramite get_material(). Questo metodo recupera una delle varianti del materiale a seconda dello stato del gizmo (selezionato e/o modificabile).
Pertanto l'estensione finale sarebbe simile a questa:
extends EditorNode3DGizmoPlugin
const MyCustomNode3D = preload("res://addons/my-addon/my_custom_node_3d.gd")
func _init():
create_material("main", Color(1,0,0))
create_handle_material("handles")
func _has_gizmo(node):
return node is MyCustomNode3D
func _redraw(gizmo):
gizmo.clear()
var node3d = gizmo.get_node_3d()
var lines = PackedVector3Array()
lines.push_back(Vector3(0, 1, 0))
lines.push_back(Vector3(0, node3d.my_custom_value, 0))
var handles = PackedVector3Array()
handles.push_back(Vector3(0, 1, 0))
handles.push_back(Vector3(0, node3d.my_custom_value, 0))
gizmo.add_lines(lines, get_material("main", gizmo), false)
gizmo.add_handles(handles, get_material("handles", gizmo), [])
# You should implement the rest of handle-related callbacks
# (_get_handle_name(), _get_handle_value(), _commit_handle(), ...).
Si noti che abbiamo appena aggiunto alcuni handle nel metodo _redraw, ma dobbiamo ancora implementare il resto dei callback correlati agli handle in EditorNode3DGizmoPlugin per ottenere handle funzionanti correttamente.
Approccio alternativo
In alcuni casi vogliamo fornire la nostra implementazione di EditorNode3DGizmo, magari perché vogliamo che uno stato sia memorizzato in ogni gizmo o perché stiamo trasferendo una vecchia estensione gizmo e non vogliamo riscriverla del tutto.
In questi casi, tutto ciò che dobbiamo fare è sovrascrivere _create_gizmo() nella nostra nuova estensione gizmo, in modo che sia restituita la nostra implementazione gizmo personalizzata per i nodi Node3D che vogliamo influenzare.
# my_custom_gizmo_plugin.gd
extends EditorNode3DGizmoPlugin
const MyCustomNode3D = preload("res://addons/my-addon/my_custom_node_3d.gd")
const MyCustomGizmo = preload("res://addons/my-addon/my_custom_gizmo.gd")
func _init():
create_material("main", Color(1, 0, 0))
create_handle_material("handles")
func _create_gizmo(node):
if node is MyCustomNode3D:
return MyCustomGizmo.new()
else:
return null
In questo modo tutta la logica e i metodi di disegno dei gizmo possono essere implementati in una nuova classe che estende EditorNode3DGizmo, così:
# my_custom_gizmo.gd
extends EditorNode3DGizmo
# You can store data in the gizmo itself (more useful when working with handles).
var gizmo_size = 3.0
func _redraw():
clear()
var node3d = get_node_3d()
var lines = PackedVector3Array()
lines.push_back(Vector3(0, 1, 0))
lines.push_back(Vector3(gizmo_size, node3d.my_custom_value, 0))
var handles = PackedVector3Array()
handles.push_back(Vector3(0, 1, 0))
handles.push_back(Vector3(gizmo_size, node3d.my_custom_value, 0))
var material = get_plugin().get_material("main", self)
add_lines(lines, material, false)
var handles_material = get_plugin().get_material("handles", self)
add_handles(handles, handles_material, [])
# You should implement the rest of handle-related callbacks
# (_get_handle_name(), _get_handle_value(), _commit_handle(), ...).
Si noti che abbiamo appena aggiunto alcuni handle nel metodo _redraw, ma dobbiamo ancora implementare il resto dei callback riguardo gli handle in EditorNode3DGizmo per ottenere handle funzionanti correttamente.