Godot 3.4.2
用来管理物品的数据,废话不多说,直接上代码,核心代码如下:
#============================================================
# Item Manager
#============================================================
# 物品管理
# * 调用 add_item 方法传入 Dictionary 类型的数据进行添加物品数据
#============================================================
# @datetime: 2022-2-18 21:45:00
#============================================================
class_name ItemManager extends Node
## 物品被新添加时
signal item_added(item, item_id)
## 物品发生改变时
signal item_changed(item, item_id)
## 物品被移除时
signal item_removed(item, item_id)
## 物品数据对象
var __item_data__ := __ItemData__.new(
# name 键的值作为主键(作为记录唯一的对象)(添加的数据要包含有 name 这个 key)
"name",
# 对添加数据进行操作的对象,这个非常重要
# (按 Ctrl 并点击这个类进行查看操作内容,查看 __ItemData__ 类的 _init 查看介绍)
__Data_Handle__
# 要分组的 key 列表,这里我我传入了一个“type”,让其对添加的数据
# 的这个 key 的值进行分组,也就是对物品的 type 的值进行分组
).add_group_key(["type"])
# [ 回调处理数据 ]
class __Data_Handle__:
# 两个数据比较时会清除这个 key
# 如果除了这几个 key 之外的值都一样
# 则调用 add_data 对数据进行追加
# 否则调用 new_data 添加为新的数据
static func get_earse_key() -> Array:
return ['name', 'count', 'id']
# 添加的数据时,对新添加的数据的操作
static func new_data(data: Dictionary, id: String) -> void:
if not data.has("count"):
data['count'] = 1
data['id'] = id
# 对追加的数据的操作
static func add_data(a: Dictionary, b: Dictionary) -> void:
a['count'] += b['count'] if b.has('count') else 1
#============================================================
# Set/Get
#============================================================
## 获取所有物品
## @return
func get_all_item_list() -> Array:
return __item_data__.get_data().values()
## 获取所有物品数据
func get_all_item_data() -> Dictionary:
return __item_data__.get_data()
## 根据物品 Id名称 获取数据
## @id 物品的 ID名称
## @return 返回对应物品数据,如果没有,则返回空字典
func get_item_by_id(id: String) -> Dictionary:
if __item_data__.has_id_key(id):
return __item_data__.get_data_by_id_key(id)
else:
return {}
## 根据物品名称获取物品数据
func get_item_by_item_name(item_name: String) -> Array:
return __item_data__.get_data_by_key_value(item_name)
## 获取对应类型的物品
## @type 物品类型
func get_item_by_type(type: String) -> Array:
return __item_data__.get_data_list_by_group_value("type", type)
#============================================================
# 自定义
#============================================================
func _init():
__item_data__.connect("data_new_added", self, "_data_new_added")
__item_data__.connect("data_changed", self, "_data_changed")
__item_data__.connect("data_removed", self, "_data_removed")
# 连接信号
func _data_new_added(data, item_id):
emit_signal('item_added', data, item_id)
func _data_changed(data, item_id):
emit_signal('item_changed', data, item_id)
func _data_removed(data, item_id):
emit_signal("item_removed", data, item_id)
#============================================================
# 自定义
#============================================================
## 添加物品
## @item 物品数据
## @custom_attribute 对物品修改的属性
## @return 返回物品的 ID名称
func add_item(item: Dictionary, custom_attribute: Dictionary = {}) -> String:
if not custom_attribute.empty():
for key in custom_attribute:
item[key] = custom_attribute[key]
return __item_data__.add_data(item)
## 添加多个物品
## @return 返回添加的物品的 ID 列表
func add_items(item_list: Array) -> Array:
var id_list := []
var id
for item in item_list:
id = add_item(item)
if not id_list.has(id):
id_list.push_back(id)
return id_list
## 移除所有这个名字的物品
## @item_name 物品名
## @return 移除掉的物品的 ID名称
func remove_by_item_name(item_name: String) -> void:
__item_data__.remove_by_value_key(item_name)
## 根据 Id名称 移除物品
## @id 物品 id 名称
func remove_by_id(id: String) -> void:
__item_data__.remove_by_id_key(id)
## 删除多个物品
## @id_list 物品的 ID 列表
func remove_items_by_id(id_list: Array) -> void:
for id in id_list:
remove_by_id(id)
## 取出一个物品
func take_out(id: String, count: int = 1) -> Dictionary:
# 获取这个物品的数据
var item = get_item_by_id(id)
if not item.empty():
# 判断数量是否超过
var temp_item = item.duplicate(true)
if temp_item['count'] > count:
item['count'] -= count
temp_item['count'] = count
emit_signal("item_changed", item, id)
else:
temp_item['count'] = item['count']
__item_data__.remove_by_id_key(id) # 全部取出了所以移除
# 返回数据
return temp_item
else:
return {}
## 获取物品的数量
func get_item_count(id: String) -> int:
return __item_data__.get_data_by_id_key(id)['count']
#============================================================
# 内部类
#============================================================
# ========================= [ 物品数据 ]
class __ItemData__:
## 数据被新添加上去
signal data_new_added(data, id)
## 数据被改变
signal data_changed(data, id)
## 数据被移除
signal data_removed(data, id)
# ===============================================================
# 【!!!重要!!!】
# 数据回调,对数据进行处理
# 这个对象必须实现以下名称的 static 类型的方法
# 1. static func add_data(a: Dictionary, b: Dictionary) -> void:
# a 为已存在的数据,b 为新添加的数据
# 2. static func new_data(data: Dictionary, id: String) -> void:
# data 为这个新添加的数据,id 为记录的 id名称
# 3. static func get_earse_key() -> Array:
# 返回一个字符串列表,添加数据时,会清除这些 key 再比较
# ===============================================================
var __data_handle__ : Object
# 比较两个数据是否相同
var __equal__ : __EqualsData__ = __EqualsData__.new()
# 数据的 value 作为 key
var __value_id_key__ : String = ""
# 分组 Key
var __group_key__ : Array = []
# id 存储的数据:__data_by_id__[id] 返回对应数据
var __data_by_id__ := {}
# key 值存储的数据列表: __data_by_value_key__[key] 返回 Array
var __data_by_value_key__ := {}
# 根据数据中的对应 key 的 value 进行分组
var __data_by_group__ := {}
func get_data() -> Dictionary:
return __data_by_id__
## 根据分组 key 的 value 获取数据列表
## @group_key 进行分组的 key
## @type_key 这个组的类型
## @return 返回这个组的所有的类型的数据
func get_data_list_by_group_value(group_key: String, type_key: String) -> Array:
return __data_by_group__[group_key][type_key]
## 根据 ID名称 获取数据
func get_data_by_id_key(id_key: String) -> Dictionary:
return __data_by_id__[id_key]
## 判断是否存在这个 id
func has_id_key(id_key: String) -> bool:
return __data_by_id__.has(id_key)
## 根据数据的 id名称 的 value 获取对应数据列表
func get_data_by_key_value(value_key: String) -> Array:
return __data_by_value_key__[value_key]
## @id_key 将数据的对应 key 的 value 作为 id 进行记录
## @compare_add_data 如果两个数据相同时调用这个对象的 add_data 方法
func _init(
id_key: String,
compare_add_data: Object
):
__value_id_key__ = id_key
__data_handle__ = compare_add_data
for key in compare_add_data.get_earse_key():
__equal__.add_erase_key(key)
__equal__.add_erase_key(id_key)
## 添加分组的 key
## @key 这个 key 的 value 相同的为一组
## (用于对数据进行分类
## * 比如物品数据中的 ItemType 有 Weapon, Armor 类型
## 对这些数据的 key 的 value 进行一个分组)
func add_group_key(key) -> __ItemData__:
if key is Array:
for _v in key:
add_group_key(_v)
else:
if not __group_key__.has(key):
__group_key__.push_back(key)
return self
## 根据数据的 value 添加到组中
## @group_key: String 对它的这个 key 的值进行分组
## @data: Dictionary 要分组的数据
func add_data_to_group_by_value_key(
group_key: String,
data: Dictionary
) -> __ItemData__:
# 获取这个 key 的分组数据分类
var group_data : Dictionary
if not __data_by_group__.has(group_key):
__data_by_group__[group_key] = {}
group_data = __data_by_group__[group_key] as Dictionary
# 获取这个分组
var value_key = data[group_key]
if not group_data.has(value_key):
group_data[value_key] = []
var group := group_data[value_key] as Array
group.push_back(data)
return self
## 添加这个数据到分组中
func add_data_to_group(data: Dictionary):
for key in __group_key__:
add_data_to_group_by_value_key(key, data)
## 添加数据
## @return 返回这个数据的 ID名称
func add_data(data: Dictionary) -> String:
data = data.duplicate(true)
# 作为 key 的 value
var id_value = data[__value_id_key__]
# 获取相同的 id key 的数据列表
#(相同 id,但部分数据内容不同的列表)
if not __data_by_value_key__.has(id_value):
__data_by_value_key__[id_value] = []
# 判断是否有相同数据
for id_key in __data_by_id__.keys():
var item = __data_by_id__[id_key]
if item[__value_id_key__] == data[__value_id_key__]:
if compare(data, item):
__data_handle__.add_data(item, data)
emit_signal("data_changed", data, id_key)
return id_key
# 没有相同数据,则添加
var id_key = __new_id_key__(data[__value_id_key__])
__data_by_id__[id_key] = data
__data_by_value_key__[data[__value_id_key__]].push_back(data)
# 添加到分组中
add_data_to_group(data)
# 回调处理
__data_handle__.new_data(data, id_key)
emit_signal("data_new_added", data, id_key)
return id_key
## 新的 id key
func __new_id_key__(id_value: String) -> String:
var pos = id_value.find('&')
if pos > -1:
id_value = id_value.left(pos)
for i in INF:
var new_id_key = "%s&%d" % [id_value, i]
if not __data_by_id__.has(new_id_key):
return new_id_key
return "%s&%d" % [id_value, 0]
## 两个数据对比
func compare(a: Dictionary, b: Dictionary):
return __equal__.set_data(a).equal(b)
## 根据 id key 删除
func remove_by_id_key(id_key: String):
var data := __data_by_id__[id_key] as Dictionary
var value_id_key := data[__value_id_key__] as String
__data_by_value_key__[value_id_key].erase(data)
emit_signal("data_removed", __data_by_id__[id_key], id_key)
__data_by_id__.erase(id_key)
## 根据主键 id key 的 value 移除数据
func remove_by_value_key(value: String):
for id_key in __data_by_id__.keys():
if __data_by_id__[id_key][__value_id_key__] == value:
emit_signal("data_removed", __data_by_id__[id_key], id_key)
__data_by_id__.erase(id_key)
__data_by_value_key__.erase(value)
# ========================= [ 比较两个数据 ]
class __EqualsData__:
var __last_data__ : Dictionary
var __erase_key__ : Array
var __hash__ : int
# 设置要比较的数据
func set_data(data: Dictionary) -> __EqualsData__:
if __last_data__ == data:
return self
__last_data__ = data
var __temp_data__ = data.duplicate(true)
for key in __erase_key__:
__temp_data__.erase(key)
__hash__ = __temp_data__.hash()
return self
## 设置比较时要清除的 key
func add_erase_key(erase_key: String):
if not __erase_key__.has(erase_key):
__erase_key__.push_back(erase_key)
## 比较两个字典是否相同
var __temp_data__ : Dictionary
func equal(data: Dictionary) -> bool:
__temp_data__ = data.duplicate(true)
for key in __erase_key__:
__temp_data__.erase(key)
return __hash__ == __temp_data__.hash()
通过在场景中添加这个节点,连接上面的三个信号,对数据进行操控,在场景中添加节点
示例文件下载:
运行效果:
|