Would you use a matrix to make a grid based inventory system?

I don’t think you’re understanding. Detecting which frame the mouse is over is done just like you said, yes. However; when you are dragging the object around over the slots. The object is lets say 3 by 4 slots wide. How would you know which slots its over to check if it can be placed in those slots?

I get out of class soon, I can write a little example once I get back.

1 Like

Would appreciate that. Not asking for someone to write the whole script for me, I’m just not understanding how that would help you tell which slots the Object is over.

Why do you need to check multiple slots? Wouldn’t a single draggable equip only occupy a single slot?

Uh that’s not what this is.

For reference this is what I’m trying to recreate essentially.

https://www.youtube.com/watch?v=W-HRdTpOXe4&t=25s

Okay so single draggable equips which occupy multiple slots. Does the size of the draggable equip correspond to the number of slots it occupies?

Something like that i guess? I’m still not sure what you’re meaning.

Uh yes? I’m just a little confused what “single draggable equips” are. But the answer is yes, the size does correspond the the number of slots it occupies.

You could absolutely use a matrix. The method you use should be heavily dependent on what functionality you want to see.

What you’ll see if you look at the Roblox Backpack source code is this:

-- 140
local SlotsByTool = {} 
-- 929
				local slot = LowestEmptySlot or MakeSlot(UIGridFrame)
				for i = slot.Index, 1, -1 do
					local curr = Slots[i] -- An empty slot, because above
					local pIndex = i - 1
					if pIndex > 0 then
						local prev = Slots[pIndex] -- Guaranteed to be full, because above
						prev:Swap(curr)
					else
						curr:Fill(tool)
					end
				end
-- 941

Diving deeper into this source code with ctrlF+SlotsByTool will show you this variable’s main functionality. It would be very similar to what you’re searching for.

The truth is that you don’t actually need to keep track of rows unless you want every slot to be accessible for organization (backpack does not have this functionality, rather it decides what slot is open and places new objects there).


That said, another option is to write each inventory slot with OOP, and attach a metatable to it that indexes functions which will handle most of your work for you. This method would provide additional functionality, depending on if you need it.

When you have created all slots, write them all to the same metatable that indexes your functions. That metatable will read your other slots and their information, etc…


If most of what you want is a readable table to keep track of what a player’s inventory is currently occupied of – this can be done with a matrix as you said above.

1 Like

Ah this is very helpful! I’m still lost on the main problem I’ve stated; detecting which slots the object is hovering over when you’re dragging it that way you can actually check if its occupied using that matrix.

Sure! I’ll use the Roblox backpack source as an example again,

Let’s take a look at it. This time we’ll look at the Hotbar functionality instead, because the backpack itself self organizes (doesn’t have slots).

I’ll be combining some important information into a singular Lua block, but I will write its source line next it.

Source (click to open)
local HOTBAR_SLOTS_FULL = 10 -- 41
local FullHotbarSlots = 0 -- 143

local function CheckBounds(guiObject, x, y) -- 270
	local pos = guiObject.AbsolutePosition
	local size = guiObject.AbsoluteSize
	return (x > pos.X and x <= pos.X + size.X and y > pos.Y and y <= pos.Y + size.Y)
end -- 274

-- Check where we were dropped (line 768)
			if CheckBounds(InventoryFrame, x, y) then
				if slot.Index <= NumberOfHotbarSlots then
					slot:MoveToInventory()
				end
				-- Check for double clicking on an inventory slot, to move into empty hotbar slot
				if slot.Index > NumberOfHotbarSlots and now - lastUpTime < DOUBLE_CLICK_TIME then
					if LowestEmptySlot then
						local myTool = slot.Tool
						slot:Clear()
						LowestEmptySlot:Fill(myTool)
						slot:Delete()
					end
					now = 0 -- Resets the timer
				end
			elseif CheckBounds(HotbarFrame, x, y) then
				local closest = {math.huge, nil}
				for i = 1, NumberOfHotbarSlots do
					local otherSlot = Slots[i]
					local offset = GetOffset(otherSlot.Frame, Vector2.new(x, y))
					if offset < closest[1] then
						closest = {offset, otherSlot}
					end
				end -- 791

Not included in the above code is SlotFrame.DragStopped, which takes X,Y of stopping position. These X,Y values along with InventoryFrame pass to CheckBounds function.

What you’re actually interested in learning is the functionality of this CheckBounds function. The reason this custom function is used instead of UIObject.MouseEnter/MouseLeave is likely because that functionality will be prone to problems depending on device. If your game is exclusively on computer, you might as well use MouseEnter/MouseLeave and self solve the edge cases.

CheckBounds works like this:
→ Check if a Hotbar slot is available, if not move item to inventory
→ If a hotbar slot is available, run CheckBounds function, which compares X & Y of HotbarFrame to the X,Y where the mouse stopped dragging. These all return as a single statement that decides whether or not you dropped into the Hotbar frame.
→ Then, this statement iterates each Hotbar slot individually and updates closest variable (one scope higher) to that specific Slot. GetOffset(otherSlot.Frame, Vector2.new(x, y)) -- line 787

  • GetOffset will return the magnitude of the Vector2 between a Slot’s absolute position & and where the mouse stopped dragging.
  • If the offset is less than the former lowest offset, it updates the closest frame.

→ These updates are made, and then tracked by top level variables for future referencing.


Keep in mind that this is for a nearly fullproof system, and you could simply write a function to check the MousePosition against Slot positioning to decide the closest slot and see perfectly fine functionality. Hope this helps.

1 Like

I learned inventory from AlvinBlox’s Egg Hatching tutorial, realized how bad that was, then made my own. It’s a pretty limited perspective. But what I do know:

  • You can store inventories based on a parent/child relationship. In the GUI, you drop the item into a frame and it populates the inventory graphically. Those individual frames have item values and that could be your table. BUT! This is a client side inventory system, so its garbage.
  • You need a server side inventory system. A table will do, unless you introduce stacking, in which case, you are probably going to need a full dictionary. Use the table to control what ends up in the GUI, not use the GUI to control what’s in the table.

I start with “inventory[player] = {}” then everything else is a table/dictionary inside that.

The GUI needs to be able to be called to add/remove/modify the contents from the server. From the client to the server, I use a GUID (unique ID) to validate all requests. The GUI is a hollow shell.

Here’s the setup, which looks very close to the Egg Hatching tutorial. Template stored in the client side script and is dropped into the ScrollingFrame. The difference is the script doesn’t actually do anything but process the item passed along from the server.

The UIGridLayout sets up the rows and columns. You don’t need a matrix. Give each template the GUID it needs to communicate back to the server.

image

Dictionaries are tables, arrays and dictionaries are the same type and will be treated the same >>type({}) or >>type({["Dog"] = true}, both are table types.

Also, the concept that you “don’t need a matrix” is a non-point. Caching inventories current state on Client is important, even if you validate updates through the server. You could have one or not have one, it doesn’t matter as long as your client can access the information.

OP’s main problem is recognizing what Slot an item should drop into, you still need a function that Checks your slot bounds to decide this. Entirely relying on UIGridLayout insinuates an inventory system that automatically places objects to a predetermined slot (does not dynamically decide or allow the user to organize their inventory).

May I reiterate that its not the inventory system that’s the issue. In fact I could explain exactly what I’ve done here with the actually inventory system itself (sever side).

The issue I’m having has to do with visuals and recognizing which slot(s) the item should drop into when drug to and frow. The problem is all client side (Gui based) not actual inventory system based. It’s the players interaction with the inventor GUI that I’m trying to figure out.

Well that explains how to tell which slots to drop into, but would I run the check on every slot in the inventory its in to tell if its within that slot?

The source code provided does that as well, I may not have explained it well:

local closest = {math.huge, nil}
				for i = 1, NumberOfHotbarSlots do
					local otherSlot = Slots[i]
					local offset = GetOffset(otherSlot.Frame, Vector2.new(x, y))
					if offset < closest[1] then
						closest = {offset, otherSlot}
					end
				end

A higher scope variable is created, and then each slot is individually assessed based on its distance from the mouse’s position. A shorter Vector2 magnitude means the higher scope variable writes into that specific slot.

Mind you the calculation is not just mouse distance to AbsolutePosition of each slot, it calculates distance from where the box bounds reach to.

1 Like

Oh wow that’s actually perfect! So that does mean basically every time the player moves their mouse, this check should be ran?

No, that would be pointless in most scenarios.

I explained this above, the code also has a custom wrote function “DragStopped”, which acts as the action event for running this function (player is dragging something and wants to drop it into a slot).

Oh yes, I miss understood. I’ll see what I can do and the get back to you.

So after reading a bit and looking at the core script source you provided, I can’t quite tell if I’ll need to make an OOP and each slot be an object created from an OOP object, then just have a check bounds function in each one and have them check themselves to see if the object being drug and stopped dragging is in the bound of itself and if it is, return true. Or in the end just do what I was doing before with the matrix thing…