0
\$\begingroup\$

So the game i'm making will have items with different functionality such as ammo boxes, med-packs, guns, food, water ect. My problem is i don't know where to put the code for the specific functionality e.g code for eating food.

My item system works by having a database (dictionary with a string and item stats) and an inventory list of strings. When using a item i look up the stats of that item using the string in the inventory list.

One idea i had was to have scrips on the player something like heal, ammo, gun ect, and have methods in those scrips for the functionality. Is this a good way of doing it?

\$\endgroup\$
0
\$\begingroup\$

Part of an item's stats can include a reference to the behavior of the item when it is consumed or used. This can be represented in the item's structure as a delegate/function pointer/closure/et cetera based on language.

In C#, you could do it with an Action delegate. So your item structure would look like:

class Item {
  int value;
  int weight;
  // ...other stats...

  Action<Item, Character> onUseEffect;
};

onUseEffect is a (possibly-null) reference to a function that takes an Item and a Character, which at runtime will be the item being used and the character using the item, respectively. You can naturally have more (or fewer) parameters as needed.

So now, when using an item you look up it's Item object as you do now to get the stats of the item. And if that Item has a non-null onUseEffect, you call that function:

void UseItem(string name) {
  Item item = m_itemDatabase[name]; // look up the item...
  if (item.onUseEffect != null) {
    item.onUseEffect(item, thisCharacter);  // use the item...
  }
}

You'd bind these actions when you create each item in the database:

Item potionItem = new Item();
// ...other initialization...
potionItem.onUseEffect = (item, user) => { 
  // Potions heal 50 HP for the user.
  user.Health += 50;
};

m_itemDatabase.Add("Potion", potionItem);

All of this allows you to define your item behavior in code without having to subclass Item for each new type or behavior. It's also a useful building block towards allowing your item's behavior to be defined in scripts (the onUseEffect delegate simply becomes a call to the item's script), as you proposed in your question. Using scripts (e.g., data) to describe the behavioral effects of your items is a good idea in general, although it might be overkill depending on the size of your game and data set. And whether or not you already have a scripting mechanism built.

\$\endgroup\$
  • \$\begingroup\$ The only problem i have with this is my database dictionary is made from two lists, so i can edit it the inspector. Should i change my system to be hard-coded like your answer? \$\endgroup\$ – ThePumkinMelon Aug 7 '18 at 17:06
  • \$\begingroup\$ No; I hard-coded the creation of the database for brevity. It would be better not to, although I'm insufficiently familiar enough with Unity to suggest how you might specifically handle that via the inspector. \$\endgroup\$ – user1430 Aug 7 '18 at 17:21
  • 1
    \$\begingroup\$ For Unity, I'd recommend creating an ItemType derived from ScriptableObject. Then each distinct ItemType can be an asset in your project folder that you can inspect individually (or group select to make edits common to several items). You can also reference these ItemTypes directly rather than keying them by name, so there's one less potential point of failure. \$\endgroup\$ – DMGregory Aug 7 '18 at 17:59
  • \$\begingroup\$ @DMGregory So i should use ScriptableObjects instead of a database? \$\endgroup\$ – ThePumkinMelon Aug 7 '18 at 18:57
  • 1
    \$\begingroup\$ It's not an either-or. The two perform different jobs. ScriptableObject lets you manipulate your item types as assets, and share references to them in inspector parameters (or even download them on demand for expansion content, etc). A database or map/dictionary is a means of looking up a particular item based on some key or query data. You could store your ScriptableObjects in a database and look them up via some criteria, if you wanted to. For many purposes though, it will be easier to just address the asset directly, without the extra lookup. It just depends what you want to do. \$\endgroup\$ – DMGregory Aug 7 '18 at 19:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.