Godot物品数据数据管理

Posted 张学徒

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Godot物品数据数据管理相关的知识,希望对你有一定的参考价值。

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 相同的为一组
	## (用于对数据进行分类
	## * 比如物品数据中的 ItemTypeWeapon, 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__.以上是关于Godot物品数据数据管理的主要内容,如果未能解决你的问题,请参考以下文章

传奇私服DBC问题:加载物品(Idx:0 Name:)数据失败!!!物品数据库加载失败!!!代码: -100

服务端捡起或丢弃指定物品ID触发详解

hihocoder-1486物品价值(状压dp)

给定物品列表,预测要出售的物品

推荐算法学习实践:基于物品相似度

[Offer收割]编程练习赛11 题目2 : 物品价值