Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Item Equip/Unequip and Using Consumables

Discussion in 'Scripting' started by yepfuk, Oct 2, 2016.

  1. yepfuk

    yepfuk

    Joined:
    Sep 23, 2015
    Posts:
    67
    Hi,

    I created an Inventory system, with equipping and unequipping feature. In this system, players easily equip and unequip items such as weapons and some wearable items. And of course I have some consumable items which players can use. The system works great so far.

    Now it's time to create a system that manages to Player Stats like Health, Armor, Skill Points, Experience Points, Speed etc. when player equip/unequip these items or use a consumable.

    How can I do this kind of system?

    What I think so far:

    - Create StatTypes enum.
    - Create Stats script for keeping player stats.
    - Create a StatModifier script to modify stats in the Stats script correctly.
    - Create 2 interfaces(IEquipable and IConsumable).
    - Create 2 scripts(Equipalbe and Consumable) and implement these interfaces.
    - In the inventory when the player add an item, I will look the type of the item and, if the item is wearable or weapon I will add the Equipable component to it, if the item is consumable I will add the Consumable component to it.
    - When the item is equipped or consumed, I send the List of stats to the StatModifier via Interfaces.
    - When the StatModifier gets this stats, change the stats with appropriate methods.

    or should I use Events?

    Which one is more convenient or should I use different approach?

    Thank you...

    Edit:

    Stat Types:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public enum StatTypes
    5. {
    6.     LVL, // int
    7.     EXP, // float
    8.     Health, // float
    9.     Armor, // float
    10.     TechPoint, // int
    11.     HealthIncreaseRate, // float
    12.     RunSpeed, // float
    13.     Damage, // float
    14.     CriticalHitChance, // float
    15.     FireRate, // float
    16.     RecoilRate, // float
    17.     HitSpeed, // float
    18.     MissHitChance, // int
    19.     ReloadSpeed, // float
    20.     Count
    21. }
    Equipable:


    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System;
    4. using System.Collections.Generic;
    5.  
    6. public class Equipable : MonoBehaviour, IEquipable
    7. {
    8.     public void Equip(List<ItemAttribute> itemStats)
    9.     {
    10.         StatModifier.instance.GetStatsToChange(itemStats);
    11.     }
    12.  
    13.     public void UnEquip(List<ItemAttribute> itemStats)
    14.     {
    15.         List<ItemAttribute> stats = itemStats;
    16.  
    17.         for(int i=0; i<stats.Count; i++)
    18.         {
    19.             stats[i].attributeBonus = stats[i].attributeBonus * -1;
    20.         }
    21.  
    22.         StatModifier.instance.GetStatsToChange(stats);
    23.     }
    24. }
    25.  
    Stat Modifier:


    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4.  
    5. public class StatModifier: MonoBehaviour{
    6.     public static StatModifier instance;
    7.  
    8.     public Dictionary<StatTypes, float> changes = new Dictionary<StatTypes, float>();
    9.  
    10.     private void Awake()
    11.     {
    12.         if(instance == null)
    13.         {
    14.             instance = this;
    15.         }
    16.         else if(instance != null)
    17.         {
    18.             Destroy(this.gameObject);
    19.         }
    20.  
    21.         DontDestroyOnLoad(this.gameObject);
    22.     }
    23.     public void GetStatsToChange(List<ItemAttribute> statsToChange)
    24.     {
    25.         changes.Clear();
    26.  
    27.         for(int i=0; i<statsToChange.Count; i++)
    28.         {
    29.             changes.Add(statsToChange[i].statType, statsToChange[i].attributeBonus);
    30.         }
    31.  
    32.         PlayerStatsManager.instance.UpdateStats(changes);
    33.     }
    34. }
    35.  
    StatManager:


    Code (CSharp):
    1.     public void UpdateStats(Dictionary<StatTypes,float> statsToAdd)
    2.     {
    3.         changedStats = statsToAdd;
    4.  
    5.         foreach(StatTypes t in changedStats.Keys)
    6.         {
    7.             currentStats[t] += changedStats[t];
    8.         }
    9.     }
    This works pretty good, but the biggest problem is this system is, adding a percentage bonuses. Some of these Stat types are based on percentage.
    Example:
    1 wearable Item can change two stats, one of these add +200 health and the other increase the ciritcal hit chance %5.

    How can I achieve this?
     
    Last edited: Oct 3, 2016
  2. DroidifyDevs

    DroidifyDevs

    Joined:
    Jun 24, 2015
    Posts:
    1,724
    Depends on how you're storing your player stats. How are you storing them?
     
  3. yepfuk

    yepfuk

    Joined:
    Sep 23, 2015
    Posts:
    67
    I store my stats using an indexer correspoinding to PlayerStats enum.
     
  4. DroidifyDevs

    DroidifyDevs

    Joined:
    Jun 24, 2015
    Posts:
    1,724
    I've never used indexers, but I'd say save your upgrade stats the same way as you save your PlayerStats. Then you can simply add them together. However, you'll need to save data after closing the game (because it would be annoying to lose your upgrade configuration every time you close the game). I'd recommend serializing data, like this:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.IO;
    4. using System.Runtime.Serialization.Formatters.Binary;
    5. using System.Runtime.Serialization;
    6. using System;
    7. using System.Collections.Generic;
    8.  
    9. //this is SaveInfoNewer.cs
    10. //this script saves and loads all the info we want
    11. public class SaveInfoNewer : MonoBehaviour
    12. {
    13.     public SlotLoader SlotLoader;
    14.     //data is what is finally saved
    15.     public Dictionary<string, int> data;
    16.  
    17.     void Awake()
    18.     {
    19.         //LoadUpgradeData();
    20.         LoadData();
    21.         //WARNING! data.Clear() deletes EVERYTHING
    22.         //data.Clear();
    23.         //SaveData();
    24.     }
    25.  
    26.     public void LoadData()
    27.     {
    28.         //this loads the data
    29.         data = SaveInfoNewer.DeserializeData<Dictionary<string, int>>("PleaseWork.save");
    30.     }
    31.  
    32.     public void SaveData()
    33.     {
    34.         //this saves the data
    35.         SaveInfoNewer.SerializeData(data, "PleaseWork.save");
    36.     }
    37.     public static void SerializeData<T>(T data, string path)
    38.     {
    39.         //this is just magic to save data.
    40.         //if you're interested read up on serialization
    41.         FileStream fs = new FileStream(path, FileMode.OpenOrCreate);
    42.         BinaryFormatter formatter = new BinaryFormatter();
    43.         try
    44.         {
    45.             formatter.Serialize(fs, data);
    46.             Debug.Log("Data written to " + path + " @ " + DateTime.Now.ToShortTimeString());
    47.         }
    48.         catch (SerializationException e)
    49.         {
    50.             Debug.LogError(e.Message);
    51.         }
    52.         finally
    53.         {
    54.             fs.Close();
    55.         }
    56.     }
    57.  
    58.     void CheckScores()
    59.     {
    60.         if (Player1Score > Player2Score)
    61.         {
    62.             //Win code
    63.             PlayerPrefs.SetInt("Player1Score", Player1Score);
    64.         }
    65.  
    66.         else
    67.         {
    68.             //player 2 wins
    69.             //do same for player 2
    70.         }
    71.     }
    72.  
    73.     public static T DeserializeData<T>(string path)
    74.     {
    75.         //this is the magic that deserializes the data so we can load it
    76.         T data = default(T);
    77.  
    78.         if (File.Exists(path))
    79.         {
    80.             FileStream fs = new FileStream(path, FileMode.Open);
    81.             try
    82.             {
    83.                 BinaryFormatter formatter = new BinaryFormatter();
    84.                 data = (T)formatter.Deserialize(fs);
    85.                 Debug.Log("Data read from " + path);
    86.             }
    87.             catch (SerializationException e)
    88.             {
    89.                 Debug.LogError(e.Message);
    90.             }
    91.             finally
    92.             {
    93.                 fs.Close();
    94.             }
    95.         }
    96.         return data;
    97.     }
    98. }
    99.  
    Generally the way I do upgrades is I create a dictionary for upgrades and another dictionary for player stats. Then at the start of the game I add them together but don't save. That way nothing changes the player's base stats. However as you said, there are many different ways of achieving the result, so I'd play around and see what you like most. At the end of the day, the result is more important than how you got there.
     
    yepfuk likes this.
  5. yepfuk

    yepfuk

    Joined:
    Sep 23, 2015
    Posts:
    67
    I can serialize and save data via my other script, but thank you for the script. I use the indexer because if I use something else then I should hard coded all the Stat Types. I will post my scripts when I done what I said in first post. Thank you ;)
     
    DroidifyDevs likes this.