I just need some directional advice. I’ve been messing around with an inventory system and I had one that was quite workable but it was missing a feature I was looking for. Basically all inventories are connected to items so your character doesn’t actually have an inventory unless you find say a backpack and have it equipped or holding it. even interacting with it will allow you to access it. I have/had all that working but the key feature I wasn’t getting right was been able to have some kind of inventory inside that one(Like a pouch inside a backpack). Because of how I had the code set up (Containers had a list of a slot class and that slot class would also reference the container class in case one was there, you can see the self looping function popping up in inspector). I spent days trying to figure out a way around it and eventually just thought “oh, wait. make a tier list of containers” Is the supplied code (simplified) a reasonable method of doing this or can someone maybe point me in some kind of direction of C# black magic I should look into? some kind of example would be nice too.
[Serializable]
public abstract class BaseContainer
{
public int size;
public int maxWeight;
public int currentWeight;
}
[Serializable]
public class LargeContainer : BaseContainer
{
public List<LargeContainerSlot> slots;
}
[Serializable]
public class MediumContainer : BaseContainer
{
public List<MediumContainerSlot> slots;
}
[Serializable]
public class SmallContainer : BaseContainer
{
public List<SmallContainerSlot> slots;
}
[Serializable]
public abstract class BaseContainerSlot
{
public SOItem item;
}
[Serializable]
public class LargeContainerSlot : BaseContainerSlot
{
public MediumContainer container;
}
[Serializable]
public class MediumContainerSlot : BaseContainerSlot
{
public SmallContainer container;
}
[Serializable]
public class SmallContainerSlot : BaseContainerSlot
{
}
You can have a game object with a Container script that simply contains a list of game objects and some of those game objects could also have a Container script. Or an even simpler method would be to drop the Container class and make objects a child of other objects. Although you’ll obviously need to deactivate the child objects so they’re not rendered. Doing this would help to make your containers feel more physical and credible. I imagine it’ll also be simpler and more fun for you to work with.
You could also make it so that it’s possible to see inside some of your containers and see the items within.
interface IItem { }
class SOItem : ScriptableObject, IItem { }
class Container : ScriptableObject, IItem
{
public List<IItem> items = new();
}
var rootcontainer = ScriptableObject.CreateInstance<Container>();
var nestedcontainer = ScriptableObject.CreateInstance<Container>();
nestedcontainer.items.Add(ScriptableObject.CreateInstance<SOItem>());
rootcontainer.items.Add(nestedcontainer);
Note while I’m doing this as an interface and ScriptableObject it’s not really important. You could have used a base abstract class for IItem, you could make these components instead of ScriptableObjects, you could have them just be plane old classes. The choice you go with will impact the diversity of types and how you do editor drawing if you need editor drawing. I generally stick to interfaces because you can implement them disparately and I’m unafraid to write editor scripts to help me along.
Also you can just have a ‘maxsize’ int on your container to limit its size and just validate your list isn’t full before adding to it. I’d probably start encapsulating at that point to control this flow, but I wanted to keep the example simple.
I wouldn’t do it that way. It’s going to be a pain to maintain, and it’s going to be messy, verbose and/or arbitrarily restrictive.
I think your issue likely stems from your “Slot” referring to a Container or an Item, rather than an Item which can be a Container. In other words, I back lordofduct’s solution - if a Container is a type of Item, then Container should extend Item. (There are other ways you could do this, but if you’re a beginner, start with this one.)
In the places where Containers need special handling, your code can then do something like:
if (item is Container) {
// Add an "Open" button to its action list, or whatever.
}
I would definitely abstract out the concept of a item container (and also the concept of an item, too, honestly). If you were to use an interface, such as IItemContainer and express the bare minimum implementation an inventory needs, that gives you room to implement all sorts of wacky concrete implementations. This also means you can have an item implementation that it itself implements IItemContainer, allowing it to be an inventory itself.
I’m not sure I like the idea of having physical objects for the actual containers though that would make some things quite simple. Populating containers in editor would be really simple though. I’ll give it a thought. Thanks.
Yeah that was pretty much my problem (the container part). I’m going to give duct’s sollution a try anyhow. The only thing I liked about the tiered thing I had going is it was easy to limit which item could go into which container. To a point. But yeah sticking to it I see myself writing a million functions just to checking what can go where.