自己的理解
signal exp_updated(current, needed) # 定义信号:参数为当前经验、升级所需经验
是自己定义的类似函数 但是有发送消息功能
exp_updated.emit(exp, exp_needed) # 发出信号,通知UI更新
然后用这个的emit发消息
player.exp_updated.connect(_on_exp_updated) # 连接信号
连接这个消息函数 然后connect到自己的函数去获取传递的变量
func _on_exp_updated(current, needed): 自己的函数 去获取到变量后进行自己的计算
整体流程
玩家(Player)拥有经验值和等级。
击杀敌人时,敌人调用玩家的 add_exp() 方法。
玩家经验增加,可能升级,并发出 exp_updated 信号。
UI 界面(ExperienceBar)监听了这个信号,收到后更新进度条和文字。
1️⃣ 玩家脚本 (Player.gd)
python
gdscript
extends CharacterBody2D
signal exp_updated(current, needed) # 定义信号:参数为当前经验、升级所需经验
var level = 1
var exp = 0
var exp_needed = 50 # 从1级升到2级需要50点经验
func add_exp(amount):
exp += amount
while exp >= exp_needed: # 可能一次获得很多经验,连续升级
exp -= exp_needed
level += 1
exp_needed = int(exp_needed * 1.2) # 每级需求增加20%
print("升级! 当前等级:", level)
exp_updated.emit(exp, exp_needed) # 发出信号,通知UI更新
关键点解释
signal exp_updated(current, needed)
声明了一个信号,它会在经验值变化时发出,并携带两个整数:当前经验和升级所需经验。UI 会连接这个信号。
exp_needed
升到下一级所需的经验值。初始为 50,意味着从 1 级升到 2 级需要 50 经验。
add_exp(amount)
外部(比如敌人)调用此方法增加经验。
先累加 exp。
用 while 循环检查是否达到或超过升级需求(可能一次性获得大量经验连升多级)。
升级时:扣除所需经验,等级 +1,并增加下一级的需求(这里用乘以 1.2,即每级需求增长 20%)。
最后发出 exp_updated 信号,把当前经验和新的升级需求传出去。
为什么用 while 而不是 if?
假如你获得 500 经验,可能连续升好几级,while 能处理这种情况。
2️⃣ UI 界面脚本 (ExperienceBar.gd)
python
gdscript
extends CanvasLayer # 保证UI永远在最前,不随相机移动
@onready var bar = $Control/ProgressBar
@onready var label = $Control/Label
func _ready():
var player = get_tree().get_first_node_in_group("player")
if player:
player.exp_updated.connect(_on_exp_updated) # 连接信号
func _on_exp_updated(current, needed):
bar.max_value = needed
bar.value = current
label.text = str(current) + "/" + str(needed)
关键点解释
CanvasLayer 根节点
让 UI 层独立于游戏世界,即使相机移动,经验条也固定在屏幕上。
get_tree().get_first_node_in_group("player")
找到场景中属于 "player" 组的第一个节点(你的玩家角色)。
注意:你需要在编辑器中选中玩家节点,在"节点"面板的 "Groups" 里添加 player 组。
player.exp_updated.connect(_on_exp_updated)
把玩家发出的 exp_updated 信号连接到 UI 自己的 _on_exp_updated 函数。这样当玩家经验变化时,UI 就会自动收到通知。
_on_exp_updated(current, needed)
收到信号后:
设置进度条的 max_value 为升级所需经验。
设置进度条的 value 为当前经验。
更新文本显示,例如 "35/50"。
3️⃣ 敌人脚本调用经验增加
gdscript
在 Enemy.gd 中,当敌人死亡时
python
func die():
var player = get_tree().get_first_node_in_group("player")
if player:
player.add_exp(10) # 击杀奖励10经验
queue_free()
关键点解释
同样通过组找到玩家节点。
直接调用玩家脚本中的 add_exp 方法,传入击杀奖励数值(比如 10)。
玩家内部会自动处理经验累加、升级、信号发射。
📌 为什么这是"标准做法"?
特性 说明
简单 只有两个信号、三个函数,没有复杂的单例或全局变量。
解耦 玩家不需要知道 UI 的存在,只需发出信号;UI 也不需要知道玩家如何计算经验,只负责显示。
健壮 while 循环处理连升多级;CanvasLayer 保证 UI 始终可见。
易扩展 想要增加升级特效?在 add_exp 里加一行 emit_signal("level_up", level) 即可。
🧪 运行流程举例
游戏开始:玩家等级 1,经验 0,需要 50 升级。UI 显示 0/50。
击杀一只僵尸 → 敌人调用 player.add_exp(10)
玩家经验变为 10,未到 50 → 发出信号 exp_updated(10, 50)
UI 收到 → 进度条变成 10/50。
再杀 4 只 → 经验累计 50 → while 循环触发:
等级变为 2,经验归 0(50-50),新的升级需求 = 50 * 1.2 = 60
发出信号 exp_updated(0, 60)
UI 更新为 0/60,同时控制台打印"升级! 当前等级: 2"。
继续游戏,经验从 0 开始向 60 积累。