So I’ve been working on my Game with my Team, as the Lead scripter I’ve run into a problem with the Inventory System. We want to model off Minecraft’s slot-based Inventory and Hotbar. Is there any defined way we can achieve this?
Do you need help with creating the GUI or scripting it to make it work? Is there anything specific you’re stuck on? And do you need it to work with any existing systems in your game?
Honestly your topic lacks context. You have told us there is a problem but never defined what the problem was. Also creating an inventory system like minecraft is pretty easy if you already know how to script an inventory; there is minor changes.
Well, you have 2 main components, the hotbar and the inventory. I would lay it out like this:
local inventory = {
{["Apple"] = 64, ["Orange"] = 24}, -- the first row is the hotbar
{["Apple"] = 64, ["Orange"] = 24} -- all the other rows are in the main inventory
}
I believe 2 tables would be unnecessary since the hotbar/inventory basically intertwine with each other, also a dictionary based inventory wouldn’t work since it wouldn’t be very friendly with listing stacks of the same items but with varying quantities. Therefore an array-based inventory system would be the more practical option.
Yeah, i forgot you could have multiple stacks of the same object . Array based is probably easier if you have a fixed grid system, no idea what I was thinking when i came up with this
local inventory = {
[1] = {"item_1", 20}
}
inventory[1][2] -- quantity
inventory[1][1] -- item name
now, to detect whether an item is in the hotbar, you simply just check whether the first index is 1-(max hotbar slots)
Thats a pretty good start, thank you!
I’m looking for a base to start off from if you will, I don’t need any particular GUI just a base to start scripting off of. And currently, there is no system in development to intertwine with the Inventory in Development.
Well, you’ll need to have the inventory data in a table, as you (pretty much) need that to store it in a data store later. It’s also the most convenient way to work with the data IMO (as opposed to having lots of StringValue or whatever objects).
Since inventory spots don’t interact with their neighbors or anything like that, you don’t need a 2D representation. So you can just have a (1D) list of inventory slots and their contents. Since each slot can only hold one item type, but several items of that type, the contents can be stored as just an item type ID and a count. This is more efficient that storing say a table of 64 identical objects. But for e.g. damaged items you need additional data (the health) which varies per item even of the same item type, so in that case you do need an object per item. Let’s just store a single object per slot and a count, and optional additional data inside the object, and disallow stacking objects with additional data.
So an item might look like {itemTypeId}
or {itemTypeId, health}
. Each inventory slot looks like {itemReference, itemCount}
. And the completee inventory data table looks like {backpack={slot, slot, ..., slot}, hotbar={slot, slot, ..., slot}}
since there are two regions in the inventory that we want to differentiate between.
Picking up a stackable item means looking for a slot of the same item type with room for more and incrementing that slot’s count. An unstackable item, or a stackable one with no non-full existing stack means finding the first empty slot, setting the item type and setting the count to 1. If there are no empty slots in the latter case, the item can’t be picked up. Well, and there’s the two zones to take care of.
function findAvailableSlot(inventory, item)
--1st pass, look for existing stacks
for _, zone in {inventory.hotbar, inventory.backpack} do
for _, slot in zone do
if slot.itemTypeId == item.itemTypeId and slot.count < MAX_STACK_SIZE then
return slot, zone
end
end
end
--2nd pass, look for empty slots
for _, zone in {inventory.hotbar, inventory.backpack} do
for _, slot in zone do
if slot.itemCount == 0 then
return slot, zone
end
end
end
return nil
end
function tryPickingUp(player, item)
local inventory = playerInventories[player]
assert(not item.pickedUp)
local slot, slotZone = findAvailableSlot(inventory, item)
if slot then
if slot.count == 0 then slot.itemTypeId = item.itemTypeId end
slot.count += 1
item.pickedUp = true --Or find some other way of preventing picking up an item more than once.
item.model:Destroy()
updateSlotGui(slot, slotZone)
end
end
game.Players.PlayerAdded:Connect(function(player)
local inventory = {
hotbar={},
backpack={},
}
for i = 1, 10 do
local slot = {zone = inventory.hotbar, slotNumber = i, itemCount = 0, itemTypeId = -1}
inventory.hotbar[i] = slot
end
for i = 1, 100 do -- or however many
local slot = {zone = inventory.horbar, slotNumber = i, itemCount = 0, itemTypeId = -1}
inventory.backpack[i] = slot
end
playerInventories[player] = inventory
end)
To connect the GUI to the data, you can store each slot GUI in an array:
local slotGuis = {
hotbar={},
backpack={},
}
function setupInventoryGui()
for i, slotGui in screenGui:FindFirstChild("Hotbar", true):GetChildren() do
if slotGui.Name == "Slot" then
slotGuis.hotbar[i] = slotGui
end
end
for i, slotGui in screenGui:FindFirstChild("Backpack", true):GetChildren() do
if slotGui.Name == "Slot" then
slotGuis.backpack[i] = slotGui
end
end
end
function updateSlotGui(slot)
local gui
if slot.zone == "hotbar" then
gui = slotGuis.hotbar
else
gui = slotGuis.backpack
end
gui.ImageLabel.Image = ITEM_TYPE_ICONS[slot.itemTypeId]
gui.TextLabel.Text = slot.itemCount
end
As usual you’ll have to run some code on the server and some on the client, and use RemoteEvents/RemoteFunctions to communicate between them.
Wow, that makes alot of sense, Tysm!
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.