【Godot】保存当前场景中所有的子节点的属性

Godot 3.4.4

我使用 Godot 制作应用程序所用到的功能,对一些需要用到的属性进行保存。

稍微修改也可以根据节点进行对一些游戏节点的数据的保存功能,思路都是一样的。

SAVE_PROPERTY_LIST 常量用于判断节点是否包含其中的属性,如果存在,则保存节点的这个属性的数据。

注意下面 _ready 方法里的 if child is Control: 做了只对 Control 进行保存的限制,删除即可对全部节点进行保存。

## 保存整个场景中的节点的信息
class_name SaveSceneControlNodeData
extends Node


## 要保存的属性(如果节点存在这个属性名,则保存这个数据)
const SAVE_PROPERTY_LIST : Array = ['text', 'pressed', "split_offset"]


# 树中的节点的数据
var _tree_node_data : Dictionary = {}


var _directory : Directory = Directory.new()
var _file : File = File.new()


func _enter_tree():
    load_data()


func _exit_tree():
    save_data()


func _ready():
    # 场景中的所有子节点在退出节点进行保存数据
    var list = []
    __all_children__(owner, list)
    for child in list:
        # 这里我限制了只对 Control 类型的节点的数据进行保存
        if child is Control:
            child.connect("tree_exiting", self, "__save_node_data__", [
                child, child.get_path(), _tree_node_data
            ])


## 加载保存的数据
func load_data():
    var save_filename = get_save_filename()
    if _file.file_exists(save_filename):
        if _file.open(save_filename, File.READ) == OK:
            var content : String = _file.get_as_text()
            _file.close()

            var saved_data = parse_json(content)
            if saved_data:
                # 将属性设置到对应节点
                for path in saved_data:
                    var node : Node = get_node(path)
                    var p_data : Dictionary = saved_data[path]
                    for property in p_data:
                        node.set(property, p_data[property])

        else:
            print("打开 ", save_filename, " 文件失败")


## 保存数据
func save_data():
    var f = get_save_filename()
    print("准备保存文件:", f)
    if _file.open(f, File.WRITE) == OK:
        _file.store_string( to_json(_tree_node_data) )
        _file.close()
        print("保存 ", f, " 文件成功")
    else:
        print("保存失败")


## 获取保存的文件的路径
##(根据当前的场景路径,保存到这个场景的目录下,格式为:名称.json)
func get_save_filename():
    # 保存到的目录
    var save_to_path = owner.filename.get_base_dir()
    if not _directory.dir_exists(save_to_path):
        save_to_path = "res://"
    # 文件名
    var fname = owner.filename.get_file().get_basename()
    if fname == "":
        fname = 'scene_control_node_data'

    # 完整文件路径
    save_to_path = save_to_path.plus_file(fname) + '.json'
    return save_to_path


# 递归获取所有的节点
func __all_children__(parent: Node, list: Array):
    for child in parent.get_children():
        list.append(child)
    for child in parent.get_children():
        __all_children__(child, list)


# 记录这个节点的数据
func __save_node_data__(node: Node, node_path: NodePath, data: Dictionary):
    # 获取这个节点中包含的属性的数据
    var current_data = {}
    for property in SAVE_PROPERTY_LIST:
        if property in node:
            current_data[property] = node[property]

    if current_data.size() > 0:
        # 根据节点路径记录数据
        data[node_path] = current_data

添加节点到场景中,默认节点都是没有任何内容的,运行后修改节点的属性,然后关闭再打开,即可看到节点存在了内容,对制作应用程序来说很方便。

发表评论