关于
“组套添加”的灵感来自于某特殊专业(指医学)使用的信息管理系统(HIS)中开组套医嘱的方式。就是通过在一个分类、分组排列好的树形列表中选中需要添加的“组套”-也就是预设好的一组医嘱,然后双击这个“组套”,就会在医嘱列表中顺序添加组套中的所有子项。这是为了便利医务人员开具固定且常用的成套的医嘱的一种设计,这里借用“组套”的思想和概念,尝试通过类似的方式来创建和添加各种固定搭配的节点结构。
最终目标
最终目标是做成插件形式。与节点添加插件myAdd一起配套使用。
用EditorScript版本先期设计和测试
Godot提供了简便的EditorScript来测试可以影响编辑器也就是EditorInterface的脚本。这可以作为最终开发编辑器插件的前置步骤,进行先期的设计和测试,最后再尝试做成插件。
节点组套:一组具有固定搭配的节点形式,比如KinematicBody2D带一个Sprite,再带一个CollisionShape2D的固定搭配
初期EditorScript代码
要想实现“节点组套”添加的设想,就需要想办法设计一种数据结构来存储节点的树状结构,一种很容易想到的结构就是嵌套形式的字典,也就是下面的形式,其中的数据记录的结构就是上文图中红框框选的节点树状从属结构:
# 节点组套的树状结构
var nodes = {
nodetype = "KinematicBody2D",
children =[
{
nodetype = "Sprite",children =[]},
{
nodetype = "CollisionShape2D",children =[]}
]
}
可以看到,每个node都采用{nodetype = "",children =[]}
形式来描述,其中nodetype存储节点的类名,而children存储该节点的子结点集合。
然后我们需要实现一个函数来具体的加载数据中所描述的节点和节点关系。我们编写了一个名为loadNodesTree的函数,它采用递归,去遍历nodes字典中的每一个节点及其子结点。
tool
extends EditorScript
func _run():
var face = get_editor_interface()
var root = face.get_edited_scene_root()
# 节点组套的树状结构
var nodes = {
nodetype = "KinematicBody2D",
children =[
{
nodetype = "Sprite",children =[]},
{
nodetype = "CollisionShape2D",children =[]}
]
}
loadNodesTree(sel(),nodes)
func loadNodesTree(parent:Node,data:Dictionary):
var face = get_editor_interface()
var root = face.get_edited_scene_root()
# 添加子节点
var nodeType = data.nodetype
var node:Node = ClassDB.instance(nodeType) # 按照类型名称添加节点
parent.add_child(node)
node.owner = root # 设置owner为场景根节点
var children = data.children
for childNode in children:
loadNodesTree(node,childNode)
pass
初步试验,描述节点组套的树状结构以及加载组套的递归算法成立!
下一步:借鉴myAdd插件中的代码,智能判断是空场景还是非空场景,从而快速创建添加有节点组套的新场景或为当前选中节点添加节点组套。
结合myAdd的核心代码实现智能判断
tool
extends EditorScript
func _run():
var face = get_editor_interface()
var root = face.get_edited_scene_root()
# 节点组套的树状结构
var nodes = {
nodetype = "KinematicBody2D",
children =[
{
nodetype = "Sprite",children =[]},
{
nodetype = "CollisionShape2D",children =[]}
]
}
if sel(): # 非空场景 - 有选中节点
loadNodesTree(sel(),nodes)
else: # 空场景/没有选中节点
empty_scene_loadNodesTree(nodes)
func loadNodesTree(parent:Node,data:Dictionary):
var face = get_editor_interface()
var root = face.get_edited_scene_root()
# 添加子节点
var nodeType = data.nodetype
var node:Node = ClassDB.instance(nodeType) # 按照类型名称添加节点
parent.add_child(node)
node.owner = root # 设置owner为场景根节点
var children = data.children
for childNode in children:
loadNodesTree(node,childNode)
pass
# 判断并返回当前场景中选中的节点
func sel():
var plug = EditorPlugin.new()
var sels = plug.get_editor_interface().get_selection().get_selected_nodes() # 获取当前选中的节点集合
var _sel
if sels.size() == 1:
_sel =sels[0]
else:
_sel = null
return _sel
# 空场景加载节点组套
func empty_scene_loadNodesTree(data:Dictionary):
var plug = EditorPlugin.new()
var root = plug.get_editor_interface().get_tree().root
var nodeType = data.nodetype
if not plug.get_editor_interface().get_edited_scene_root():# 当前场景为空场景
# 新建根节点
var scene_tree_dock = root.find_node("Scene",true,false)
scene_tree_dock._tool_selected(0)
var create_dialog = find_child_as_class(scene_tree_dock,"CreateDialog")
# 搜索框
var hs = create_dialog.get_child(3)
var vb = hs.get_child(1)
var mg = vb.get_child(1)
var txt:LineEdit = mg.get_child(0).get_child(0)
# "创建"按钮
var hb = create_dialog.get_child(2)
var creBtn:Button = hb.get_child(1)
txt.text = nodeType # 修改搜索关键字
txt.emit_signal("text_changed",nodeType) # 触发“文本改变”信号
creBtn.emit_signal("pressed") # 触发“创建”按钮pressed信号
# 添加子节点
var node = plug.get_editor_interface().get_edited_scene_root()
var children = data.children
for childNode in children:
loadNodesTree(node,childNode)
# 返回对应类名的子节点
func find_child_as_class(node:Node,className:String):
var children = node.get_children()
for child in children:
if child.is_class(className):
return child
通过借鉴myAdd插件的核心代码,我们可以快速实现为空场景和任意当前场景选中节点添加节点组套。
实现插件版本
等待施工中…