千里之行,始于足下
零、 笔记
制作简易库存,用于存放被收集的物品。在Godot4.3类星露谷游戏开发之【简易库存】(UI部分)的基础上,本章将进一步打通从 “收集物品” 到 “更新物品槽 UI 表现” 与 “同步物品字典数据” 的完整逻辑链;
一、设计架构
在Godot4.3类星露谷游戏开发之【可收集物品】中,我们采用组件化思想,设计并创建了 可收集组件.tscn 。该组件可以作为任意物品的子节点,赋予物品可收集的功能。现在,为了实现物品被收集后,同步变更物品数据的目标,设计架构如下:
二、附加脚本
(一)更新——可收集组件.gd
class_name 可收集组件
extends Area2D
signal 已收集
@export var 物品名: String
var 物品纹理: Texture2D
func _on_body_entered(body: Node2D) -> void:
if body.is_in_group("玩家"):
# 更新库存物品数据,将物品添加到库存面板物品槽
物品纹理 = get_parent().texture
if InventoryManager.尝试添加物品(物品名, 物品纹理):
已收集.emit()
get_parent().queue_free()
else:
print("物品槽已满,无法收集")
(二)库存管理器.gd(单例)
第一步,在路径 res://脚本/全局脚本/ 下创建独立脚本 库存管理器.gd ;
extends Node
signal 库存变更(物品字典, 物品纹理字典) # 使用 Texture2D 类型
var 库存: Dictionary = {} # 键: 物品名, 值: [数量, Texture2D]
var 占用槽位: int = 0 # 实时记录已占用的槽位数(数量>0的物品)
# 尝试添加物品到库存,返回是否成功
func 尝试添加物品(物品名: String, 物品纹理: Texture2D) -> bool:
# 已有物品:增加数量
if 库存.has(物品名):
库存[物品名][0] += 1
更新并发送库存信号()
return true
# 新物品:检查物品槽是否有空位
elif 占用槽位 < 6:
库存[物品名] = [1, 物品纹理]
占用槽位 += 1 # 新增物品,槽位计数+1
更新并发送库存信号()
return true
else:
print("添加失败:物品槽已满(最多显示6种物品)")
return false
# 尝试从库存中移除物品,返回是否成功
func 尝试移除物品(物品名: String, 数量: int = 1) -> bool:
if not 库存.has(物品名):
return false
库存[物品名][0] -= 数量
if 库存[物品名][0] <= 0:
库存.erase(物品名) # 数量为0时移除物品
占用槽位 -= 1 # 物品移除,槽位计数-1
更新并发送库存信号()
return true
# 内部方法:更新并发送库存信号
func 更新并发送库存信号():
# 准备要发送的数据
var 物品字典 = {}
var 物品纹理字典 = {}
# 构建物品数量字典和物品纹理字典(此时库存中所有物品数量都>0)
for 物品 in 库存.keys():
物品字典[物品] = 库存[物品][0] # 物品名: 数量
物品纹理字典[物品] = 库存[物品][1] # 物品名: 纹理
库存变更.emit(物品字典, 物品纹理字典) # 发送变更信号
第二步,打开 项目->项目设置->全局,设置该脚本为 单例,并命名节点名称为 InventoryManager ;
(三)库存UI.gd
切换到 库存UI.tscn 场景,选中根节点 库存UI ,附加脚本;
extends NinePatchRect
# 物品槽UI元素引用(保持用户定义的变量名)
@onready var 物品纹理: TextureRect = $"MarginContainer/HBoxContainer/物品槽/物品纹理"
@onready var 物品数量: Label = $"MarginContainer/HBoxContainer/物品槽/物品纹理/物品数量"
@onready var 物品纹理2: TextureRect = $"MarginContainer/HBoxContainer/物品槽2/物品纹理2"
@onready var 物品数量2: Label = $"MarginContainer/HBoxContainer/物品槽2/物品纹理2/物品数量2"
@onready var 物品纹理3: TextureRect = $"MarginContainer/HBoxContainer/物品槽3/物品纹理3"
@onready var 物品数量3: Label = $"MarginContainer/HBoxContainer/物品槽3/物品纹理3/物品数量3"
@onready var 物品纹理4: TextureRect = $"MarginContainer/HBoxContainer/物品槽4/物品纹理4"
@onready var 物品数量4: Label = $"MarginContainer/HBoxContainer/物品槽4/物品纹理4/物品数量4"
@onready var 物品纹理5: TextureRect = $"MarginContainer/HBoxContainer/物品槽5/物品纹理5"
@onready var 物品数量5: Label = $"MarginContainer/HBoxContainer/物品槽5/物品纹理5/物品数量5"
@onready var 物品纹理6: TextureRect = $"MarginContainer/HBoxContainer/物品槽6/物品纹理6"
@onready var 物品数量6: Label = $"MarginContainer/HBoxContainer/物品槽6/物品纹理6/物品数量6"
# 物品槽UI元素数组(使用正确的变量名初始化)
var 物品图片数组 = []
var 物品数量数组 = []
func _ready():
# 初始化物品槽数组(修正变量引用)
物品图片数组 = [物品纹理, 物品纹理2, 物品纹理3, 物品纹理4, 物品纹理5, 物品纹理6]
物品数量数组 = [物品数量, 物品数量2, 物品数量3, 物品数量4, 物品数量5, 物品数量6]
# 连接库存变更信号
InventoryManager.库存变更.connect(_on_库存变更)
func _on_库存变更(物品字典, 物品纹理字典):
# 清空所有物品槽显示
for i in range(6):
物品图片数组[i].visible = false
物品数量数组[i].text = ""
# 更新有物品的槽位
var 物品索引 = 0
for 物品名 in 物品字典.keys():
if 物品索引 >= 6:
break
var 数量 = 物品字典[物品名]
var 纹理: Texture2D = 物品纹理字典[物品名] # 明确指定 Texture2D 类型
# 设置物品图片
if 纹理:
物品图片数组[物品索引].texture = 纹理
物品图片数组[物品索引].visible = true
# 设置物品数量(始终显示,不隐藏)
物品数量数组[物品索引].text = str(数量)
物品索引 += 1
三、搭建测试环境
第一步,参考Godot4.3类星露谷游戏开发之【可收集物品】,创建多个可收集物品;
第二步,选中各个可收集物品场景中的 可收集组件 节点,并在检查器中填上 物品名 ,这里以 蛋.tscn 为例;
第三步,将可收集物品添加到 测试_简易库存.tscn 场景中,完成测试场景搭建;
四、测试
运行 测试_简易库存.tscn 场景,并收集所有可收集物品以测试;
发现收集木屋时,库存UI变形!据此可以定位到 库存UI.tscn 场景存在问题,采取措施如下:
回到 库存UI.tscn 场景中,分别选中各个 物品纹理 节点,更改 Expand Mode 为 Ignore Size,更改 Stretch Mode 为 Keep Aspect Centered ;
再次运行场景,问题得到解决;
测试完成!
五、免费开源资产包
-
进入链接后点击下图按钮;
-
然后点击【No thanks,just take me to the downloads】(不了谢谢,只想下载);
-
最后点击下图按钮完成下载(注意导入前需解压缩)。