My question is quite simple but yet, I can’t answer it. I have a Scriptable Object named Item. From this, I have four derived classes : Weapon, Armor, Food and Material (for crafting for exemple). I need to use it from an exterior script. All I want to do is using a variable contained in the Food child (for exemple the HP amount to give when the player eat it, that doesn’t exist in the others scripts), when I only use the parent in this script. How can I do something like Parent.ChildVariable ?
But it’s usually a code smell and wrong way if you have chosen to use inheritance.
You shouldn’t care about underlying type and its data, there should be an interface suitable for each item.
If all of your items can be used, then you should create abstract/virtual Use method which accepts reference to Player, so inside food class you are calling player.Heal() or something.
Thank you for your answer with @AndersMalmgren ! So, if I understand, I must rewrite my items to not use child/parent ?
I must only have a “UsableItem” ScriptableObject and a “NonUsableItem” ScriptableObject ?
I mean the actual answer here should probably depend on the scope of which items and surrounding systems take part in your project. Is there only a handful of items that make up a small part of your game? Or is there going to hundreds if not thousands, and be one of the major focuses?
That said I found that a component-based system provides as much scalability as you could poke a stick at without getting too complicated. Though rather than MonoBehaviour components, you use plain C# objects in a collection serialized with [SerializeReference] to enable polymorphism. That way, you only need one scriptable object class for your items, and can implement any number of component types.
It does require custom inspector stuff to get working, but tools like Odin Inspector can make it work out of the box.
IF not all your items are consumables then you need to adress that. Easiest way is to make all items consumables and have NOOP implementaion on those that do not support being consumed.
YOu can also make a IConsumable interface and make concrete types both implement IItem and IConsumable if they can be consumed. A little tricker using from code, coudl be solved with GetComponent() and similar mechanics.
You can use casting like earlier explained. But difference here is that its not done from a super type and also does not violate SOLID. Example from our game.
public void OnCollisionEnter(Collision collision)
{
if (NVRInteractables.GetInteractable(collision.collider) is IPhysicalHandCollidable collidable)
{
collidable.OnCollide(hand, collision);
}
}
In your game this would transfer to NVRInteractables.GetInteractable(collision.collider) returning a IItem and IPhysicalHandCollidable being a IConsumable