【极简】Godot4.4 简易仓库A(附完整代码/素材包)

无望其速成,无诱于势利。

一、展示

【极简】Godot4.4 快速搭建测试场景A(附完整代码/素材包)基础上,本文实现简易仓库,功能:物品堆叠。

请添加图片描述

二、复刻

(一)节点结构

1. inventory_ui.tscn

  • InventoryUI(CanvasLayer)
    • PanelContainer
      • GridContainer

2. slot_ui.tscn

  • SlotUI(VBoxContainer)
    • TextureRect
      • StackLabel(Label)
    • NameLabel(Label)

请添加图片描述

(二)独立资源/脚本

1. event_bus.gd(事件总线)

功能:集中定义信号

extends Node

@warning_ignore("unused_signal")
signal inventory_item_added(item: InventoryItem)	# 添加物品

var inventory_items: Array[Resource]	# 存储物品数据的列表

func _ready() -> void:
	inventory_items.resize(6)

项目设置->全局->路径(该脚本的路径)->添加,使得该脚本被设置为全局脚本。

在这里插入图片描述

2. inventory_item.gd(物品信息模板)

功能:可复用的物品信息的模板

class_name InventoryItem
extends Resource

@export var texture: Texture
@export var name: String
@export var max_stack: int = 99
var stack: int = 0

3. inventory_item.tres(物体信息实体)

创建resource文件,并命名为 inventory_item.tres;

在这里插入图片描述
在这里插入图片描述
点击打开后,在检查中把inventory_item.gd 附加到 inventory_item.tres 上;

在这里插入图片描述
可以发现检查器中多出来InventoryItem,里面正是在 inventory_item.gd 中的各种数值。

(三)附加脚本

1. Egg.gd

附加到egg.tscn中的Egg节点(Sprite2D):

extends Sprite2D
## 可收集的蛋

@export var item: InventoryItem
# 蛋的默认数量
@export var stack : int = 1

# 从PickUpComponent连接的信号
func _on_pick_up_component_body_entered(body: Node2D) -> void:
	if body is CharacterBody2D:	
		item.stack = stack
		EventBus.inventory_item_added.emit(item)	# 蛋被收集后发送广播信号 
		queue_free()	# 删除蛋 

2. inventory_ui.gd

附加到 inventory_ui.tscn中的InventoryUI节点(CanvasLayer):

class_name InventoryUI
extends CanvasLayer
## 库存面板,用于更新物品槽,处理事件

const SLOT_UI = preload("res://scenes/UI/slot_ui.tscn")

@export var sizes: int = 6					# 物品槽的总数
@export var columns: int = 3				# 物品槽的列数 

@onready var grid_container: GridContainer = $PanelContainer/GridContainer


func _ready() -> void:
	# 在库存面板中初始化所有的物品槽
	grid_container.columns = columns
	for i in sizes:
		var slot = SLOT_UI.instantiate()
		slot.slot_index = i
		grid_container.add_child(slot)
	
	# 连接添加物品信号
	EventBus.inventory_item_added.connect(_on_egg_inventory_item_added)


# 当收到egg节点发送的信号inventory_item_added后,更新库存面板
# 命名规范:_on_[发送节点名]_[发送信号名]
func _on_egg_inventory_item_added(item: InventoryItem) ->void:
	# TODO: 先堆叠同名物品,若有剩余物品,再寻空物品槽加入
	var remain: int = item.stack
	var index: int = -1

	# 寻找同名物品,若存在且有空位进行堆叠
	for i in EventBus.inventory_items.size():
		if EventBus.inventory_items[i] != null and EventBus.inventory_items[i].name == item.name and remain > 0:
			var available: int = EventBus.inventory_items[i].max_stack - EventBus.inventory_items[i].stack
			index = i
			EventBus.inventory_items[i].stack += min(remain, available)	# 堆叠物品  
			
			# 更新原本的slot标签
			update_slot_stack_label(EventBus.inventory_items[i], index)
			remain = remain - available		#剩余未堆叠物品
	
	
	# 将未堆叠的剩余物品放进空物品槽(如果有的话)		
	while remain > 0 and EventBus.inventory_items.has(null):
		# 放进空物品槽
		var add_mount:int = min(remain, item.max_stack)
		var new_item:InventoryItem = item.duplicate(true)	#创建一个新的item
		new_item.stack = add_mount
		var first_empty_index: int = EventBus.inventory_items.find(null)
		EventBus.inventory_items[first_empty_index] = new_item# 保存进列表
		update_first_empty_slot(new_item)	# 选择第一个空槽,更新物品信息
		
		# 剩余物品若大于零,继续循环找空位放置 
		remain = remain - add_mount
		
	
# 放进从左往右,从上到下数第一个空槽
func update_first_empty_slot(item: InventoryItem) ->void:
	# 过滤出当前所有的空槽
	var empty_slots: Array = grid_container.get_children().filter(func(slot): return slot.is_empty)
	#选择空槽列表中的第一个
	var first_empty_slot :SlotUI = empty_slots.front()
	#创建一个空格
	first_empty_slot.update_slot(item)


# 跟新物品槽数量标签
func update_slot_stack_label(item: InventoryItem, index: int) ->void:
	grid_container.get_child(index).stack_label.text = str(item.stack)

如果 const SLOT_UI = preload(“res://slot_ui.tscn”) 报错,说明路径不对,需改成文件系统中自定义的slot_ui.tscn所在的路径。

3. slot_ui.gd

附加到 slot_ui.tscn 中的 SlotUI 节点(VBoxContainer):

class_name SlotUI
extends VBoxContainer
## 物品槽,实现拖放

@export var inventory_item: InventoryItem
var is_empty: bool = true  #物品槽默认为空
var slot_index: int = -1  #物品槽索引默认为-1

@onready var texture_rect: TextureRect = $TextureRect
@onready var stack_label: Label = $TextureRect/StackLabel
@onready var name_label: Label = $NameLabel


# 初始化物品槽
func _ready() -> void:
	if inventory_item.texture != null:
		texture_rect.texture = inventory_item.texture
	if inventory_item.name != null:	
		name_label.text = inventory_item.name
	
	
	
# 当收到InventoryUI节点发送的信号后,更新物品槽
# 命名规范:_on_[发送节点名]_[发送信号名]
func update_slot(item: InventoryItem) ->void:
	texture_rect.texture = item.texture
	stack_label.text = str(item.stack)
	name_label.text = item.name	
	is_empty = false

4. slot_ui.tscn

选中场景中的SlotUI节点,在检查器中加载物品信息模板 inventory_item.tres;

###

5. egg.tscn

首先我们找到 inventory_item.tres 文件,将它复制为 egg_inventory_item.tres;

在这里插入图片描述
选中 egg.tscn 场景中的 Egg 节点,在检查器中加载物品信息模板 egg_inventory_item.tres;
并在Texture、Name中分别填上蛋的图片和名字信息;

在这里插入图片描述

(四)其他设置

1. inventory_ui.tscn

选中 inventory_ui.tscn 场景下的 PanelContainer 节点,在检查器Layout->Custom Minimum Size设置x = 90.0px, y = 76.0px,然后找到锚点预设,将当前节点设置为居中;

在这里插入图片描述

2. slot_ui.tscn

选中 slot_ui.tscn 场景下的 TextureRect 节点,在检查器Layout->Custom Minimum Size设置x = 30.0px, y = 30.0px;

在这里插入图片描述
选中 slot_ui.tscn 场景下的 StackLabel 节点,在检查器中设置为右下方向;

在这里插入图片描述
选中 slot_ui.tscn 场景下的 StackLabel 节点在检查器Control->Transform:Size.x= 30.0px,Size.y = 30.0px;

在这里插入图片描述
选中 slot_ui.tscn 场景下的 StackLabel 节点在检查器Control->Theme中新建Theme,然后将默认字体大小 Default Font Size 设置为10px;
在Theme Overrides下勾选字体阴影颜色 Font Shadow Color 和字体轮廓颜色 Font Outline Color;

在这里插入图片描述
同样,选中slot_ui.tscn 场景下的 NameLabel 节点在检查器设置如下图所示;
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3. 显示画面太小

在项目设置->显示->窗口:缩放设置为4.0;

在这里插入图片描述

4. 画面模糊

在项目设置->渲染->纹理->画布纹理:默认纹理过滤设置为Nearest;

在这里插入图片描述

三、运行测试

搭建测试场景如下:

在这里插入图片描述
请添加图片描述

四、自查对照

问题现象 关键检查点 解决方案
The InputMap action “down” doesn’t exist. Did you mean “ui_down”? 检查输入映射是否存在left,right,up,down动作 项目设置→输入映射→添加left,right,up,down并绑定键盘左、右键
画面太小 检查项目设置->常规->显示->拉伸->缩放 调整缩放大小
角色像素纹理不清晰 检查项目设置->渲染->纹理->画布纹理->默认纹理过滤 在默认纹理过滤设置为Nearest
Invalid assignment of property or key ‘stack’ with value of type ‘int’ on a base object of type ‘Nil’. egg.tscn场景或者是slot_ui.tscn场景未加载egg_inventory_item.tres或inventory_item.tres文件 打开场景在检查器中加载对应文件
库存面板在左上角 检查inventory_ui.tscn场景中的PanelContainer是否预设未居中 选中inventory_ui.tscn场景中的PanelContainer节点,在检查器或者是2D区预设该节点为居中

(欢迎评论区讨论!)

五、免费开源资产包

某开源网站精灵图资源包链接: 点击此处

  1. 进入链接后点击下图按钮
    下载

  2. 然后点击【No thanks,just take me to the downloads】(不了谢谢,只想下载)
    No thanks,just take me to the downloads

  3. 最后点击下图按钮完成下载(注意导入前需解压缩)
    下载