My game has an item system that is relatively small compared to most of the RPGs, but it is pretty similar to the games like Half-Life and Counter-Strike where you have an inventory consists of several menus (categories) and a few slots in them. Whenever the player picks up or receives the weapon, from then on they can select it using their inventory which is quite simplistic, in my opinion, and I like it.
First of all, I want to indicate that I am willing to separate logic and data. For data, I am using ScriptableObjects and the basic concept behind is basically referencing ScriptableObjects to MonoBehaviours and handle the tasks in there according to the data. This can be of course made with Prefabs but the thing is, you would de unconsciously duplicating common components that an item would use and only change some of the fields in one of your MonoBehaviours that is related to items. So my approach to that is, keep the data with ScriptableObjects, create only single Prefab, then tie the related components to it and the logic MonoBehaviour which will reference the certain data.
To begin with, I want to talk about how I designed my ScriptableObjects (in other words, data structures). There is the base (abstract) class called ItemData
which contains common stuff like every item will have, for example, HUD icon. Then, there are two more abstract classes which are called PassiveItemData
& ActiveItemData
and derived from ItemData
.
public enum ActiveItemType {
Active,
Firearm,
Melee
}
public abstract class ActiveItemData : ItemData {
public Sprite wieldingSprite;
public ActiveItemType type;
public int menuPosition;
public SupplyData resourceType;
}
public abstract class PassiveItemData : ItemData {
}
PassiveItemData
does not have any fields at the moment, but might do in the future. For now, the only class that derives from it is this:
public class SupplyData : PassiveItemData {
[Tooltip("The maximum amount that the player can carry this type of resource at once.")]
public int max;
}
SupplyData
is the data of consumable items (e.g. ammo) which have no use on their own but can be consumed by other "active" items. Active items are the items that have actual functionalities (e.g. firearm, melee weapon) and can be directly used by the players and switched to via inventory. And a typical active item would also consume a supply. In games like Half-Life, there is no such thing called "active items", whatever that is can be switched to and directly used, they are called weapons in there. The reason that I named mine version as active items is that because, in my game, there won't be only weapons that can be directly used but also items like Medical Syringe (which consumes syringes) for healing purposes. My problem is I don't know where should I put the methods that perform the tasks like fire, use, swing, etc... Because they are not very generic and may belong to the only specific type of items, which is kinda tricky to implement.
My point was to put them inside a MonoBehaviour that will be tied to the Prefab. However, it is not possible to implement it with a single MonoBehaviour since the data would reference either a firearm or melee weapon data. Say, it is a melee weapon, it'd be non-sense to keep a field like ammoInMagazine
that is related to only firearms within the script. But you can never know for sure if the reference data will be firearm or melee weapon. So you have to keep it in there whatsoever. Yet, I don't want this to happen. So I used several more classes that are going to keep the data and perform the tasks accordingly that derives from MonoBehaviour. And the issue has now come to how am I going to use these MonoBehaviours? Create prefabs for each MonoBehaviour? Like Firearm.cs
MonoBehaviour to Firearm Prefab and MeleeWeapon.cs
MonoBehaviour to Melee Weapon Prefab? Oh, my God. Does this mean I'd have to deal with this each time I implement a new item type? No way I do that. Or maybe I do, but not sure if this is the right approach.
I also thought of doing all these without creating MonoBehaviours and Prefabs that they are going to be tied. But in this case, there are going to be other situations where you might not be able to configure the "fire point", for example.
So, people, this might be a little longer than you expected but I still don't even think I included all the details. Nevertheless, I believe you have the big picture and can suggest a thing or two. Thanks in advance.