文章目录
- GDEditorV2
-
- 基本信息
- 概述
- 属性
- 方法
-
- get_child_by_indexPath(node:Node,indexPath:PoolIntArray)
- get_child_as_class(node:Node,className:String)
- top_container()
- add_control_to_editor_topright_area(control:Control)
- top_menu_container()
- top_menu(idx:int)
- add_sys_top_menu(text:String,items:PoolStringArray,target:Object,itm_pressed_fuc:String)
- remove_sys_top_menu(idx = -1 )
- show_sys_dialog(dlg:int,tab_index:int = 0)
- scene_tree_dock()
- get_selected_node() -> Node
- create_node_dialog()
- edited_scene_root()
- current_scene_is_empty() -> bool
- empty_scene_add_root(nodeType:String) -> void
- select_node_add_child_node(nodeType:String)
- file_system_dock()
- select_file(file_path:String) -> void
- inspector_dock()
- inspect_object(object:Object,for_property:String,inspector_only:bool = false) -> void
- add_control_to_inspector_bottom(control:Control)
- set_main_screen_editor(name:String) -> void
- is_playing_scene() -> bool
- stop_playing_scene() -> void
- open_scene_from_path(scene_filepath:String) -> void
- play_current_scene() -> void
- play_custom_scene(scene_file_path:String) -> void
- play_main_scene() -> void
- reload_scene_from_path(scene_file_path:String) -> void
- save_scene()
- save_scene_as(path:String,with_preview:bool = true) -> void
- is_plugin_enabled(plugin:String) -> bool
- set_plugin_enabled(plugin:String,enabled:bool) -> void
- script_editor()
- script_top_container()
- script_create_dialog()
- script_TabContainer()
- get_current_Script_tab_control()
- get_current_Script_TextEdit()
- get_current_Script_PopupMenu()
- open_class_help_in_editor(className:String) -> void
- close_all_EditorHelp() -> void
- insert_code(code:String)
- append_code(code:String)
- append_file_code(codePath:String)
- insert_HR_comment(str_or_char:String,repeat_time:int,comment:String = "")
- insert_top_meta_comment()
- insert_param_comment()
- insert_return_comment()
- close_all_script() -> void
- add_control_to_2D_menu(control:Control)
- add_control_to_2D_left(control:Control)
- add_control_to_2D_right(control:Control)
- add_control_to_2D_bottom(control:Control)
- add_control_to_3D_menu(control:Control)
- add_control_to_3D_left(control:Control)
- add_control_to_3D_right(control:Control)
- add_control_to_3D_bottom(control:Control)
- loadString(path:String) -> String
- 源代码
GDEditorV2
基本信息
脚本信息
项目 | 信息 |
---|---|
文件名 | GDEditor.gd |
is_tool | 是 |
extend | EditorPlugin |
class_name | GDEditor |
文件信息
项目 | 信息 |
---|---|
项目名称 | myAdd插件v3.0 |
文件路径 | res://addons/myTreeAdd/lib/GDEditor.gd |
绝对路径 | E:/【Godot-项目】/myAdd插件v3.0/addons/myTreeAdd/lib/GDEditor.gd |
其他信息
项目 | 信息 |
---|---|
作者 | @巽星石 @张学徒 @timothyqi |
备注 | 尚未扩充和修改完善,但已经可以用来快速创建Godot的编辑器插件。 |
文档信息
项目 | 信息 |
---|---|
文档创建时间 | 2022-09-25 20:28:36 |
概述
提供 Godot 插件开发相关的工具函数,加快插件开发,可直接在您的插件项目中使用。
-
基于: @张学徒 在2022年5月13日分享的代码改进,部分独门秘技来自@timothyqiu帮助
-
Godot版本:3.5 【请尽量确保您的Godot版本一致,否则可能出现未知错误】
-
基于之前的版本重新编写,除了2个全局变量,其余全部函数化。
属性
变量 | 值类型 | 默认值 | 描述 |
---|---|---|---|
face | EditorInterface | get_editor_interface() | 编辑器的EditorInterface实例 |
root | Viewport | face.get_tree().root | 编辑器根视口 |
方法
get_child_by_indexPath(node:Node,indexPath:PoolIntArray)
通过层级索引查找并返回节点。方便在编辑器的节点树中深度寻找和定位一个节点。
node是基于的节点,indexPath传入一个PoolIntArray,代表向下一层的索引。
建议配合Editor Debuger使用。
get_child_as_class(node:Node,className:String)
返回node节点的子节点中类型为className的第一个子节点。
top_container()
整个Godot编辑器顶部的HBoxContainer容器。
add_control_to_editor_topright_area(control:Control)
将control控件添加到编辑器右上角“运行场景”等按钮之后的区域。
tool
extends EditorScript
var gd = GDEditor.new()
func _run():
var btn = Button.new()
btn.text = "自定义按钮"
gd.add_control_to_editor_topright_area(btn)
上面的代码运行后:
top_menu_container()
获取Godot编辑器顶部菜单的整个HBoxContainer容器。
top_menu(idx:int)
获取索引为idx的顶部菜单,返回类型为MenuButton。
idx | 对应菜单 |
---|---|
0 | 场景 |
1 | 项目 |
2 | 调试 |
3 | 编辑器 |
4 | 帮助 |
add_sys_top_menu(text:String,items:PoolStringArray,target:Object,itm_pressed_fuc:String)
添加一个名为text,以items作为菜单项的自定义顶部菜单。会被添加到当前所有顶部菜单之后。
target和itm_pressed_fuc用于连接菜单的"id_pressed"信号。
remove_sys_top_menu(idx = -1 )
移除索引为idx顶部菜单。无法删除原有的Godot编辑器原有的顶部菜单。
show_sys_dialog(dlg:int,tab_index:int = 0)
显示对应的系统对话框。
sys_dlg枚举 | 数值 | 描述 |
---|---|---|
PROJECT_SETTING | 0 | 项目设置 |
EDITOR_SETTING | 1 | 编辑器设置 |
CREATE | 2 | 新建资源 |
PLUGIN_CONFIG | 3 | 创建插件 |
ABOUT | 4 | 关于Godot |
FEATURE_PROFILE_MANAGER | 5 | 编辑器功能管理 |
EXPORT | 6 | 项目导出对话框 |
scene_tree_dock()
"场景"面板。
get_selected_node() -> Node
返回当前场景中选中的节点。如果没有选中返回null。
create_node_dialog()
“添加节点"对话框。
edited_scene_root()
当前正在编辑的场景的根节点。如果为null,表示当前场景是一个空场景。
current_scene_is_empty() -> bool
判断当前场景是否为空场景(也就是没有添加任何节点)。
empty_scene_add_root(nodeType:String) -> void
为当前创建的空场景添加nodeType类型的根节点。
select_node_add_child_node(nodeType:String)
为“场景”面板上选中的节点添加nodeType类型的子节点。
file_system_dock()
“文件系统”面板。
select_file(file_path:String) -> void
在“文件系统”面板中选中路径为file_path的文件。
inspector_dock()
“检视器”面板。
inspect_object(object:Object,for_property:String,inspector_only:bool = false) -> void
在编辑器的属性检查器中显示指定的object对象。
add_control_to_inspector_bottom(control:Control)
将控件添加到 - 检视器面板 - 底部。
set_main_screen_editor(name:String) -> void
切换编辑器。name为“2D”、“3D”、“Script”、“AssetLib”或其他的屏幕插件名称。
is_playing_scene() -> bool
如果场景正在播放,返回 true,否则返回 false。暂停的场景将被视为正在播放。
stop_playing_scene() -> void
停止当前正在播放的场景。
open_scene_from_path(scene_filepath:String) -> void
打开给定路径scene_filepath的场景。
play_current_scene() -> void
播放当前活动的场景。
play_custom_scene(scene_file_path:String) -> void
播放文件路径所指定的场景。
play_main_scene() -> void
播放主场景。
reload_scene_from_path(scene_file_path:String) -> void
重新加载给定路径scene_file_path的场景。
save_scene()
保存场景。返回 OK 或 ERR_CANT_CREATE(见 @GlobalScope 常量)。
save_scene_as(path:String,with_preview:bool = true) -> void
将场景保存为 path 处的文件。
is_plugin_enabled(plugin:String) -> bool
如果指定的插件 plugin 已启用时返回 true。插件名称与其目录名称一致。
set_plugin_enabled(plugin:String,enabled:bool) -> void
设置插件的启用状态。插件名称与其目录名称相同。
script_editor()
Godot编辑器中名为ScriptEditor的节点。可以认为是整个脚本编辑器的顶级节点。
script_top_container()
脚本编辑器顶部的HBoxContainer。
script_create_dialog()
“创建脚本”对话框。
script_TabContainer()
ScriptEditor下的TabContainer。其下是所有已经打开的脚本和内置文档所对应的控件。可以用其动态的打开、关闭脚本、内置文档或添加其他的东西。
get_current_Script_tab_control()
返回当前打开的脚本编辑器或内置文档对应的控件。也就是script_TabContainer()所指定的TabContainer当前显示的控件,有可能是脚本,也有可能是内置文档。
get_current_Script_TextEdit()
返回当前打开的脚本编辑器的TextEdit控件引用。获取它,就可以直接获取当前打开的脚本的内容,并对其施加影响。
get_current_Script_PopupMenu()
获取当前打开的脚本编辑器对应的TextEdit控件的右键菜单。
open_class_help_in_editor(className:String) -> void
在脚本界面,打开className对应的类型的内置文档。
close_all_EditorHelp() -> void
关闭脚本界面,所有已经打开的内置文档。
insert_code(code:String)
在前脚本编辑器的光标位置添加code对应的文本。
append_code(code:String)
将code对应的文本追加到当前脚本编辑器的末尾。
append_file_code(codePath:String)
将codePath所指定的文件的内容追加到当前脚本编辑器的末尾。
insert_HR_comment(str_or_char:String,repeat_time:int,comment:String = “”)
在前脚本编辑器的光标位置添加分割线注释。
insert_HR_comment("=",15,"这是一条水平注释")
会产生如下的注释字符串:
# ===============这是一条水平注释===============
repeat_time最大不能超过15。
insert_top_meta_comment()
在当前脚本的最顶部添加如下元信息注释模板。
# ======================================================================
# 名称:
# 类型:
# 作者:
# 创建时间:
# 最后修改时间:
# ======================================================================
insert_param_comment()
在前脚本编辑器的光标位置添加# @param
。
insert_return_comment()
在前脚本编辑器的光标位置添加# @return
。
close_all_script() -> void
关闭所有打开的脚本(不关闭已经打开的内置文档)
add_control_to_2D_menu(control:Control)
将控件添加到 - 2D场景 - 顶部菜单。
add_control_to_2D_left(control:Control)
将控件添加到 - 2D场景 - 左侧。
add_control_to_2D_right(control:Control)
将控件添加到 - 2D场景 - 右侧。
add_control_to_2D_bottom(control:Control)
将控件添加到 - 2D场景 - 底部。
add_control_to_3D_menu(control:Control)
将控件添加到 - 3D场景 - 顶部菜单。
add_control_to_3D_left(control:Control)
将控件添加到 - 3D场景 - 左侧。
add_control_to_3D_right(control:Control)
将控件添加到 - 3D场景 - 右侧。
add_control_to_3D_bottom(control:Control)
将控件添加到 - 3D场景 - 底部。
loadString(path:String) -> String
返回指定路径文件中的内容。在类内部方便文件存取的便捷函数。
源代码
这里是完整源代码:
# =====================================================================
# 名称: GDEditor_V2
# 描述: 提供 Godot 插件开发相关的工具函数,加快插件开发,可直接在您的插件项目中使用
# 作者: @巽星石 @张学徒 @timothyqiu
# 基于: @张学徒 在2022年5月13日分享的代码改进,部分独门秘技来自@timothyqiu帮助
# Godot版本:3.5
#
# 【请尽量确保您的Godot版本一致,否则可能出现未知错误】
#
# 最后修改时间:2022年9月25日16:51:06
# =====================================================================
tool
extends EditorPlugin
class_name GDEditor
var face = get_editor_interface()
var root = face.get_tree().root # 编辑器根视口
# ======================= 基本的节点查找函数 =======================
# 通过层级索引查找并返回节点
func get_child_by_indexPath(node:Node,indexPath:PoolIntArray):
for idx in indexPath:
var nd = node.get_child(idx)
node = nd
return node
# 返回对应类名的子节点
func get_child_as_class(node:Node,className:String):
var children = node.get_children()
for child in children:
if child.is_class(className):
return child
# ======================= 编辑器部位的获取 =======================
# 整个顶部(编辑器菜单,视图切换,运行场景)部分的HBoxContainer容器
func top_container():
var editor_panel = face.get_base_control() # 编辑器的基础节点
var main_vbox = get_child_as_class(editor_panel,"VBoxContainer")
var top_container = get_child_as_class(main_vbox,"HBoxContainer")
return root.find_node("Scene",true,false)
# 将控件添加到 - 编辑器右上角 - 运行场景等按钮之后
func add_control_to_editor_topright_area(control:Control):
add_control_to_container(EditorPlugin.CONTAINER_TOOLBAR,control)
# 编辑顶部菜单的HBoxContainer容器
func top_menu_container():
return top_container().get_child(0)
# ================================================ 顶部菜单
# 返回 - 索引为idx的顶部菜单 - MenuButton类型
func top_menu(idx:int):
top_menu_container().get_child(idx)
# 添加自定义顶部菜单
func add_sys_top_menu(text:String,items:PoolStringArray,target:Object,itm_pressed_fuc:String):
var top = top_menu_container()
# 创建MenuButton
var menu = MenuButton.new()
menu.text = text # 名
menu.get_popup().connect("id_pressed",target,itm_pressed_fuc) # 绑定菜单项点击
# 添加菜单项
var idx = 0
for item in items:
menu.get_popup().add_item(item,idx)
idx += 1
# 添加菜单
top.add_child(menu)
return menu.get_popup() # 返回PopupMenu
# 移除顶部菜单
# @param idx 要删除的顶部菜单在整个sys_top_menu_container中索引位置
# 一般请传入大于等于5的值,否则无效,不会删除原系统的菜单
func remove_sys_top_menu(idx = -1 ):
var top = top_menu_container()
var top_menus = top.get_children()
if idx > 4 and idx < top_menus.size(): # 不删除原系统菜单
top.remove_child(top_menus[idx])
elif idx == -1: # 默认值,删除全部自定义菜单
for aa in range(5,top.get_child_count()):
top.remove_child(top_menus[aa])
# ============================================== 系统对话框
# 系统对话框
enum SYS_DLG{
PROJECT_SETTING, # 项目设置
EDITOR_SETTING,# 编辑器设置
CREATE,# 新建资源
PLUGIN_CONFIG,# 创建插件
ABOUT,#关于Godot
FEATURE_PROFILE_MANAGER,# 编辑器功能管理
EXPORT# 项目导出对话框
}
# 显示对应的系统对话框
func show_sys_dialog(dlg:int,tab_index:int = 0):
var pal = face.get_base_control() # 编辑器的基础节点
var className = [
"ProjectSettingsEditor",
"EditorSettingsDialog",
"CreateDialog",
"PluginConfigDialog",
"EditorAbout",
"EditorFeatureProfileManager",
"ProjectExportDialog"
]
var _dlg = get_child_as_class(pal,className[dlg])
# 选项卡
var _tabs:TabContainer = get_child_as_class(_dlg,"TabContainer")
# 显示对话框
_dlg.popup()
# 切换选项卡
if tab_index>0 and tab_index< _tabs.get_tab_count():
_tabs.current_tab = tab_index
else:
_tabs.current_tab = 0
# ================================================ "场景"面板
func scene_tree_dock():
return root.find_node("Scene",true,false)
# ---- 节点添加 ----
# 返回当前场景中选中的节点
func get_selected_node() -> Node:
var sels = face.get_selection().get_selected_nodes() # 获取当前选中的节点集合
var _sel
if sels.size() == 1:
_sel =sels[0]
else:
_sel = null
return _sel
# “添加节点"对话框
func create_node_dialog():
return get_child_as_class(scene_tree_dock(),"CreateDialog")
# 当前正在编辑的场景的根节点
func edited_scene_root():
return face.get_edited_scene_root()
# 判断当前场景是否为空场景(也就是没有添加任何节点)
func current_scene_is_empty() -> bool:
if not edited_scene_root():# 当前场景为空场景
return true
else:
return false
# 为空场景添加根节点
# @param nodeType 节点类型的名称,字符串
func empty_scene_add_root(nodeType:String) -> void:
if current_scene_is_empty():# 当前场景为空场景
# 新建根节点
scene_tree_dock()._tool_selected(0) # 打开“添加Node”对话框 - @timothyqiu 提供的秘技
# 搜索框
var hs = create_node_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_node_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信号
# 为当前场景选中节点添加对应类型的子节点
# @param nodeType 节点类型名称,字符串
func select_node_add_child_node(nodeType:String):
var selected_node = get_selected_node()
if selected_node: # 场景非空,存在选中节点
if ClassDB.class_exists(nodeType):
# 添加子节点
var node:Node = ClassDB.instance(nodeType) # 按照类型名称添加节点
selected_node.add_child(node)
node.owner = edited_scene_root() # 设置owner为场景根节点
# ================================================ “文件系统”面板
func file_system_dock():
return face.get_file_system_dock()
# 在“文件系统”面板中选中路径为file_path的文件
func select_file(file_path:String) -> void:
face.select_file(file_path)
# ================================================ “检视器”面板
func inspector_dock():
return face.get_inspector()
func inspect_object(object:Object,for_property:String,inspector_only:bool = false) -> void:
face.inspect_object(object,for_property,inspector_only)
# 将控件添加到 - 检视器面板 - 底部
func add_control_to_inspector_bottom(control:Control):
add_control_to_container(EditorPlugin.CONTAINER_PROPERTY_EDITOR_BOTTOM,control)
# 切换编辑器 2D、3D、Script、AssetLib或其他的屏幕插件名称
func set_main_screen_editor(name:String) -> void:
face.set_main_screen_editor(name)
# === 场景操作相关 ===
func is_playing_scene() -> bool:
return face.is_playing_scene()
func stop_playing_scene() -> void:
face.stop_playing_scene()
func open_scene_from_path(scene_filepath:String) -> void:
face.open_scene_from_path(scene_filepath)
func play_current_scene() -> void:
face.play_current_scene()
func play_custom_scene(scene_file_path:String) -> void:
face.play_custom_scene(scene_file_path)
func play_main_scene() -> void:
face.play_main_scene()
func reload_scene_from_path(scene_file_path:String) -> void:
face.reload_scene_from_path(scene_file_path)
func save_scene():
return face.save_scene()
func save_scene_as(path:String,with_preview:bool = true) -> void:
face.save_scene_as(path,with_preview)
# ==== 插件的启用和停止 ====
func is_plugin_enabled(plugin:String) -> bool:
return face.is_plugin_enabled(plugin)
func set_plugin_enabled(plugin:String,enabled:bool) -> void:
face.set_plugin_enabled(plugin,enabled)
## ================================================ 脚本编辑器
# ScriptEditor
func script_editor():
return face.get_script_editor()
# 脚本菜单工具按钮列表(其中有部分不是按钮)
func script_top_container():
return script_editor().get_child(0).get_child(0)
# “创建脚本”对话框
func script_create_dialog():
return get_script_create_dialog()
# ScriptEditor下的TabContainer
func script_TabContainer():
return get_child_by_indexPath(script_editor(),[0,1,1])
# 返回当前打开的脚本编辑器或内置文档对应的控件
func get_current_Script_tab_control():
var sc_tabs:TabContainer = script_TabContainer() # 代码编辑器选项卡容器
var index = sc_tabs.current_tab # 当前打开的选项卡索引值
return sc_tabs.get_child(index)
# 返回当前打开的脚本编辑器的TextEdit控件引用
func get_current_Script_TextEdit():
var ctl = get_current_Script_tab_control()
if ctl.get_class() == "ScriptTextEditor":
var sc_edt = ctl
var txt_edt:TextEdit = get_child_by_indexPath(sc_edt,[0,0,0])
return txt_edt
# 获取当前脚本TextEdit控件的右键菜单
func get_current_Script_PopupMenu(): # -> PopupMenu
var ctl = get_current_Script_tab_control()
return get_child_as_class(ctl,"PopupMenu")
# ---- 内置文档 ----
# 在脚本界面,打开相应className对应的类型的内置文档
func open_class_help_in_editor(className:String) -> void:
if ClassDB.class_exists(className):
set_main_screen_editor("Script") # 切换到脚本编辑器界面
# 显示内置文档
script_editor()._help_class_goto(className) # 同样来自 @timothyqiu 提供的秘技
# 关闭所有打开的内置文档
func close_all_EditorHelp() -> void:
var sc_tabs:TabContainer = script_TabContainer() # 代码编辑器选项卡容器
var ctls = sc_tabs.get_children()
for ctl in ctls:
if ctl.get_class() == "EditorHelp":
sc_tabs.remove_child(ctl)
# ---- 插入代码 ----
# 在光标位置添加代码
func insert_code(code:String):
var edt = get_current_Script_TextEdit()
edt.insert_text_at_cursor(code)
# 追加内容到当前脚本编辑器末尾
func append_code(code:String):
var edt = get_current_Script_TextEdit()
edt.text += "\n\n" + code
edt.cursor_set_line(edt.get_line_count()) # 定位到最后一行
# 追加文件中的代码到当前脚本编辑器末尾
func append_file_code(codePath:String):
var dir = Directory.new()
if dir.file_exists(codePath):
append_code(loadString(codePath))
# ---- 插入注释 ----
# 分割线注释
func insert_HR_comment(str_or_char:String,repeat_time:int,comment:String = ""):
repeat_time = clamp(repeat_time,0,15)
insert_code("# " + str_or_char.repeat(repeat_time) + comment + str_or_char.repeat(repeat_time))
# 在脚本的最顶部添加元信息注释
func insert_top_meta_comment():
var meta_comment = "# %s\n" % "=".repeat(70)
meta_comment += "# 名称:\n"
meta_comment += "# 类型:\n"
meta_comment += "# 作者:\n"
meta_comment += "# 创建时间:\n"
meta_comment += "# 最后修改时间:\n"
meta_comment += "# %s\n" % "=".repeat(70)
var edt = get_current_Script_TextEdit()
edt.text = meta_comment +"\n" + edt.text
func insert_param_comment():
insert_code("# @param")
func insert_return_comment():
insert_code("# @return")
# 关闭所有打开的脚本(不关闭已经打开的内置文档)
func close_all_script() -> void:
var sc_tabs:TabContainer = script_TabContainer() # 代码编辑器选项卡容器
var ctls = sc_tabs.get_children()
for ctl in ctls:
if ctl.get_class() == "ScriptTextEditor":
sc_tabs.remove_child(ctl)
# === 2D场景 ===
# 将控件添加到 - 2D场景 - 顶部菜单
func add_control_to_2D_menu(control:Control):
add_control_to_container(EditorPlugin.CONTAINER_CANVAS_EDITOR_MENU,control)
# 将控件添加到 - 2D场景 - 左侧
func add_control_to_2D_left(control:Control):
add_control_to_container(EditorPlugin.CONTAINER_CANVAS_EDITOR_SIDE_LEFT,control)
# 将控件添加到 - 2D场景 - 右侧
func add_control_to_2D_right(control:Control):
add_control_to_container(EditorPlugin.CONTAINER_CANVAS_EDITOR_SIDE_RIGHT,control)
# 将控件添加到 - 2D场景 - 底部
func add_control_to_2D_bottom(control:Control):
add_control_to_container(EditorPlugin.CONTAINER_CANVAS_EDITOR_BOTTOM,control)
# === 3D场景 ===
# 将控件添加到 - 3D场景 - 顶部菜单
func add_control_to_3D_menu(control:Control):
add_control_to_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_MENU,control)
# 将控件添加到 - 3D场景 - 左侧
func add_control_to_3D_left(control:Control):
add_control_to_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_SIDE_LEFT,control)
# 将控件添加到 - 3D场景 - 右侧
func add_control_to_3D_right(control:Control):
add_control_to_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_SIDE_RIGHT,control)
# 将控件添加到 - 3D场景 - 底部
func add_control_to_3D_bottom(control:Control):
add_control_to_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_BOTTOM,control)
# ========================================== 额外的方法
# 返回指定路径文件中的内容
func loadString(path:String) -> String:
var file = File.new()
var string = ""
file.open(path,File.READ)
string = file.get_as_text() # 整个文件内容
file.close()
return string