-
What do you want to achieve?
i tried to make cell based inventory system -
What is the issue?
when i try to move inventory item it dissappears if there’s no other item like AK beside it from right or left
InventoryLocal script
-- PlayerGui -> InventoryGui -> InventoryLocalScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UserInputService = game:GetService("UserInputService")
local UpdateInventoryEvent = ReplicatedStorage:WaitForChild("Remotes"):WaitForChild("UpdateInventory")
local MoveItemEvent = ReplicatedStorage:WaitForChild("Remotes"):WaitForChild("MoveItem")
local ItemDatabase = require(ReplicatedStorage:WaitForChild("ItemDatabase"))
local ScrollingFrame = script.Parent:WaitForChild("InventoryScrollingFrame")
local Template = ScrollingFrame:WaitForChild("Template")
Template.Visible = false
local CELL_SIZE = 50
local INVENTORY_ROWS = 12
local INVENTORY_COLS = 7
local draggingNode = nil
local dragItemKey = nil
local startRow, startCol = nil, nil
local dragOffset = Vector2.new(0, 0)
local function renderInventory(grid)
for _, child in ipairs(ScrollingFrame:GetChildren()) do
if child:IsA("ImageButton") and child ~= Template then
child:Destroy()
end
end
for r = 1, INVENTORY_ROWS do
if grid[r] then
for c = 1, INVENTORY_COLS do
local cellData = grid[r][c]
if cellData and cellData.isHead then
local itemKey = cellData.itemKey
local itemData = ItemDatabase[itemKey]
if itemData then
local itemClone = Template:Clone()
itemClone.Name = itemKey
itemClone.Image = itemData.Image
itemClone.Visible = true
itemClone.Position = UDim2.new(0, (c - 1) * CELL_SIZE, 0, (r - 1) * CELL_SIZE)
itemClone.Size = UDim2.new(0, itemData.Width * CELL_SIZE, 0, itemData.Height * CELL_SIZE)
itemClone.Parent = ScrollingFrame
itemClone.MouseButton1Down:Connect(function()
if draggingNode then return end
draggingNode = itemClone
dragItemKey = itemKey
startRow = r
startCol = c
local mousePos = UserInputService:GetMouseLocation()
dragOffset = Vector2.new(
mousePos.X - itemClone.AbsolutePosition.X,
mousePos.Y - itemClone.AbsolutePosition.Y
)
itemClone.ImageTransparency = 0.5
itemClone.ZIndex = 10
end)
end
end
end
end
end
end
UserInputService.InputChanged:Connect(function(input)
if draggingNode and input.UserInputType == Enum.UserInputType.MouseMovement then
local framePos = ScrollingFrame.AbsolutePosition
local mousePos = UserInputService:GetMouseLocation()
local relativeX = mousePos.X - framePos.X - dragOffset.X
local relativeY = mousePos.Y - framePos.Y - dragOffset.Y + ScrollingFrame.CanvasPosition.Y
draggingNode.Position = UDim2.new(0, relativeX, 0, relativeY)
end
end)
UserInputService.InputEnded:Connect(function(input)
if draggingNode and input.UserInputType == Enum.UserInputType.MouseButton1 then
local framePos = ScrollingFrame.AbsolutePosition
local mousePos = UserInputService:GetMouseLocation()
local relativeX = mousePos.X - framePos.X - dragOffset.X
local relativeY = mousePos.Y - framePos.Y - dragOffset.Y + ScrollingFrame.CanvasPosition.Y
local calculatedCol = math.round(relativeX / CELL_SIZE) + 1
local calculatedRow = math.round(relativeY / CELL_SIZE) + 1
local targetCol = math.clamp(calculatedCol, 1, INVENTORY_COLS)
local targetRow = math.clamp(calculatedRow, 1, INVENTORY_ROWS)
local nodeRef = draggingNode
local savedStartRow = startRow
local savedStartCol = startCol
draggingNode = nil
-- Instant visual return (in case of a ping)
nodeRef.Position = UDim2.new(0, (savedStartCol - 1) * CELL_SIZE, 0, (savedStartRow - 1) * CELL_SIZE)
nodeRef.ImageTransparency = 0
nodeRef.ZIndex = 1
MoveItemEvent:FireServer(savedStartRow, savedStartCol, targetRow, targetCol)
end
end)
UpdateInventoryEvent.OnClientEvent:Connect(renderInventory)
InventoryServer script
-- ServerScriptService -> InventoryServer
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ItemDatabase = require(ReplicatedStorage:WaitForChild("ItemDatabase"))
local MoveItemEvent = ReplicatedStorage:WaitForChild("Remotes"):WaitForChild("MoveItem")
local INVENTORY_ROWS = 12
local INVENTORY_COLS = 7
local PlayerInventories = {}
local function createEmptyGrid()
local grid = {}
for r = 1, INVENTORY_ROWS do
grid[r] = {}
for c = 1, INVENTORY_COLS do
grid[r][c] = nil
end
end
return grid
end
local function canPlaceItemIgnore(grid, itemKey, startRow, startCol, ignoreRow, ignoreCol)
local itemData = ItemDatabase[itemKey]
local w, h = itemData.Width, itemData.Height
-- 1. Geometric check of grid boundaries
if startRow < 1 or startRow + h - 1 > INVENTORY_ROWS then return false end
if startCol < 1 or startCol + w - 1 > INVENTORY_COLS then return false end
-- 2. Checking each cell for occupancy
for r = startRow, startRow + h - 1 do
for c = startCol, startCol + w - 1 do
local cell = grid[r][c]
-- If the cell is not empty, we check if it belongs to the same item
if cell ~= nil then
local isMyOwnTail = (cell.rootRow == ignoreRow and cell.rootCol == ignoreCol)
if not isMyOwnTail then
return false -- There is a FOREIGN object here that cannot be placed
end
end
end
end
return true
end
-- Cleaning an item from the grid
local function removeItemFromGrid(grid, rootRow, rootCol)
local cellData = grid[rootRow][rootCol]
if not cellData then return end
local itemData = ItemDatabase[cellData.itemKey]
for r = rootRow, rootRow + itemData.Height - 1 do
for c = rootCol, rootCol + itemData.Width - 1 do
grid[r][c] = nil
end
end
end
-- Writing an object to coordinates
local function forcePlaceItem(grid, itemKey, startRow, startCol)
local itemData = ItemDatabase[itemKey]
for r = startRow, startRow + itemData.Height - 1 do
for c = startCol, startCol + itemData.Width - 1 do
grid[r][c] = { itemKey = itemKey, isHead = false, rootRow = startRow, rootCol = startCol }
end
end
grid[startRow][startCol] = { itemKey = itemKey, isHead = true, rootRow = startRow, rootCol = startCol }
end
-- Auto-add function to start
local function addItemToInventory(grid, itemKey)
for r = 1, INVENTORY_ROWS do
for c = 1, INVENTORY_COLS do
if canPlaceItemIgnore(grid, itemKey, r, c, 0, 0) then
forcePlaceItem(grid, itemKey, r, c)
return true
end
end
end
return false
end
-- Movement processing
MoveItemEvent.OnServerEvent:Connect(function(player, fromRow, fromCol, toRow, toCol)
local grid = PlayerInventories[player.UserId]
if not grid then return end
-- SERVER PROTECTIVE BARRIER: checking the validity of the sent indexes
if toRow < 1 or toRow > INVENTORY_ROWS or toCol < 1 or toCol > INVENTORY_COLS then
warn("Сервер отклонил пакет: Координаты вне инвентаря! [", toRow, ",", toCol, "]")
ReplicatedStorage.Remotes.UpdateInventory:FireClient(player, grid)
return
end
local cellData = grid[fromRow][fromCol]
if not cellData or not cellData.isHead then
ReplicatedStorage.Remotes.UpdateInventory:FireClient(player, grid)
return
end
local itemKey = cellData.itemKey
print("--- TRANSFER REQUEST ---")
print("Item:", itemKey)
print("From Cell: [Row:", fromRow, ", Col:", fromCol, "]")
print("To Cell: [Row:", toRow, ", Col:", toCol, "]")
if canPlaceItemIgnore(grid, itemKey, toRow, toCol, fromRow, fromCol) then
print("Result: Moved successfully!")
removeItemFromGrid(grid, fromRow, fromCol)
forcePlaceItem(grid, itemKey, toRow, toCol)
else
print("Result: Denied, cell is busy!")
end
ReplicatedStorage.Remotes.UpdateInventory:FireClient(player, grid)
end)
Players.PlayerAdded:Connect(function(player)
local grid = createEmptyGrid()
PlayerInventories[player.UserId] = grid
addItemToInventory(grid, "AK74")
addItemToInventory(grid, "Medkit")
addItemToInventory(grid, "Bottle")
addItemToInventory(grid, "Ammo_545")
addItemToInventory(grid, "Medkit")
addItemToInventory(grid, "AK74")
ReplicatedStorage.Remotes.UpdateInventory:FireClient(player, grid)
end)
Players.PlayerRemoving:Connect(function(player)
PlayerInventories[player.UserId] = nil
end)
Module script
-- ReplicatedStorage -> ItemDatabase (ModuleScript)
local ItemDatabase = {
["Medkit"] = { Name = "Medkit", Width = 1, Height = 1, Image = "rbxassetid://10318739285" },
["Bottle"] = { Name = "Water", Width = 1, Height = 1, Image = "rbxassetid://136821935409252" },
["AK74"] = { Name = "AK-74m", Width = 5, Height = 2, Image = "rbxassetid://10456861522" },
["Ammo_545"] = { Name = "5.45x39 ammo", Width = 1, Height = 1, Image = "rbxassetid://99027744712862" }
}
return ItemDatabase