Thought it would be fun to try and expand my knowledge with metatables, and in doing so I’ve attempted to create an inventory system. There is a BaseSlot, PurchasedSlot, HotbarSlot, and then multiple other slots for different item types.
BaseSlot is the. base… Every slot inherits this.
PurchasedSlot is created once said slot is purchased, upgrading a BaseSlot to a PurchasedSlot.
HotbarSlot inherits a PurchasedSlot since you start out with them.
Now this is where I am having trouble… When an item is added to a slot, the slot changes depending on the item type (ie. ToolSlot). Now this could inherit either a PurchasedSlot or a HotbarSlot depending which is the next available slot. I get how to inherit from a predetermined parent, but i’m not sure how to be able to do so on the fly (ie. On creation).
function ToolSlot.new(purchasedSlot) -- purchasedSlot can be either a PurchaseSlot or HotbarSlot
-- This was my latest attempt
-- ToolSlot.__index = purchasedSlot -- If a method does exist, look it up in super
-- local self = setmetatable(purchasedSlot, ToolSlot) -- Set metatable to ToolSlot
-- Errors with 'loop in gettable'
return self
end
I think you’d want to make a factory instead of a .new. But, whatever works.
function ToolSlot.new(purchasedSlot)
local self = {}
self.__index = purchasedSlot
return setmetatable(self, self)
end
However, I think the bigger problem is that you have too many kinds of slots. You should make a generic slot instead that can contain any items. Then, you can add or remove slots based off how much slots a player should have. You’d probably have lists of slot for where they can be. So, inventory would be a list of slots and so would the hotbar.
Thanks for the reply! Also good points, however, continuing onwards just to solve this problem… What if ToolSlot also had functions that need to be called?
function ToolSlot:Talk()
...
end
Obviously that would error if called by a created ToolSlot object. How would I go about solving that?
Guessing I would somehow have to check if it exists in ToolSlot first, if not __index purchasedSlot?
You can’t set multiple metatables, you are essentially resetting the metatable. I realize what’s actually needed is a Mixin. The easiest way of doing that would be with a function. So, you’d essentially want to check in two places if there is the key you are looking for.
function ToolSlot.new(purchasedSlot)
return setmetatable({}, {
__index = function(tbl, key) return ToolSlot[key] or purchasedSlot[key] end
}
end
Now, keep in mind that the ToolSlot is going to override any key that is found in purchasedSlot (if it doesn’t already exist in the new object of ToolSlot). I think this isn’t an ideal solution since you are now creating a unique metatable for each object. The true problem is at an architectural level as mentioned before – but if it works, it works .