空间变换轴插件
前言
Spatial gizmo[空间辅助线框]插件是由编辑器和自定义插件来定义附加到任何类型的Spatial节点的辅助线框.
本教程将向您展示定义您自己的自定义辅助线框的两种主要方法. 第一种方法对于简单的辅助线框来说效果很好, 并且在你的插件结构中较少的混乱, 而第二种方法将让你存储每个辅助线框的一些数据.
备注
本教程假设您已经知道如何制作通用插件。如有疑问,请参阅 制作插件 页面。
编辑器空间变换轴插件
不管我们选择什么方式, 我们需要创建一个新的 EditorSpatialGizmoPlugin . 我们可以为新建的变换轴类型设置名称并定义其他行为, 比如是否可以隐藏.
这是一个基本设置:
# MyCustomGizmoPlugin.gd
extends EditorSpatialGizmoPlugin
func get_name():
return "CustomNode"
# MyCustomEditorPlugin.gd
tool
extends EditorPlugin
const MyCustomGizmoPlugin = preload("res://addons/my-addon/MyCustomGizmoPlugin.gd")
var gizmo_plugin = MyCustomGizmoPlugin.new()
func _enter_tree():
add_spatial_gizmo_plugin(gizmo_plugin)
func _exit_tree():
remove_spatial_gizmo_plugin(gizmo_plugin)
对于简单的辅助线框, 只要继承 EditorSpatialGizmoPlugin 就足够了. 如果你想存储每个线框的一些数据, 或者你要把一个Godot 3.0的线框移植到3.1+, 你应该选择第二种方法.
简单方法
第一步, 在我们的自定义变换轴插件中, 重写 has_gizmo() 方法, 当空间参数为目标类型时, 它将返回 true
.
# ...
func has_gizmo(spatial):
return spatial is MyCustomSpatial
# ...
我们可以重写譬如 redraw() 的方法, 或所有与句柄相关的方法.
# ...
func _init():
create_material("main", Color(1, 0, 0))
create_handle_material("handles")
func redraw(gizmo):
gizmo.clear()
var spatial = gizmo.get_spatial_node()
var lines = PoolVector3Array()
lines.push_back(Vector3(0, 1, 0))
lines.push_back(Vector3(0, spatial.my_custom_value, 0))
var handles = PoolVector3Array()
handles.push_back(Vector3(0, 1, 0))
handles.push_back(Vector3(0, spatial.my_custom_value, 0))
gizmo.add_lines(lines, get_material("main", gizmo), false)
gizmo.add_handles(handles, get_material("handles", gizmo))
# ...
请注意, 我们在 _init 方法中创建了一个材质, 并在 redraw 方法中使用 get_material() 取得它. 该方法根据变换轴的状态(选择中和/或可编辑)来获取材质的变体.
您最后的场景应该是这样的:
extends EditorSpatialGizmoPlugin
const MyCustomSpatial = preload("res://addons/my-addon/MyCustomSpatial.gd")
func _init():
create_material("main", Color(1,0,0))
create_handle_material("handles")
func has_gizmo(spatial):
return spatial is MyCustomSpatial
func redraw(gizmo):
gizmo.clear()
var spatial = gizmo.get_spatial_node()
var lines = PoolVector3Array()
lines.push_back(Vector3(0, 1, 0))
lines.push_back(Vector3(0, spatial.my_custom_value, 0))
var handles = PoolVector3Array()
handles.push_back(Vector3(0, 1, 0))
handles.push_back(Vector3(0, spatial.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()...).
注意,我们只是在重绘方法中添加了一些句柄,但是我们仍然需要在 EditorSpatialGizmoPlugin 中实现其他与句柄相关的回调,以获得正确的工作句柄。
替代方法
在某些情况下,我们希望提供自己的 EditorSpatialGizmo 实现,也许是因为我们想要在每个变换轴中存储一些状态,或者正在移植一个旧的变换轴插件,而不想经历重写过程。
在这些情况下,我们需要做的就是在我们的新变换轴插件中覆盖 create_gizmo(),因此它返回我们想要实现的目标空间节点的自定义变换轴。
# MyCustomGizmoPlugin.gd
extends EditorSpatialGizmoPlugin
const MyCustomSpatial = preload("res://addons/my-addon/MyCustomSpatial.gd")
const MyCustomGizmo = preload("res://addons/my-addon/MyCustomGizmo.gd")
func _init():
create_material("main", Color(1, 0, 0))
create_handle_material("handles")
func create_gizmo(spatial):
if spatial is MyCustomSpatial:
return MyCustomGizmo.new()
else:
return null
这样, 所有的gizmo逻辑和绘图方法都可以在一个新的类中实现, 扩展为 EditorSpatialGizmo , 像这样:
# MyCustomGizmo.gd
extends EditorSpatialGizmo
# You can store data in the gizmo itself (more useful when working with handles).
var gizmo_size = 3.0
func redraw():
clear()
var spatial = get_spatial_node()
var lines = PoolVector3Array()
lines.push_back(Vector3(0, 1, 0))
lines.push_back(Vector3(gizmo_size, spatial.my_custom_value, 0))
var handles = PoolVector3Array()
handles.push_back(Vector3(0, 1, 0))
handles.push_back(Vector3(gizmo_size, spatial.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()...).
请注意,我们刚刚在重绘方法中添加了一些句柄,但我们仍然需要在 EditorSpatialGizmo 中实现其余的与句柄相关的回调,以获得正确工作的句柄。