Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
2
Question by Arithan · Jun 26, 2019 at 08:18 PM · scriptableobjectinventoryinventory systemitemsmonobehavior

Inventory with Upgradable Items and Varying Stats

Hello,

I created an inventory system following this tutorial series: https://www.youtube.com/watch?v=bTPEMt1RG3s&list=PLm7W8dbdfloj4CWX8RS5_cnDWVn1Q6u9Q∈dex=1

The problem with this tutorial, as well as all the other inventory tutorials I've been able to find, use scriptable objects as the items. This is fine for items that have stats that don't change, but for my game, the equipable items will be generated with a range of random stats (similar to Diablo) and players will also be able to upgrade these items multiple times to increase its stats. So using scriptable objects for this won't really work since the stats change.

I tried creating a GameObject and having a MonoBehaviour on that object for storing the current stats, etc., but I can't store that into the inventory because it wants an Item class. It also doesn't seem like a good idea to store GameObjects because then I would need to use GetComponent() on each GameObject every time I want to retrieve the item's stats. There has to be a better way to do this, but I'm having trouble finding what that is. The creator of that tutorial series hasn't been answering people's questions, so I'm not sure how he would handle this issue.

The design is really nice in that I can easily create multiple inventories/bank and different item types, but what I really need is something that can also store items with dynamic stats. Anyone know a good way to convert this inventory system to be able to do that? Thanks in advance.

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

2 Replies

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by Razputin · Jun 27, 2019 at 06:21 AM

Can't you just make a new scriptable object for the randomly generated items using the normal scriptable object as the base?

  1. Spawn new scriptable object

  2. Set its stats equal to the base stats of the randomized object

  3. Add randomness to the new scriptable object

I don't remember how to make a new scriptable object off the top of my head but something like

 new ScriptableObject RNGHammer;
 RNGHammer = NormalHammer;
 RNGHammer.attack += Random.Range(0, 10);

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Arithan · Jun 27, 2019 at 08:26 AM 0
Share

I actually didn't know you can create scriptable objects at runtime. It turns out the tutorial is already instantiating copies of scriptable objects before adding them to the inventory. I just need to modify the stats when it's instantiated and save that data for loading later.

I'm having some issues accessing the variables of the current class though. Here's a small sample of how it's currently set up:

Item Scriptable Object (this is the base Item class that can be used as a template for different item types)

 public class Item : ScriptableObject
 {
     public string id;
     public new string name;
     public int maximumStacks = 1;
     public Sprite icon;
 
     public virtual Item GetCopy()
     {
         return this;
     }
 
     public virtual void GenerateStats()
     {
 
     }
 }



EquipmentItem class (this is an equippable item with a range of possible starting values)

 public class EquipmentItem : Item
 {
     public enum EquipmentType { Barrel, Breech, Head, $$anonymous$$ount, Swivel, Base, $$anonymous$$od1, $$anonymous$$od2 }
     public EquipmentType equipmentType;
 
     public int starting$$anonymous$$inFirepower;
     public int starting$$anonymous$$axFirepower;
     public int starting$$anonymous$$inFireRate;
     public int starting$$anonymous$$axFireRate;
     public int starting$$anonymous$$inTrackingSpeed;
     public int starting$$anonymous$$axTrackingSpeed;
     public int starting$$anonymous$$inAccuracy;
     public int starting$$anonymous$$axAccuracy;
 
     public override Item GetCopy()
     {
         return Instantiate(this);
     }
 
     public override void GenerateStats()
     {
         // calculate stats
     }
 }



For my loot drop script, it's something like this:

 public Item item;
 
 private void DropLoot()
 {
             Item itemCopy = item.GetCopy();
             itemCopy.GenerateStats();  // this works fine
             itemCopy.name = "New Name";  // this also works fine
 
             int temp = itemCopy.starting$$anonymous$$inFirepower;  // doesn't work
 }



Now if I try to access the name of the item, doing "itemCopy.name" works since it's in the Item class, but I can't access any of the variables in the EquipmentItem class like that even though I was able to put an EquipmentItem in the "item" slot of my loot drop script.

I could change it so that the loot drop script takes an EquipmentItem ins$$anonymous$$d of Item, but then I wouldn't be able to put in non equipment items, like consumables, currency, etc.

avatar image Kennai Arithan · Jun 27, 2019 at 08:52 AM 1
Share

I suggest you to add func Init() in Item class and override this func inside GetCopy class. and then you can calc your attributes there.
Or calc atributes in GetCopy - instantiate scriptable object, fill attributes and return instance.
you also may need attribute in Item which will describe that type of item is that - weapon, Equipment and so on. Then you can do something like that:

 private void DropLoot()
  {
              Item itemCopy = item.GetCopy();
              if(itemCopy.itemType == ItemType.Equipment)
              {
                   EquipmentItem equipItem ?= itemCopy;
                   //do what you need with equipItem
              }
  }

but if you want to calc some attributes of an Item - I suggest you to add func in Item and override it in EquipmentItem.
if your "item" do damage - you can add function in Item - GetDamage which will return 0 for class Item. and then override this function in EquipmentItem and return some value.
such stuff will help you to work with items and easely expand it.

 if(item.itemType == ItemType.Weapon)
 {
     float dmg = item.GetDamage();
 }

avatar image Arithan Kennai · Jun 27, 2019 at 09:37 AM 0
Share

I added some more info to my script samples above to make things more clear. Calculating the attributes isn't a problem with my GenerateStats() function, but reading a variable from a child class is. But it just occurred to me that I probably shouldn't be reading the variables directly anyway and that it would be better to create another function inside the child class for that.

avatar image
2

Answer by Kennai · Jun 27, 2019 at 07:25 AM

Hello, @Arithan!
Everything depends on how you make scriptable object for items!
If you make it as item object - then yes, its not fit you. But you can make it as 'template" for item and then use it in separate class.
I mean, in scriptable object you can set min and max damage, sprite, item color, or a set of colors, which will depends on item "level". If item is level 0, then it has min damage, if item is level 1, it has min + 5 damage and so on.
After you will make your "template" scriptable object, you can create a new pure class (without mono behaviour and etc)
and use that new class instead of scriptable object! You also can access Scriptable object from Item class, if needed (to show image or something else)
I made small example, where TemplateItem is a scriptable object.
example of Item class, I made two constructors, to show how it can be used:

 public class Item
 {
    public float damage;
    public float cost;
    public float mass;

     public TemplateItem item { get; private set; }
 
    public Item(TemplateItem tempItem)
    { //tempItem is your scriptable object template
       this.item = tempItem;
       this.damage = tempItem.minDamage + Random.value *
  (tempItem.maxDamage - tempItem.minDamage);
       this.cost = tempItem.baseCost + Random.value * tempItem.randCost;
       this.mass = tempItem.mass;
    }
 
    public Item(TemplateItem tempItem, int level)
    { //tempItem is your scriptable object template
       this.damage = tempItem.minDamage + level * tempItem.lvlDamage;
       this.cost = tempItem.baseCost + level * tempItem.lvlCost;
       this.mass = tempItem.mass + level * tempItem.lvlMass;
    }
 }
Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Arithan · Jun 27, 2019 at 08:58 AM 0
Share

I think this is similar to what's already happening. I have an Item class (parent class) that is a scriptable object, and various other child classes for each type of item, like EquipmentItem for equippable items. The EquipmentItem class has a random range of starting stats for the item. I also had a class called Equipment that stores the current stats after they have been generated, but this class is a $$anonymous$$onoBehaviour, which causes the problem of not being able to add it to an inventory since the Inventory class only wants objects with the Item class.

After reading your answer and the answer from @Razputin I think the best thing to do is to create new instances of the scriptable object at runtime when the loot is generated and then save that data into json or something so it can be loaded later. But I currently have the issue of not being able to access certain variables and methods of the child classes. $$anonymous$$ore in depth details about this are in the comments sections of @Razputin answer.

avatar image Kennai Arithan · Jun 27, 2019 at 09:33 AM 1
Share

Look at this pls, is it suit you?

 public class Item : ScriptableObject
 {
     public string id;
     public new string name;
     public int maximumStacks = 1;
     public Sprite icon;
 
     public bool isDroppable = true;
     public bool isTradable = true;
     public bool isEquipment = true;
     public bool isStackable = true;
 
     public virtual Item GetCopy()
     {
         return this;
     }
 
     //this func is used to equip your hero
     public virtual void Equip(Hero hero)
     {
         //do nothing in Item
     }
 
     public virtual void Unequip(Hero hero)
     {
         //do nothing in Item
     }
 }
 
 public class EquipmentItem : Item
 {
     private bool installed = false;
     public float Armor { get; private set; }
     public float Damage { get; private set; }
 
     public float $$anonymous$$Damage;
     public float maxDamage;
     public float $$anonymous$$Armor;
     public float maxArmor;
 
     public override Item GetCopy()
     {
         EquipmentItem equipItem = Instantiate(this);
 
         equipItem.Armor = $$anonymous$$Armor + Random.value * (maxArmor - $$anonymous$$Armor);
         equipItem.Damage = $$anonymous$$Damage + Random.value * (maxDamage - $$anonymous$$Damage);
 
         return equipItem;
     }
 
     public override void Equip(Hero hero)
     {
         if (installed)
             return;
         hero.Add(this);
         hero.damage = Damage;
         hero.armor += Armor;
         installed = true;
     }
 
     public override void Unequip(Hero hero)
     {
         if (!installed)
             return;
         hero.Remove(this);
         hero.damage = 0f;
         hero.armor -= Armor;
         installed = false;
     }
 }
 
 public class SomeClass
 {
     public Item item;//or a list of items - what you want
     public Hero hero;
 
     public void InstallButton()
     {
         if (item.isEquipment)
             item.Equip(hero);
     }
 }

avatar image Arithan Kennai · Jun 27, 2019 at 09:48 AM 0
Share

Thanks for this. It helped me understand more about how inheritance works. I like how you do the calculations in the GetCopy() function before returning the item rather than how I was trying to do it after.

I'll have to try to put what I learned from these answers into my scripts tomorrow and see if I can get it to work how I want.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

114 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Inventory armor wielding proplem,How to convert from derived to base 1 Answer

Equipting a Item/Weapon 1 Answer

How to Instantiate objects that are Scriptable Objects 0 Answers

How i can make a script-made button interactable? 0 Answers

Scriptableobject List and Instantiating objects from it 3 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges