CGJOY_084666854 发表于 2025-7-30 07:55

分享一波自己写的背包脚本godot4

extends Node
var utils = load("res://script/utils/index.gd").new()
@onready var items_library_img = load("res://static/items.png")

# 临时物品节点(拖拽时显示)
var dragged_canvas_layer
var dragged_item
# 丢弃提示标签
var drop_label: Label
# 记录拖拽开始位置
var drag_start_position: Vector2
# 最小拖拽距离(超过这个距离才会触发丢弃)
var min_drag_distance: float = 60
# 是否满足丢弃距离条件
var can_drop: bool = false
# 拖拽层级(确保在背包之上)
var drag_layer: int = 10


func _ready():
        print("初始化背包系统")

func register_inverntory_handle():
        var grid_container = self.find_child("GridContainer")
        print("grid_container", self, grid_container)
        if grid_container:
                for _index in grid_container.get_children().size():
                        var patent_node = grid_container.get_child(_index)
                        if utils.has_node_child_by_type(patent_node, "TextureRect"):
                                var _node = utils.get_node_child_by_type(patent_node, "TextureRect")
                                _node.connect("gui_input", Callable(self, "_on_inverntory_drop").bind(_node, _index))
                        #_node.connect("pressed", Callable(self, "_on_inverntory_click"), [], CONNECT_DEFERRED)


func clear_inverntory_handle():
        var grid_container = self.find_child("GridContainer")
        if grid_container:
                for _index in grid_container.get_children().size():
                        var patent_node = grid_container.get_child(_index)
                        if utils.has_node_child_by_type(patent_node, "TextureRect"):
                                var _node = utils.get_node_child_by_type(patent_node, "TextureRect")
                                _node.disconnect("gui_input", Callable(self, "_on_inverntory_drop").bind(_node, _index))


# 拖拽包中的物品
func _on_inverntory_drop(event: InputEvent, node:TextureRect, index:int):
        var dragged_item_pos = Global.PLAYER.get_local_mouse_position()+ Vector2(Global.PLAYER.get_viewport().size / 2)
        if event is InputEventMouseButton && event.pressed && event.button_index == MOUSE_BUTTON_LEFT:
                drag_start_position = dragged_item_pos
                if dragged_canvas_layer:
                        dragged_canvas_layer.queue_free()
                        dragged_canvas_layer = null
               
                # 1. 开始拖拽:创建临时物品
                dragged_item = Sprite2D.new()
                dragged_item.texture = node.texture# 设置物品图标
                dragged_item.position = dragged_item_pos
                dragged_item.modulate = Color(1, 1, 1, 0.8)

                # 创建丢弃提示标签
                drop_label = Label.new()
                drop_label.text = "丢弃"
                drop_label.add_theme_color_override("font_color", Color(1, 0, 0))# 红色文字
                drop_label.visible = false# 初始隐藏

                # 添加到玩家场景
               
                dragged_canvas_layer = CanvasLayer.new()
               
                dragged_canvas_layer.add_child(dragged_item)
                dragged_canvas_layer.add_child(drop_label)
               
               
                Global.PLAYER.add_child(dragged_canvas_layer)
               
                dragged_item.z_index = drag_layer
                drop_label.z_index = drag_layer + 1# 标签层级高于物品
               
                can_drop = false
#
        elif event is InputEventMouseMotion && dragged_item:
                ## 2. 拖拽中:更新临时物品位置
                var mouse_pos = dragged_item_pos
                dragged_item.position = mouse_pos
               
                # 标签显示在物品右下方
                drop_label.position = mouse_pos + Vector2(20, 10)
               
                # 检测是否丢弃
                var current_distance = drag_start_position.distance_to(mouse_pos)
                var grid_container = self.find_child("GridContainer")
                # 检测是否移出背包
                if current_distance >= min_drag_distance and grid_container.get_global_rect().has_point(mouse_pos) == false:
                        if !can_drop:
                                can_drop = true
                                dragged_item.modulate = Color(1, 1, 1, 1)# 恢复不透明度
                                drop_label.visible = true# 显示丢弃文字
                else:
                        if can_drop:
                                can_drop = false
                                dragged_item.modulate = Color(1, 1, 1, 0.9)# 降低不透明度
                                drop_label.visible = false# 隐藏丢弃文字

        elif event is InputEventMouseButton && !event.pressed && event.button_index == MOUSE_BUTTON_LEFT && dragged_item:
                # 检测是否为交换物品的格子
                #
                if inverntory_get_slot_at_mouse():
                        inverntory_swap_items(index, self.find_child("GridContainer").get_children().find(inverntory_get_slot_at_mouse()))
               
                # 检测是否丢弃
                var current_distance = drag_start_position.distance_to(dragged_item_pos)
                print("current_distance", current_distance)
                # 触发点击
                if current_distance <= 10:
                        _on_inverntory_click(node)
               
                ## 3. 松开鼠标:丢弃物品
                if can_drop:
                        drop_item(node)
                # 清理临时节点
                dragged_canvas_layer.queue_free()
                dragged_item = null
                drop_label = null
                dragged_canvas_layer = null
               

# 把物品加入背包中
func push_inverntory(data, callback):
        var is_inverntory_max = true
        var toast_node = preload("res://script/utils/toast.gd").new()# 替换为实际节点路径
       
        var grid_container = self.find_child("GridContainer")
        for _rect in grid_container.get_children():
                var _node = TextureRect.new()
                if utils.has_node_child_by_type(_rect, "TextureRect"):
                        pass
                else:
                        var _atlas_texture = AtlasTexture.new()
                        _atlas_texture.atlas = items_library_img
                        _atlas_texture.region = data.icon_rect
                        _node.texture = _atlas_texture
                        _node.set_meta("data", data)
                        is_inverntory_max = false
                        callback.call()
                        _rect.add_child(_node)
                        break
        if is_inverntory_max:
                toast_node.show_message(self, "背包已满")
        self.clear_inverntory_handle()
        self.register_inverntory_handle()

# 交换背包
func inverntory_swap_items(start_index, end_index):
        if start_index == end_index:
                return
        var grid = self.find_child("GridContainer")
        # 交换网格中的节点
        var item1 = grid.get_child(start_index)
        var item2 = grid.get_child(end_index)
        grid.move_child(item2, start_index)
        grid.move_child(item1, end_index)
        clear_inverntory_handle()
        self.register_inverntory_handle()
# 丢弃背包的品
func drop_item(node):
        var item = preload("res://script/items/item.tscn").instantiate()
        var game = get_node("/root/game")
        game.add_child(item)
       
        item.setTexture(node.texture)
        item.setPosition(Global.PLAYER.position)
        item.set_meta("data", node.get_meta("data"))
        node.queue_free()

# 点击包中的物品
func _on_inverntory_click(node):
        Global.PLAYER.equipment_node.equip(node)


# 检测行为是否为交换背包中的物品并且得到该格子
func inverntory_get_slot_at_mouse():
        # 获取鼠标下的物品槽
        var grid_container = self.find_child("GridContainer")
        var mouse_pos = Global.PLAYER.get_local_mouse_position()+ Vector2(get_viewport().size / 2)
        for slot in grid_container.get_children():
                if slot.get_global_rect().has_point(mouse_pos):
                        return slot
        return null

路…一直都在 发表于 2025-7-30 09:11

这个是不是打包成文件比较好,Godot 的资源不多,感谢分享啊
页: [1]
查看完整版本: 分享一波自己写的背包脚本godot4