Found a grid inventory script, want to make the grid smaller

So I found this pretty old post which explains how to make a grid inventory system.

Link to the post

Screenshot

I want to modify the grid to a 5x5 and move it to the right but I cannot, for the life of me, figure out how to do so.

Sort of like this:
image

Here’s my script:

-- Services and global variables setup
-- Get essential Roblox services for accessing replicated storage and user input.
local replicatedStorage = game:GetService("ReplicatedStorage");
local userInputService = game:GetService("UserInputService");

-- References to game assets and the inventory system stored in ReplicatedStorage.
local assets = replicatedStorage:WaitForChild("Assets");
local itemInv = replicatedStorage:WaitForChild("Inventory");

-- References to the main inventory UI components.
local invMain = script.Parent
local invGrid = invMain:WaitForChild("InvGrid");

-- Constants for grid part size and the total number of parts, plus variables for drag-and-drop.
local gridPartSize = 70; -- Change grid part size here.
local gridPartAmount = 98; -- Change amount of grid parts here.
local currentlyDraggingItem = nil;
local currentlyDraggingItemFrame = nil;
local currentlyDraggingMouseOffset = Vector2.new(0, 0);

-- Determine which grid part is beneath the item being dropped.
local function getGridPartFromDropPos(dropPosX, dropPosY)
	-- This function calculates the grid part's ID based on the drop position.
	local gridPartPosYSum = (dropPosY - 1) * invGrid.UIGridLayout.AbsoluteCellCount.X;
	local gridPart = invGrid:FindFirstChild(dropPosX + gridPartPosYSum);

	return gridPart;
end

-- Calculate the appropriate drop position based on the current mouse position and item size.
local function getDropPos(posX, posY, sizeX, sizeY)
	-- Converts mouse position to grid coordinates, clamping within the grid's bounds.
	local dropPosX = math.floor(posX / gridPartSize + 1.5);
	local dropPosY = math.floor(posY / gridPartSize + 1.5);

	local dropPosXClamp = math.clamp(dropPosX, 1, invGrid.UIGridLayout.AbsoluteCellCount.X - sizeX + 1);
	local dropPosYClamp = math.clamp(dropPosY, 1, invGrid.UIGridLayout.AbsoluteCellCount.Y - sizeY + 1);

	return dropPosXClamp, dropPosYClamp;
end

-- Get positions currently occupied by items in the inventory, excluding a specified item.
local function getOccupiedPositions(inventory, ignoredItem)
	-- Creates a list of positions occupied by items, useful for collision detection.
	local occupiedPositions = {};
	for _, item in pairs(inventory:GetChildren()) do
		if not (item == ignoredItem) then
			for sizeOffsetX = 0, item.InvSizeX.Value - 1 do
				for sizeOffsetY = 0, item.InvSizeY.Value - 1 do
					table.insert(occupiedPositions, Vector2.new(item.InvPosX.Value + sizeOffsetX, item.InvPosY.Value + sizeOffsetY));
				end
			end
		end
	end
	
	return occupiedPositions;
end

-- Check if placing an item at a given position will collide with existing items.
local function isColliding(colliderItem, posX, posY)
	-- Uses the occupied positions to determine if the new position is already taken.
	local occupiedPositions = getOccupiedPositions(itemInv, colliderItem);

	for sizeOffsetX = 0, colliderItem.InvSizeX.Value - 1 do
		for sizeOffsetY = 0, colliderItem.InvSizeY.Value - 1 do
			if (table.find(occupiedPositions, Vector2.new(posX + sizeOffsetX, posY + sizeOffsetY))) then
				return true;
			end
		end
	end

	return false;
end

-- Find the next available position in the grid that can accommodate the item's size.
local function getNextEmptyDropPos(item)
	-- Searches the grid systematically for an empty spot that fits the item.
	for y = 1, invGrid.UIGridLayout.AbsoluteCellCount.Y do
		for x = 1, invGrid.UIGridLayout.AbsoluteCellCount.X do
			if not (x >= invGrid.UIGridLayout.AbsoluteCellCount.X + 1) then
				x = math.clamp(x, 1, invGrid.UIGridLayout.AbsoluteCellCount.X - item.InvSizeX.Value + 1);
			end

			if not (y >= invGrid.UIGridLayout.AbsoluteCellCount.Y + 1) then
				y = math.clamp(y, 1, invGrid.UIGridLayout.AbsoluteCellCount.Y - item.InvSizeY.Value + 1);
			end

			local colliding = isColliding(item, x, y);
			if not (colliding) then
				return true, x, y;
			end
		end
	end

	return false, nil, nil;
end

-- Sorts items by their size and attempts to place them in the inventory grid efficiently.
local function sortItems(items)
	-- A basic sorting algorithm that organizes items to minimize gaps in the inventory.
	table.sort(items, function(a, b) return a.InvSizeX.Value * a.InvSizeY.Value > b.InvSizeX.Value * b.InvSizeY.Value end);

	for _, item in pairs(items) do
		local success, invPosX, invPosY = getNextEmptyDropPos(item);
		if (success) then
			item.InvPosX.Value = invPosX;
			item.InvPosY.Value = invPosY;
		end
	end
end

-- Event listener for when the user is dragging an item.
userInputService.InputChanged:Connect(function(input, gameProcessed)
	-- Manages the visual feedback of dragging an item across the inventory grid.
	if (currentlyDraggingItemFrame) and (input.UserInputType == Enum.UserInputType.MouseMovement) then
		local mousePos = input.Position;
		currentlyDraggingItemFrame.Position = UDim2.new(0, mousePos.X - currentlyDraggingMouseOffset.X, 0, mousePos.Y - currentlyDraggingMouseOffset.Y);

		for _, gridPart in pairs(invGrid:GetChildren()) do
			if not (gridPart:IsA("UIGridLayout")) then
				gridPart.Cosmetic.BackgroundColor3 = Color3.fromRGB(20, 20, 20);
			end
		end

		local dropPosX, dropPosY = getDropPos(currentlyDraggingItemFrame.Position.X.Offset, currentlyDraggingItemFrame.Position.Y.Offset, currentlyDraggingItem.InvSizeX.Value, currentlyDraggingItem.InvSizeY.Value);
		local colliding = isColliding(currentlyDraggingItem, dropPosX, dropPosY);
		for sizeOffsetX = 0, currentlyDraggingItem.InvSizeX.Value - 1 do
			for sizeOffsetY = 0, currentlyDraggingItem.InvSizeY.Value - 1 do
				local gridPart = getGridPartFromDropPos(dropPosX + sizeOffsetX, dropPosY + sizeOffsetY);
				if (gridPart) then
					if (colliding) then
						gridPart.Cosmetic.BackgroundColor3 = Color3.new(1, 0.15, 0.15);
					else
						gridPart.Cosmetic.BackgroundColor3 = Color3.new(0.85, 0.85, 0.85);
					end
				end
			end
		end
	end
end);

-- Event listener for when the user releases the mouse button to drop an item.
userInputService.InputEnded:Connect(function(input)
	-- Finalizes the position of the dragged item based on where it's dropped.
	if (currentlyDraggingItemFrame) and (input.UserInputType == Enum.UserInputType.MouseButton1) then
		local dropPosX, dropPosY = getDropPos(currentlyDraggingItemFrame.Position.X.Offset, currentlyDraggingItemFrame.Position.Y.Offset, currentlyDraggingItem.InvSizeX.Value, currentlyDraggingItem.InvSizeY.Value);
		local colliding = isColliding(currentlyDraggingItem, dropPosX, dropPosY);
		if not (colliding) then
			currentlyDraggingItemFrame.Position = UDim2.new(0, dropPosX * 70 - 70, 0, dropPosY * 70 - 70);

			currentlyDraggingItem.InvPosX.Value = dropPosX;
			currentlyDraggingItem.InvPosY.Value = dropPosY;
		else
			currentlyDraggingItemFrame.Position = UDim2.new(0, currentlyDraggingItem.InvPosX.Value * 70 - 70, 0, currentlyDraggingItem.InvPosY.Value * 70 - 70);
		end

		currentlyDraggingItemFrame.ZIndex = 2;
		currentlyDraggingItemFrame.ItemImg.ZIndex = 3;
		currentlyDraggingItemFrame.Button.ZIndex = 3;

		currentlyDraggingItem = nil;
		currentlyDraggingItemFrame = nil;

		for _, gridPart in pairs(invGrid:GetChildren()) do
			if not (gridPart:IsA("UIGridLayout")) then
				gridPart.Cosmetic.BackgroundColor3 = Color3.fromRGB(20, 20, 20);
			end
		end
	end
end);

-- Initializes and populates the inventory UI with items.
local function loadInventoryItems()
	-- Clones item frames from a template, adjusting their position based on inventory data.
	for _, item in pairs(itemInv:GetChildren()) do
		item.InvPosX.Value = -10000;
		item.InvPosY.Value = -10000;
	end
	
	sortItems(itemInv:GetChildren());

	for _, item in pairs(itemInv:GetChildren()) do
		local itemFrame = assets.UI.InvItem:Clone();
		itemFrame.ItemImg.Image = item.Image.Value
		itemFrame.Size = UDim2.new(0, item.InvSizeX.Value * gridPartSize, 0, item.InvSizeY.Value * gridPartSize);
		itemFrame.Position = UDim2.new(0, item.InvPosX.Value * 70 - 70, 0, item.InvPosY.Value * 70 - 70);

		itemFrame.Button.MouseButton1Down:Connect(function()
			currentlyDraggingItemFrame = itemFrame;
			currentlyDraggingItem = item;

			currentlyDraggingItemFrame.ZIndex = 4;
			currentlyDraggingItemFrame.ItemImg.ZIndex = 5;
			currentlyDraggingItemFrame.Button.ZIndex = 5;

			local mousePos = userInputService:GetMouseLocation() - Vector2.new(0, 36);
			local itemPosOffset = Vector2.new(mousePos.X - currentlyDraggingItemFrame.Position.X.Offset, mousePos.Y - currentlyDraggingItemFrame.Position.Y.Offset);
			currentlyDraggingMouseOffset = itemPosOffset;
		end);

		itemFrame.Parent = invMain;
	end
end

-- Initializes the grid layout for the inventory UI.
local function loadInventoryGrid()
	-- Dynamically creates the grid parts based on specified size and amount.
	for gridPartNum = 1, gridPartAmount do
		local gridPartFrame = assets.UI.InvGridPart:Clone();
		gridPartFrame.Size = UDim2.new(0, gridPartSize, 0, gridPartSize);
		gridPartFrame.LayoutOrder = gridPartNum;
		gridPartFrame.Name = gridPartNum;
		gridPartFrame.Parent = invGrid;
	end

	invMain.Size = UDim2.new(0, invGrid.UIGridLayout.AbsoluteContentSize.X, 0, invGrid.UIGridLayout.AbsoluteContentSize.Y);
end

-- Initial loading of the inventory UI components.
loadInventoryGrid();
loadInventoryItems();

-- Event listener for a UI button designed to reload inventory items.
script.Parent.Parent.ReloadItems.MouseButton1Click:Connect(function()
	-- Clears and repopulates the inventory, useful for refreshing or updating the UI.
	for _, itemFrame in pairs(invMain:GetChildren()) do
		if itemFrame.Name == "InvItem" then
			itemFrame:Destroy();
		end
	end

	loadInventoryItems()
end)

Here’s a download for the .rblx file:
GridInventorySystem.rbxl (64.4 KB)

3 Likes

It’s actually quite well labelled.

Change the gridPartSize and gridPartAmount until it works for you.

Change gridPartAmount to 25 (5x5) and gridPartSize to whatever size you want. Right now gridPartAmount is 98, giving the current 14x7 grid.

Not so sure about moving it though right now. Maybe check out the itemFrame.Position stuff.

The width of the grid remains the same and it looks like grid size only changes the grid size of the items

if i change the grid size back and change this

	invMain.Size = UDim2.new(0, invGrid.UIGridLayout.AbsoluteContentSize.X, 0, invGrid.UIGridLayout.AbsoluteContentSize.Y);

to this

	invMain.Size = UDim2.new(0, 400, 0, invGrid.UIGridLayout.AbsoluteContentSize.Y);

then the items dont align with the grid

Check out item.InvSizeX.Value and item.InvSizeY.Value. I believe that is the item size.

You do have the 5x5 grid though which is a step closer.

That is good and all, you just have to align it properly now.

image
the item.invsize is just the amount of grid spaces X and Y the items take up
item.invposx and y is 0 by default

InvPosX and InvPosY will help you move it to the right. Change the x to a positive number.

About the grid, you have to change the item grid size.

You did figure that out. Just align it now.

InvPosX and InvPosY will help you move it to the right. Change the x to a positive number.

Those variables arent static (arent offsets).
They do not reflect the actual positions of the items as in pixelsX by pixelsY, they just tell where on the grid the item is located. therefore i would somehow need to change the grid snapping function

The item configurations are read to create items in the grid

(sorry for the **** ton of edits, i am rather confused myself)

then add offsets i guess? I’m not sure.
Screenshot 2024-04-07 at 10.41.29 AM
These items i suppose. (forgot if ScreenGUI can have offsets, just whichever one).

About the item sizing and location, there is probably something further in code.

Oh my god I am such an idiot!!!
Looks like I didnt need to change anything but the grid part amount in the script. To achieve the desired result I simply needed to change the size and position of InvMain - therefore also InvGrid to fit a 5x5 grid and the script I had in the beginning did the rest of the work.

I overlooked from the start the possibility of changing the frame sizing manually because I, for some obscure reason, decided that it is somehow set in the script anyway. Sorry!

image

Update: Made it better

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.