Roblox背包与Hotbar物品移动脚本单向失效问题求助
Roblox库存系统双向移动功能故障修复
问题描述
开发Roblox库存系统,目标实现物品在快捷栏(Hotbar)与背包之间的双向移动。初始运行脚本正常,但执行一次移动操作后,另一项操作便无法生效,问题集中在脚本末尾的两个移动逻辑循环中。
原代码
game.StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, false) local replicatedStorage = game.ReplicatedStorage local userInputService local toolFolder = replicatedStorage.ToolFolder local images = replicatedStorage.Images local uis = game:GetService("UserInputService") local player = game.Players.LocalPlayer local playergui = player.PlayerGui local inventory = playergui:WaitForChild("Inventory") local hotbar = inventory.Hotbar local inventoryFrame = inventory.Inventory local itemFrame = inventoryFrame.ScrollingFrame local hotbarTable = {} local inventoryTable = {} local insertedItems = {} local keyConversions = { [Enum.KeyCode.One] = 1, [Enum.KeyCode.Two] = 2, [Enum.KeyCode.Three] = 3, [Enum.KeyCode.Four] = 4, [Enum.KeyCode.Five] = 5, [Enum.KeyCode.Six] = 6, [Enum.KeyCode.Seven] = 7, [Enum.KeyCode.Eight] = 8, [Enum.KeyCode.Nine] = 9, [Enum.KeyCode.Zero] = 10, } local function pickSlot() for i, v in pairs(hotbarTable) do if v.Item == "None" then return i end end end local function addItem(item) local slot = pickSlot() if slot ~= nil then hotbarTable[slot].Item = item hotbarTable[slot].Count = 1 hotbarTable[slot].Image = images[item].Texture table.insert(insertedItems, item) elseif slot == nil then inventoryTable[item] = { Count = 1; Image = images[item].Texture } end end local function fillInventoryTables() for i = 1, 10 do hotbarTable[i] = { Item = "None"; Count = 0; Image = "None" } end for i, v in pairs(toolFolder:GetChildren()) do if #insertedItems > 0 then if table.find(insertedItems, v.Name) then for x, c in pairs(hotbarTable) do if c.Item == v.Name then c.Count += 1 end end else addItem(v.Name) end else addItem(v.Name) end end end local function display() for i, v in pairs(hotbarTable) do hotbar[i].Image = v.Image hotbar[i].Counter.Text = v.Count end for i, v in pairs(inventoryTable) do local clone = inventoryFrame.ScrollingFrame.Sample:Clone() clone.Visible = true clone.Name = tostring(i) clone.Parent = inventoryFrame.ScrollingFrame clone.Image = v.Image clone.Counter.Text = v.Count end end local function Equip(key) local tool = hotbarTable[key].Item if player.Character:FindFirstChildOfClass("Tool") then if player.Character:FindFirstChildOfClass("Tool").Name == tool then player.Character:FindFirstChild("Humanoid"):UnequipTools() player.Backpack[tool]:Destroy() elseif player.Character:FindFirstChildOfClass("Tool").Name ~= tool then player.Character:FindFirstChild("Humanoid"):UnequipTools() player.Backpack:GetChildren()[1]:Destroy() toolFolder[tool]:Clone().Parent = player.Backpack player.Character:FindFirstChild("Humanoid"):EquipTool(player.Backpack:GetChildren()[1]) end elseif not player.Character:FindFirstChild(tool) then toolFolder[tool]:Clone().Parent = player.Backpack player.Character:FindFirstChild("Humanoid"):EquipTool(player.Backpack:GetChildren()[1]) end end local function removeInventoryFrames() for i, v in pairs(inventoryFrame.ScrollingFrame:GetChildren()) do if v.ClassName == "ImageButton" and v.Name ~= "Sample" then v:Destroy() end end end fillInventoryTables() hotbarTable[1].Item = "None" hotbarTable[1].Count = 0 hotbarTable[1].Image = "None" display() uis.InputBegan:Connect(function(key) if key.UserInputType == Enum.UserInputType.Keyboard then Equip(keyConversions[key.KeyCode]) end end) -- Moving items from backpack to hotbar for i, v in ipairs(inventoryFrame.ScrollingFrame:GetChildren()) do if v.ClassName == "ImageButton" then v.MouseButton1Click:Connect(function() print(1) for x, c in pairs(hotbarTable) do if c.Item == "None" then c.Item = v c.Count = v.Counter.Text c.Image = v.Image inventoryTable[v.Name] = nil removeInventoryFrames() display() end end end) end end -- Moving items from hotbar to backpack for i, v in ipairs(hotbar:GetChildren()) do if v.ClassName == "ImageButton" then v.MouseButton1Click:Connect(function() inventoryTable[v.Name] = { Count = hotbarTable[tonumber(v.Name)].Count; Image = hotbarTable[tonumber(v.Name)].Image } hotbarTable[tonumber(v.Name)].Item = "None" hotbarTable[tonumber(v.Name)].Count = 0 hotbarTable[tonumber(v.Name)].Image = "None" print(v.Name) removeInventoryFrames() display() end) end print(hotbarTable) end
问题分析
- 背包到快捷栏的事件绑定仅初始化一次:原代码中第一个for循环仅在脚本启动时遍历滚动框内的控件并绑定点击事件,后续调用
display()生成的新背包物品控件没有绑定事件,导致点击无响应。 - 快捷栏数据存储错误:背包到快捷栏的逻辑中,
c.Item = v将控件实例存入了hotbarTable,而非物品名称,后续判断c.Item == "None"会失效,因为存储的是Instance对象而非字符串。 - 循环逻辑冗余:寻找空快捷栏时未在找到后终止循环,可能导致多个槽位被修改。
修复后的代码
game.StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, false) local replicatedStorage = game.ReplicatedStorage local toolFolder = replicatedStorage.ToolFolder local images = replicatedStorage.Images local uis = game:GetService("UserInputService") local player = game.Players.LocalPlayer local playergui = player.PlayerGui local inventory = playergui:WaitForChild("Inventory") local hotbar = inventory.Hotbar local inventoryFrame = inventory.Inventory local itemFrame = inventoryFrame.ScrollingFrame local hotbarTable = {} local inventoryTable = {} local insertedItems = {} local keyConversions = { [Enum.KeyCode.One] = 1, [Enum.KeyCode.Two] = 2, [Enum.KeyCode.Three] = 3, [Enum.KeyCode.Four] = 4, [Enum.KeyCode.Five] = 5, [Enum.KeyCode.Six] = 6, [Enum.KeyCode.Seven] = 7, [Enum.KeyCode.Eight] = 8, [Enum.KeyCode.Nine] = 9, [Enum.KeyCode.Zero] = 10, } local function pickSlot() for i, v in pairs(hotbarTable) do if v.Item == "None" then return i end end end local function addItem(item) local slot = pickSlot() if slot ~= nil then hotbarTable[slot].Item = item hotbarTable[slot].Count = 1 hotbarTable[slot].Image = images[item].Texture table.insert(insertedItems, item) elseif slot == nil then inventoryTable[item] = { Count = 1; Image = images[item].Texture } end end local function fillInventoryTables() for i = 1, 10 do hotbarTable[i] = { Item = "None"; Count = 0; Image = "None" } end for i, v in pairs(toolFolder:GetChildren()) do if #insertedItems > 0 then if table.find(insertedItems, v.Name) then for x, c in pairs(hotbarTable) do if c.Item == v.Name then c.Count += 1 end end else addItem(v.Name) end else addItem(v.Name) end end end -- 新增:绑定背包物品点击事件的函数 local function bindInventoryItemEvents() for i, v in ipairs(inventoryFrame.ScrollingFrame:GetChildren()) do if v.ClassName == "ImageButton" and v.Name ~= "Sample" then -- 先清除已有事件,避免重复绑定 v.MouseButton1Click:DisconnectAll() v.MouseButton1Click:Connect(function() local emptySlot = pickSlot() if emptySlot then -- 存储物品名称而非控件 hotbarTable[emptySlot].Item = v.Name hotbarTable[emptySlot].Count = tonumber(v.Counter.Text) hotbarTable[emptySlot].Image = v.Image inventoryTable[v.Name] = nil removeInventoryFrames() display() end end) end end end local function display() -- 更新快捷栏显示 for i, v in pairs(hotbarTable) do hotbar[i].Image = v.Image hotbar[i].Counter.Text = v.Count end -- 生成背包物品控件 for i, v in pairs(inventoryTable) do local clone = inventoryFrame.ScrollingFrame.Sample:Clone() clone.Visible = true clone.Name = tostring(i) clone.Parent = inventoryFrame.ScrollingFrame clone.Image = v.Image clone.Counter.Text = v.Count end -- 生成控件后立即绑定事件 bindInventoryItemEvents() end local function Equip(key) local tool = hotbarTable[key].Item if tool == "None" then return end -- 空槽位不执行操作 if player.Character:FindFirstChildOfClass("Tool") then local equippedTool = player.Character:FindFirstChildOfClass("Tool") if equippedTool.Name == tool then player.Character.Humanoid:UnequipTools() player.Backpack[tool]:Destroy() else player.Character.Humanoid:UnequipTools() player.Backpack[equippedTool.Name]:Destroy() toolFolder[tool]:Clone().Parent = player.Backpack player.Character.Humanoid:EquipTool(player.Backpack[tool]) end else toolFolder[tool]:Clone().Parent = player.Backpack player.Character.Humanoid:EquipTool(player.Backpack[tool]) end end local function removeInventoryFrames() for i, v in pairs(inventoryFrame.ScrollingFrame:GetChildren()) do if v.ClassName == "ImageButton" and v.Name ~= "Sample" then v:Destroy() end end end fillInventoryTables() hotbarTable[1].Item = "None" hotbarTable[1].Count = 0 hotbarTable[1].Image = "None" display() uis.InputBegan:Connect(function(key) if key.UserInputType == Enum.UserInputType.Keyboard then Equip(keyConversions[key.KeyCode]) end end) -- 绑定快捷栏到背包的事件(仅需初始化一次,因为快捷栏控件不会被销毁) for i, v in ipairs(hotbar:GetChildren()) do if v.ClassName == "ImageButton" then v.MouseButton1Click:Connect(function() local slotNum = tonumber(v.Name) local itemData = hotbarTable[slotNum] if itemData.Item ~= "None" then inventoryTable[itemData.Item] = { Count = itemData.Count; Image = itemData.Image } hotbarTable[slotNum].Item = "None" hotbarTable[slotNum].Count = 0 hotbarTable[slotNum].Image = "None" removeInventoryFrames() display() end end) end end
修复要点说明
- 新增
bindInventoryItemEvents函数:每次调用display()生成新背包控件后,自动绑定点击事件,确保新生成的物品也能响应移动操作。 - 修正数据存储逻辑:背包到快捷栏时,将物品名称存入
hotbarTable而非控件实例,保证后续空槽位判断正常。 - 优化空槽位查找:直接调用
pickSlot()获取第一个空槽位,找到后终止逻辑,避免重复修改。 - 完善Equip函数:增加空槽位判断,避免无效操作;直接通过物品名称查找背包工具,替代
GetChildren()[1]的不稳定写法。
内容的提问来源于stack exchange,提问作者TrulyBlue2
相关产品推荐
相关产品推荐

