【Godot】数据管家:数据管理

Godot 4.0 alpha 14

数据管家,暂时只想到了用于管理物品数据

数据状态

#============================================================
#    Data State
#============================================================
# - datetime: 2022-08-24 12:46:54
#============================================================

##  数据状态。操作数据时的数据的状态,对数据进行修改以影响添加时的内容
class_name DataState


##  当前的数据
var data : Dictionary 
##  是否是新的数据
var is_new := false
##  是否要添加这个数据
var add := true
##  是否已经添加过了
var is_added := false

数据管家

#============================================================
#    Data Steward
#============================================================
# - datetime: 2022-08-23 23:42:06
#============================================================

##  数据管家
class_name DataSteward
extends Node


##  操作数据。如果对 state 的属性进行修改会影响后面添加时的操作
signal operation_data(state: DataState)
##  属性发生改变
signal property_changed(id, old_data: Dictionary, new_data: Dictionary)


#  ID key 
var __id_key
#  ID 到数据的映射
var __id_to_data_map : Dictionary = {}

# 分组 key 列表
var __group_key_list : Array = []
#  分组数据
var __group_value_to_data_map : Dictionary = {}


#============================================================
#  SetGet
#============================================================
##  添加 ID。可以通过这个 Key 的值获取到对应的数据
func set_id_key(key):
    assert(__id_key == null, "只能设置一次 ID key")
    __id_key = key

##  获取 ID key
func get_id_key():
    return __id_key

##  获取数据
##[br]
##[br][code]id_value[/code]  ID 值
func get_data(id_value) -> Dictionary:
    return __id_to_data_map.get(id_value)

##  获取所有数据
func get_all_data() -> Dictionary:
    return __id_to_data_map

##  获取数据列表
func get_data_list() -> Array[Dictionary]:
    return __id_to_data_map.values()

##  获取这个组中的数据
##[br]
##[br][code]group_key[/code]  这个组的key
##[br][code]group_value[/code]  这个组的 Key 包含有的值
func get_data_by_group(group_key, group_value) -> Array[Dictionary]:
    return __group_value_to_data_map.get(group_key, {}).get(group_value, {}).keys()


##   筛选
##[br]
##[br][code]condition[/code]  条件方法。这个方法需要有一个 [code]Dictionary[/code] 类型的参数用于接收判断数据,
## 并返回 [code]bool[/code] 类型结果
func filter(condition: Callable) -> Array[Dictionary]:
    var list : Array[Dictionary] = []
    for data in get_data_list():
        if condition.call(data):
            list.append(data)
    return list


##  获取这个组中符合条件的数据数据
##[br]
##[br][code]condition[/code]  条件数据。只要 [code]condition[/code] 里的数据都包含于数据中则符合条件
func filter_by_dict(condition: Dictionary) -> Array[Dictionary]:
    var list : Array[Dictionary] = []
    var condi_hash := condition.hash()
    var temp := {}
    for data in get_data_list():
        for k in condition:
            temp[k] = data[k]
        if temp.hash() == condi_hash:
            list.append(data)
    return list


#============================================================
#  自定义
#============================================================
# 新的数据
func __new_data(state: DataState):
    operation_data.emit(state)
    if state.add:
        if state.is_new:
            __id_to_data_map[state.data[__id_key]] = state.data
            # 数据发生改变
            property_changed.emit(state.data[__id_key], {}, state.data)
        else:
            __add_data(state)


# 追加数据
func __add_data(state: DataState):
    operation_data.emit(state)
    if state.add:
        if state.is_new:
            __new_data(state)
        else:
            # 获取数据
            var id_to_data := __id_to_data_map[state.data[__id_key]] as Dictionary
            # 记录为旧数据
            var old_data = id_to_data.duplicate(true)
            # 追加数据值
            for key in state.data:
                if typeof(state.data[key]) in [TYPE_FLOAT, TYPE_INT]:
                    if id_to_data.has(key):
                        id_to_data[key] += state.data[key]
                    else:
                        id_to_data[key] = state.data[key]
            # 数据发生改变
            if old_data.hash() != id_to_data.hash():
                property_changed.emit(state.data[__id_key], old_data, id_to_data)


# 添加到分组中
func __add_to_group(dict: Dictionary):
    var group_data : Dictionary
    var group_value
    for group_key in __group_key_list:
        # 获取这个组,并添加到这个组中
        group_data = __group_value_to_data_map[group_key]
        group_value = dict.get(group_key)
        __group_value_to_data_map[group_key]
        if group_value:
            if not group_data.has(group_value):
                group_data[group_value] = {}
            group_data[group_value][dict] = null


##  添加组别 Key。通过这个 key 的值获取这个组里的所有数据
func add_group_key(group_key):
    __group_key_list.append(group_key)
    __group_value_to_data_map[group_key] = {}


##  添加数据
func add_data(dict: Dictionary):
    var state := DataState.new()
    state.data = dict
    state.is_added = false
    state.add = true
    if __id_to_data_map.has(state.data[__id_key]):
        state.is_new = false
        __add_data(state)
    else:
        state.is_new = true
        __new_data(state)
    __add_to_group(state.data)
    return state.data[__id_key]


## 根据ID添加数据
func add_data_by_id(id, dict: Dictionary):
    dict[__id_key] = id
    add_data(dict)



测试

测试代码,按 ctrl + shift + X 执行,或者点击脚本编辑上方的 文件-运行

#============================================================
#    Demo
#============================================================
# - datetime: 2022-08-24 01:15:45
#============================================================

# 测试功能

@tool
extends EditorScript


func _run() -> void:
    # 创建数据管家
    var d = DataSteward.new()

    # 设置数据的 ID,通过这个 ID key 的值获取对应的数据
    d.set_id_key("name")

    # 设置数据分组,通过这个组的 key 的值获取这个值的组的所有数据
    # 比如数据中包含有 type 的 key,这个 key 里有 “食物”“武器”“药品”等
    # 添加这个组别,将会对这个几个key进行分组,获取组别为“武器”,
    # 将会得到这个组里的所有type的值为“武器”的数据
    d.add_group_key("type")

    # 操作数据,添加数据时会发出 operation_data 信号
    d.operation_data.connect(func(state: DataState):
        # 没有添加这个数据时
        if not state.is_added:
            # 没有 count 这个 key 时
            if not state.data.has("count"):
                # 我们对数据自动添加 count 键,就是物品的数量
                state.data["count"] = 1
    )

    # 连接数据发生改变时,调用这个 lambda 表达式
    d.property_changed.connect(func(id, old_data: Dictionary, new_data: Dictionary):
        prints(" -> ", id, " 数据发生改变,新数据为:", new_data)
    )

    # 添加数据
    d.add_data({
        "name": "黄酒",
        "type": "食物",
        "health": 100,
        "coin": 10,
    })
    d.add_data({
        "name": "青铜剑",
        "type": "武器",
        "coin": 500,
    })
    d.add_data({
        "name": "精钢剑",
        "type": "武器",
        "coin": 900,
    })


    # 获取所有数据
    print(d.get_data_list())
    print("-".repeat(40))

    # 增加黄酒的 count 值
    d.add_data({
        "name":"黄酒",
        "count": 10,
    })

    # 添加青铜剑的数量(也可以这样添加数据)
    d.add_data_by_id("青铜剑", {
        "count": 2,
    })

    # 获取“黄酒”的数据
    print(d.get_data("黄酒"))
    print("黄酒数量:", d.get_data("黄酒").get("count") )

    # 获取所有 type 为 “武器” 的数据
    print(d.get_data_by_group("type", "武器"))

    # 筛选
    print("价格超过400的物品:", d.filter(func(data: Dictionary):
        return data.get('coin') > 400
    ) )



执行结果如下:

发表评论