Skip to content

属性管理系统及BUFF系统

1.首先是一个属性脚本,管理角色属性

gdscript
extends Resource
class_name Stats

##枚举用于加buff的属性
enum BuffableStats{
	current_max_health,
	current_defense,
	current_attack,
	speed,
	health,
}

#region 此部分用于等级升级,若无此打算可忽略
###数值曲线数组,曲线根据等级返回数值
#const stat_curves:Dictionary[BuffableStats,Curve]={
	#BuffableStats.current_max_health:preload("uid://3vch3h8vn8nn"),
	#BuffableStats.current_defense:preload("uid://4cbidtfvw2ml"),
	#BuffableStats.current_attack:preload("uid://dd4dk1qiprft1")
#}
###基础经验
#const base_level_xp:float=100
#endregion

##生命值小于等于0时发出
signal health_depleted
##生命值改变时发出
signal health_changed(current_health:float,changed_hp:float,max_health:float,)
##属性改变时发出
signal attri_change(n:String,v:float,flag:StatBuff.BuffType)

#列出属性
@export var speed:float=200
@export var jump_speed:float=-350
#region 此部分用于等级升级,若无此打算可忽略
#@export var base_max_health:float
#@export var base_defense:float
#@export var base_attack:float
###经验值
#@export var experience:float=0:set=_experience_set
###等级计算和等级,每当获取level时自动返回等级结果
#var level:int:
	#get():return floor(sqrt(experience/base_level_xp)+0.5)
#endregion
@export var current_max_health:float
@export var current_defense:float
@export var current_attack:float
##生命值
@export var health:float=0:set=_health_set
##StatBuff数组,存放要加的buff
var stat_buffs:Array[StatBuff]

func _init() -> void:
	recaculate_stats()
	#print(current_max_health)
	_setup_stats.call_deferred()

##为了防止
func _setup_stats():
	health=current_max_health

##当血量改变时触发
func _health_set(current_health:float):
	#算出改变的血量
	var changed_hp:float=health-current_health
	#更新血量
	health=clampf(current_health,0,current_max_health)
	#发送血量改变信号
	health_changed.emit(current_health,changed_hp,current_max_health)
	#若血量小于零则发出死亡信号
	if health<=0:
		health_depleted.emit()
		
#region 此部分用于等级升级,若无此打算可忽略
#func _experience_set(v:float):
	#var old_level:int=level
	#experience=v
	#
	#if not old_level==level:
		#recaculate_stats()
#endregion
		
##添加buff
func add_buff(buff:StatBuff):
	stat_buffs.append(buff)
	recaculate_stats()

##移除buff
func remove_buff(buff:StatBuff):
	stat_buffs.erase(buff)
	recaculate_stats()

##计算状态
func recaculate_stats():
	##计算各个属性对应的增益值
	var stat_multipliers:Dictionary={}
	var stat_addends:Dictionary={}
	#便利
	for buff in stat_buffs:
		#这样写的目的是获取字符串类型的属性,而非枚举(int)类型的属性
		var stat_name:String=BuffableStats.keys()[buff.stat]
		# stat_name示例["current_max_health", "current_defense", "current_attack", "speed"] 0
		match buff.buff_type:
			StatBuff.BuffType.add:
				#算出增益总和并放入stat_addends中
				if not stat_addends.has(stat_name):
					stat_addends[stat_name]=0.0
				stat_addends[stat_name]+=buff.buff_amount
				#发送buff信号
				attri_change.emit(stat_name,buff.buff_amount,StatBuff.BuffType.add)
			StatBuff.BuffType.multiply:
				#算出增益总和并放入stat_multipliers中
				if not stat_multipliers.has(stat_name):
					stat_multipliers[stat_name]=1.0
				stat_multipliers[stat_name]+=buff.buff_amount
				#发送buff信号
				attri_change.emit(stat_name,buff.buff_amount,StatBuff.BuffType.add)
				#这部分是防止出现负数,看自己需求
				if stat_multipliers[stat_name]<0.0:
					stat_multipliers[stat_name]=0.0
	#region 此部分用于等级升级,若无此打算可忽略
	##先计算好当前的基础属性,当前的属性为基础属性乘以曲线比例
	##level在一个曲线上的位置值。
	#var curve_level_pos:float=(float(level)/100.0)-0.01
	#current_max_health=base_max_health*stat_curves[BuffableStats.current_max_health].sample(curve_level_pos)
	#current_defense=base_defense*stat_curves[BuffableStats.current_defense].sample(curve_level_pos)
	#current_attack=base_attack*stat_curves[BuffableStats.current_attack].sample(curve_level_pos)
	#endregion

	#将增益值应用到当前基础属性
	for stat in stat_multipliers:
		set(stat,get(stat)*stat_multipliers[stat])
	for stat in stat_addends:
		set(stat,get(stat)+stat_addends[stat])
	pass

2.然后是一个buff脚本,用于定义buff

gdscript
extends Resource
class_name StatBuff

enum BuffType{
	multiply,
	add,
}

@export var stat:Stats.BuffableStats
@export var buff_amount:float
@export var buff_type:BuffType

func _init(_stat:Stats.BuffableStats=Stats.BuffableStats.current_max_health,
			_buff_amount:float=1,
			_buff_type:StatBuff.BuffType=BuffType.multiply) -> void:
	stat=_stat
	buff_type=_buff_type
	buff_amount=_buff_amount