Forum begins after the advertisement:


[Part 15] Evolution level blocking upgrading items to that level

Home Forums Video Game Tutorial Series Creating a Rogue-like Shoot-em Up in Unity [Part 15] Evolution level blocking upgrading items to that level

Viewing 15 posts - 1 through 15 (of 16 total)
  • Author
    Posts
  • #15969
    Grant Totinov
    Level 3
    Participant
    Helpful?
    Up
    0
    ::

    Hello. So if i set for ex. evolution Level to 2 for garlic to evolve in Soul Eater, I cant upgrade garlic to level 2. this error pop up:

    View post on imgur.com
    View post on imgur.com
    <code>NullReferenceException: Object reference not set to an instance of an object
    PlayerInventory.Get (PassiveData type) (at Assets/Scripts/Player/PlayerInventory.cs:88)
    PlayerInventory.Get (ItemData type) (at Assets/Scripts/Player/PlayerInventory.cs:77)
    Item.CanEvolve (ItemData+Evolution evolution, System.Int32 levelUpAmount) (at Assets/Scripts/Passive Items/Item.cs:51)
    Item.AttemptEvolution (ItemData+Evolution evolutionData, System.Int32 levelUpAmount) (at Assets/Scripts/Passive Items/Item.cs:64)
    Item.DoLevelUp () (at Assets/Scripts/Passive Items/Item.cs:109)
    Weapon.DoLevelUp () (at Assets/Scripts/Weapons/Weapon.cs:102)
    AuraWeapon.DoLevelUp () (at Assets/Scripts/Weapons/AuraWeapon.cs:34)
    PlayerInventory.LevelUpWeapon (System.Int32 slotIndex, System.Int32 upgradeIndex) (at Assets/Scripts/Player/PlayerInventory.cs:266)
    PlayerInventory+<>c__DisplayClass21_1.<ApplyUpgradeOptions>b__1 () (at Assets/Scripts/Player/PlayerInventory.cs:349)
    UnityEngine.Events.InvokableCall.Invoke () (at <914d6100afbb4dcbb0365e05b2154b62>:0)
    UnityEngine.Events.UnityEvent.Invoke () (at <914d6100afbb4dcbb0365e05b2154b62>:0)
    UnityEngine.UI.Button.Press () (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Button.cs:70)
    UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Button.cs:114)
    UnityEngine.EventSystems.ExecuteEvents.Execute (UnityEngine.EventSystems.IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/ExecuteEvents.cs:57)
    UnityEngine.EventSystems.ExecuteEvents.Execute[T] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.ExecuteEvents+EventFunction1[T1] functor) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/ExecuteEvents.cs:272)
    UnityEngine.EventSystems.EventSystem:Update() (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/EventSystem.cs:514)</code>

    If i set the level to 3 for garlic to evolve to Soul Eater, it can be upgraded to level 3 but not any further.

    But if i have the other catalyst, for ex Pummarola and garlic i set to evolve in Soul Eater in level 2. if i get pummarola first, i can upgrade garlic to leve 2 and it evolves to Soul Eater.

    Heres my code: Item.cs

    <code>using System.Collections;
    using System.Collections.Generic;
    using UnityEditor.Build;
    using UnityEngine;
    
    public abstract class Item : MonoBehaviour
    {
        public int currentLevel = 1, maxLevel = 1;
        protected ItemData.Evolution[] evolutionData;
        protected PlayerInventory inventory;
        public PlayerStats owner;
    
        public virtual void Initialise(ItemData data)
        {
            maxLevel = data.maxLevel;
            // Store the evolution data as we have to track whether all catalysts are in the inventory so we can evolve
            evolutionData = data.evolutionData;
    
            // NOTE: Have to find a better way to refference the player inventory in future, this is inefficiant
            inventory = FindObjectOfType<PlayerInventory>();
            owner = FindObjectOfType<PlayerStats>();
        }
    
        // Call this function to get all the evolutions that the wepaon can currently evolve to
        public virtual ItemData.Evolution[] CanEvolve()
        {
            List<ItemData.Evolution> possibleEvolutions = new();
    
            // Check each listed evolution and whether it is on the inventory
            foreach(ItemData.Evolution e in evolutionData)
            {
                if(CanEvolve(e))
                    possibleEvolutions.Add(e);
            }
            return possibleEvolutions.ToArray();
        }
    
        // Checks if a specific evolution is possible
        public virtual bool CanEvolve(ItemData.Evolution evolution, int levelUpAmount = 1)
        {
            // Cannot evolve if the item hasnt reached the level to evolve
            if (evolution.evolutionLevel > currentLevel + levelUpAmount)
            {
                Debug.LogWarning(string.Format("Evolution Failed. Current level {0}, evolution level {1}", currentLevel, evolution.evolutionLevel));
                return false;
            }
            // Checks to see if all the catalysts are in the inventory
    
            foreach(ItemData.Evolution.Config c in evolution.catalysts)
            {
                Item item = inventory.Get(c.itemType);
                if(!item || item.currentLevel < c.level)
                {
                    Debug.LogWarning(string.Format("Evolution Failed. Missing {0}", c.itemType.name));
                    return false;
                }
            }
            return true;
        }
    
        // AttemptEvolution will spawn a new weapon for the character,a nd remove all the weapons that are supposed to be consumed
        public virtual bool AttemptEvolution(ItemData.Evolution evolutionData, int levelUpAmount = 1)
        {
            if(!CanEvolve(evolutionData, levelUpAmount))
                return false;
    
            // should passives/weapons be consumed?
            bool consumePassives = (evolutionData.consumes & ItemData.Evolution.Consumption.passives) > 0;
            bool consumeWeapons = (evolutionData.consumes & ItemData.Evolution.Consumption.weapons) > 0;
    
            // Loop through the catalysts and check if we should consume them
            foreach(ItemData.Evolution.Config c in evolutionData.catalysts)
            {
                if (c.itemType is PassiveData && consumePassives)
                    inventory.Remove(c.itemType, true);
    
                if (c.itemType is WeaponData && consumeWeapons)
                    inventory.Remove(c.itemType, true);
            }
    
            // Should we consume ourselves as well
            if (this is Passive && consumePassives)
                inventory.Remove((this as Passive).data, true);
    
            else if (this is Weapon && consumeWeapons)
                inventory.Remove((this as Weapon).data, true);
    
            // Ad the new weapon onto inventory
            inventory.Add(evolutionData.outcome.itemType);
    
            return true;
        }
    
        public virtual bool CanLevelUp()
        {
            return currentLevel <= maxLevel;
        }
    
        // Whenever an item levels up, attemp to evolve
        public virtual bool DoLevelUp()
        {
            if (evolutionData == null)
                return true;
            // Tries to evolve into every listed evolution of this weapon if the weapons evolution condition is levelinh ip
            foreach(ItemData.Evolution e in evolutionData)
            {
                if(e.condition == ItemData.Evolution.Condition.auto)
                    AttemptEvolution(e);
            }
            return true;
        }
    
        // What effects owner recieve on equiping an item
        public virtual void OnEquip() { }
    
    
        // What effects are removed on unequiping an utem
        public virtual void OnUnequip() { }
    
    }</code>

    PlayerInventory.cs

    <code>using System;
    using System.Collections;
    using System.Collections.Generic;
    using TMPro;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class PlayerInventory : MonoBehaviour
    {
        [System.Serializable]
        public class Slot
        {
            public Item item;
            public Image image;
    
            public void Assign(Item assignedItem)
            {
                this.item = assignedItem;
                if(item is Weapon)
                {
                    Weapon w = item as Weapon;
                    image.enabled = true;
                    image.sprite = w.data.icon;
                }
                else
                {
                    Passive p = item as Passive;
                    image.enabled = true;
                    image.sprite = p.data.icon;
                }
                Debug.Log(string.Format("Assigned {0} to player", item.name));
            }
    
            public void Clear()
            {
                item = null;
                image.enabled = false;
                image.sprite = null;
            }
    
            public bool IsEmpty() { return item == null; }
        }
    
        public List<Slot> weaponSlots = new(6);
        public List<Slot> passiveSlots = new(6);
    
        [System.Serializable]
        public class UpgradeUI
        {
            public TMP_Text upgradeNameDisplay;
            public TMP_Text upgradeDescriptionDisplay;
            public Image upgradeIcon;
            public Button upgradeButton;
        }
    
        [Header("UI elements")]
        public List<WeaponData> avaiableWeapons = new();
        public List<PassiveData> avaiablePassives = new();
        public List<UpgradeUI> upgradeUIOptions = new();
    
        PlayerStats player;
    
        void Start()
        {
            player = GetComponent<PlayerStats>();
        }
    
        // Checks if the inventory has an item of a certaint type
        public bool Has(ItemData type) { return Get(type); }
    
        public Item Get(ItemData type)
        {
            if(type is WeaponData)
                return Get(type as WeaponData);
    
            else if(type is PassiveData)
                return Get(type as PassiveData);
    
            return null;
        }
    
        // Find a passive of a certain type in the inventory
        public Passive Get(PassiveData type)
        {
            foreach(Slot s in passiveSlots)
            {
                Passive p = s.item as Passive;
                if(p.data == type)
                    return p;
            }
            return null;
        }
    
        //Find a weapon of certain type in the inventory
        public Weapon Get(WeaponData type)
        {
            foreach (Slot s in weaponSlots)
            {
                Weapon w = s.item as Weapon;
                if (w.data == type)
                    return w;
            }
            return null;
        }
    
        //Removes a weapon of a particular type, as specified by data
        public bool Remove(WeaponData data, bool removeUpgradeAvailability = false)
        {
            // Remove this weapon from the upgrade pool
            if (removeUpgradeAvailability)
                avaiableWeapons.Remove(data);
    
            for (int i = 0; i < weaponSlots.Count; i++)
            {
                Weapon w = weaponSlots[i].item as Weapon;
                if (w.data == data)
                {
                    weaponSlots[i].Clear();
                    w.OnUnequip();
                    Destroy(w.gameObject);
                    return true;
                }
            }
            return false;
        }
    
        //Removes a passive of a particular type, as specified by data
        public bool Remove(PassiveData data,  bool removeUpgradeAvailability = false)
        {
            if (removeUpgradeAvailability)
                avaiablePassives.Remove(data);
    
            for (int i = 0; i < passiveSlots.Count; i++)
            {
                Passive p = passiveSlots[i].item as Passive;
                if (p.data == data)
                {
                    weaponSlots[i].Clear();
                    p.OnUnequip();
                    Destroy(p.gameObject);
                    return true;
                }
            }
            return false;
        }
    
        // If an ItemData is passed, determine what type it is and call the respective overload
        public bool Remove(ItemData data, bool removeUpgradeAvailability = false)
        {
            if(data is PassiveData)
                return Remove(data as PassiveData, removeUpgradeAvailability);
    
            else if(data is WeaponData)
                return Remove(data as WeaponData, removeUpgradeAvailability);
    
            return false;
        }
    
        // Finds an empty slot and adds a wepaon of certain type, returns the slot number that the item was put in
        public int Add(WeaponData data)
        {
            int slotNum = -1;
    
            // Try to find an empty slot
            for(int i = 0; i < weaponSlots.Capacity; i++)
            {
                if (weaponSlots[i].IsEmpty())
                {
                    slotNum = i;
                    break;
                }
            }
    
            // if theres no empty slot, exit
            if (slotNum < 0)
                return slotNum;
    
            // Otherwise create the weapon in the slot
            // Get the type of the weapon we want to spawn
            Type weaponType = Type.GetType(data.behaviour);
    
            if(weaponType != null)
            {
                // Spawn the weapon gameObject
                GameObject go = new(data.baseStats.name + " Controller");
                Weapon spawnedWeapon = (Weapon)go.AddComponent(weaponType);
                spawnedWeapon.Initialise(data);
                spawnedWeapon.transform.SetParent(transform);
                spawnedWeapon.transform.localPosition = Vector2.zero;
                spawnedWeapon.OnEquip();
    
                // Assign the weapon to the slot
                weaponSlots[slotNum].Assign(spawnedWeapon);
    
                // Close the level ip UI if it is on
                if(GameManager.Instance != null && GameManager.Instance.choosingUpgrade)
                    GameManager.Instance.EndLevelUp();
    
                return slotNum;
            }
            else
            {
                Debug.LogWarning(string.Format("Invalid weapon type specified for {0}", data.name));
            }
            return -1;
        }
    
        // Finds an empty slot and adds a passive of a certain type, returns the slot number that the item was put in
        public int Add(PassiveData data)
        {
            int slotNum = -1;
    
            // Try to find an empty slot
            for (int i = 0; i < passiveSlots.Capacity; i++)
            {
                if (passiveSlots[i].IsEmpty())
                {
                    slotNum = i;
                    break;
                }
            }
    
            // if theres no empty slot, exit
            if (slotNum < 0)
                return slotNum;
    
            // Otherwise create the weapon in the slot
            // Get the type of the weapon we want to spawn
    
            // Spawn the weapon gameObject
            GameObject go = new(data.baseStats.name + " Passive");
            Passive p = go.AddComponent<Passive>();
            p.Initialise(data);
            p.transform.SetParent(transform);
            p.transform.localPosition = Vector2.zero;
    
            // Assign the weapon to the slot
            passiveSlots[slotNum].Assign(p);
    
            // Close the level ip UI if it is on
            if (GameManager.Instance != null && GameManager.Instance.choosingUpgrade)
                 GameManager.Instance.EndLevelUp();
    
            player.RecalculateStats();
    
            return slotNum;
        }
    
        // If we dont know what item is being added, this function will determine that
        public int Add(ItemData data)
        {
            if(data is WeaponData)
                return Add(data as WeaponData);
            else if(data is PassiveData)
                return Add(data as PassiveData);
            return -1;
        }
    
        public void LevelUpWeapon(int slotIndex, int upgradeIndex)
        {
            if(weaponSlots.Count > slotIndex)
            {
                Weapon weapon = weaponSlots[slotIndex].item as Weapon;
    
                // Dont level up the weapon if it is already at max level
                if (!weapon.DoLevelUp())
                {
                    Debug.LogWarning(string.Format("Failed to level up {0}", weapon.name));
                    return;
                }
            }
            if (GameManager.Instance != null && GameManager.Instance.choosingUpgrade)
                GameManager.Instance.EndLevelUp();
        }
    
        public void LevelUpPassiveItem(int slotIndex, int upgradeIndex)
        {
            if(passiveSlots.Count > slotIndex)
            {
                Passive p = passiveSlots[slotIndex].item as Passive;
                if (!p.DoLevelUp())
                {
                    Debug.LogWarning(string.Format("Failed to level up {0}", p.name));
                    return;
                }
            }
            if(GameManager.Instance != null && GameManager.Instance.choosingUpgrade)
                GameManager.Instance.EndLevelUp();
    
            player.RecalculateStats();
        }
    
        // Determaines what upgrade options should apear
        void ApplyUpgradeOptions()
        {
            // Make a duplicate of the avaiable weapon / passive upgrade lists
            List<WeaponData> avaiableWeaponUpgrades = new(avaiableWeapons);
            List<PassiveData> avaiablePassiveItemUpgrades = new(avaiablePassives);
    
            // Iterate through each slot in the upgrade UI
            foreach (UpgradeUI upgradeOption in upgradeUIOptions)
            {
                // If there are no more avaiable upgrades, then abort
                if (avaiableWeaponUpgrades.Count == 0 && avaiablePassiveItemUpgrades.Count == 0)
                    return;
    
                // Determine whether this upgrade should be for a passive or active weapons
                int upgradeType;
                if (avaiableWeaponUpgrades.Count == 0)
                    upgradeType = 2;
    
                else if (avaiablePassiveItemUpgrades.Count == 0)
                    upgradeType = 1;
    
                else
                    // random generates a number between 1 and 2
                    upgradeType = UnityEngine.Random.Range(1, 3);
    
                // Generates an active weapon upgrade
                if (upgradeType == 1)
                {
                    // Pick a weapon upgrade, them remove it so that we dont get it twice
                    WeaponData chosenWeaponUpgrade = avaiableWeaponUpgrades[UnityEngine.Random.Range(0, avaiableWeaponUpgrades.Count)];
                    avaiableWeaponUpgrades.Remove(chosenWeaponUpgrade);
    
                    // Ensures that the selected weapon data is valid
                    if (chosenWeaponUpgrade != null)
                    {
                        // Turns on the UI slot
                        EnableUpgradeUI(upgradeOption);
    
                        // Loops through all existing weapons. If we find a match, will hook an event listtener to the button that will level up the weapon when the upgrade option is clicked
                        bool isLevelUp = false;
                        for (int i = 0; i < weaponSlots.Count; i++)
                        {
                            Weapon w = weaponSlots[i].item as Weapon;
                            if (w != null && w.data == chosenWeaponUpgrade)
                            {
                                // If the weapon is already at max level, do not allow upgrade
                                if (chosenWeaponUpgrade.maxLevel <= w.currentLevel)
                                {
                                    DisableUpgradeUI(upgradeOption);
                                    isLevelUp = true;
                                    break;
                                }
    
                                // Set the Event Listener, item and level description to be that of the next level
                                upgradeOption.upgradeButton.onClick.AddListener(() => LevelUpWeapon(i, i));
                                Weapon.Stats nextLevel = chosenWeaponUpgrade.GetLevelData(w.currentLevel + 1);
                                upgradeOption.upgradeDescriptionDisplay.text = nextLevel.description;
                                upgradeOption.upgradeNameDisplay.text = nextLevel.name;
                                upgradeOption.upgradeIcon.sprite = chosenWeaponUpgrade.icon;
                                isLevelUp = true;
                                break;
                            }
                        }
    
                        // If the code gets here, it means that it will be adding a new weapon, instead of upgrading existing weapon
                        if (!isLevelUp)
                        {
                            upgradeOption.upgradeButton.onClick.AddListener(() => Add(chosenWeaponUpgrade));
                            upgradeOption.upgradeDescriptionDisplay.text = chosenWeaponUpgrade.baseStats.description;
                            upgradeOption.upgradeNameDisplay.text = chosenWeaponUpgrade.baseStats.name;
                            upgradeOption.upgradeIcon.sprite = chosenWeaponUpgrade.icon;
                        }
                    }
                }
                else if (upgradeType == 2)
                {
                    // NOTE: I have to recode this system, as right now it disables an upgrade slot if i hit a weapon that has already reached max level
                    PassiveData chosenPassiveUpgrade = avaiablePassiveItemUpgrades[UnityEngine.Random.Range(0, avaiablePassiveItemUpgrades.Count)];
                    avaiablePassiveItemUpgrades.Remove(chosenPassiveUpgrade);
    
                    if (chosenPassiveUpgrade != null)
                    {
                        // Turn on the UI slot
                        EnableUpgradeUI(upgradeOption);
    
                        // Loops through all existing passives. If theres a match it will hook an event listener to the button what will level up the passive
                        bool isLevelUp = false;
                        for (int i = 0; i < passiveSlots.Count; i++)
                        {
                            Passive p = passiveSlots[i].item as Passive;
                            if (p != null && p.data == chosenPassiveUpgrade)
                            {
                                // If the passive is already at max level, do not allow upgrade
                                if (chosenPassiveUpgrade.maxLevel <= p.currentLevel)
                                {
                                    DisableUpgradeUI(upgradeOption);
                                    isLevelUp = true;
                                    break;
                                }
                                upgradeOption.upgradeButton.onClick.AddListener(() => LevelUpPassiveItem(i, i));
                                Passive.Modifier nextLevel = chosenPassiveUpgrade.GetLevelData(p.currentLevel + 1);
                                upgradeOption.upgradeDescriptionDisplay.text = nextLevel.description;
                                upgradeOption.upgradeNameDisplay.text = nextLevel.name;
                                upgradeOption.upgradeIcon.sprite = chosenPassiveUpgrade.icon;
                                isLevelUp = true;
                                break;
                            }
                        }
                        if (!isLevelUp) // Spawn a new passive item
                        {
                            upgradeOption.upgradeButton.onClick.AddListener(() => Add(chosenPassiveUpgrade));
                            Passive.Modifier nextLevel = chosenPassiveUpgrade.baseStats;
                            upgradeOption.upgradeDescriptionDisplay.text = nextLevel.description;
                            upgradeOption.upgradeNameDisplay.text = nextLevel.name;
                            upgradeOption.upgradeIcon.sprite = chosenPassiveUpgrade.icon;
                        }
                    }
                }
            }
        }
    
        void RemoveUpgradeOptions()
        {
            foreach(UpgradeUI upgradeOption in upgradeUIOptions)
            {
                upgradeOption.upgradeButton.onClick.RemoveAllListeners();
                DisableUpgradeUI(upgradeOption);
            }
        }
    
        public void RemoveAndApplyUpgrades()
        {
            RemoveUpgradeOptions();
            ApplyUpgradeOptions();
        }
    
        void DisableUpgradeUI(UpgradeUI ui)
        {
            ui.upgradeNameDisplay.transform.parent.gameObject.SetActive(false);
        }
    
        void EnableUpgradeUI(UpgradeUI ui)
        {
            ui.upgradeNameDisplay.transform.parent.gameObject.SetActive(true);
        }
    }</code>
    #15970
    Terence
    Level 30
    Keymaster
    Helpful?
    Up
    0
    ::

    It seems like the NullReferenceException is blocking the complete execution of your code. Change the Get() and Remove() functions in your code as follows:

        // Find a passive of a certain type in the inventory
        public Passive Get(PassiveData type)
        {
            foreach(Slot s in passiveSlots)
            {
                Passive p = s.item as Passive;
                if(p && p.data == type)
                    return p;
            }
            return null;
        }
    
        //Find a weapon of certain type in the inventory
        public Weapon Get(WeaponData type)
        {
            foreach (Slot s in weaponSlots)
            {
                Weapon w = s.item as Weapon;
                if (w && w.data == type)
                    return w;
            }
            return null;
        }
    
        //Removes a weapon of a particular type, as specified by data
        public bool Remove(WeaponData data, bool removeUpgradeAvailability = false)
        {
            // Remove this weapon from the upgrade pool
            if (removeUpgradeAvailability)
                avaiableWeapons.Remove(data);
    
            for (int i = 0; i < weaponSlots.Count; i++)
            {
                Weapon w = weaponSlots[i].item as Weapon;
                if (w && w.data == data)
                {
                    weaponSlots[i].Clear();
                    w.OnUnequip();
                    Destroy(w.gameObject);
                    return true;
                }
            }
            return false;
        }
    
        //Removes a passive of a particular type, as specified by data
        public bool Remove(PassiveData data,  bool removeUpgradeAvailability = false)
        {
            if (removeUpgradeAvailability)
                avaiablePassives.Remove(data);
    
            for (int i = 0; i < passiveSlots.Count; i++)
            {
                Passive p = passiveSlots[i].item as Passive;
                if (p && p.data == data)
                {
                    weaponSlots[i].Clear();
                    p.OnUnequip();
                    Destroy(p.gameObject);
                    return true;
                }
            }
            return false;
        }

    This is because a NullReferenceException occurs in the lines where we access p.data or w.data if either of the variables is null. These variables will be null if we are searching for a passive, and come across a weapon instead, because s.item as Passive will fail and return null, and vice versa if we are searching for a weapon and come across a passive.

    By adding the green highlighted sections, we prevent the code from executing if the conversion fails.

    Let me know if this fixes the issue!

    #15972
    Grant Totinov
    Level 3
    Participant
    Helpful?
    Up
    0
    ::

    Hello Terence. Thank your for your help. This fixed the upgrade lock issue. But now i have another. If soul eater requires Level 2 Harlic and Level 1 Pummarola, if i get Garlic to level 2 and Pummarola to level 1, it doesnt evolve, but if i upgrade Pummarola to Level 2 too, then it proceeds to evolve.

    I get this console error when i have Garlic Level 2 and get Pummarola Level 1:

    <code>Evolution Failed. Missing Pummarola
    UnityEngine.Debug:LogWarning (object)
    Item:CanEvolve (ItemData/Evolution,int) (at Assets/Scripts/Passive Items/Item.cs:54)
    Item:AttemptEvolution (ItemData/Evolution,int) (at Assets/Scripts/Passive Items/Item.cs:64)
    Item:DoLevelUp () (at Assets/Scripts/Passive Items/Item.cs:109)
    Weapon:DoLevelUp () (at Assets/Scripts/Weapons/Weapon.cs:102)
    AuraWeapon:DoLevelUp () (at Assets/Scripts/Weapons/AuraWeapon.cs:34)
    PlayerInventory:LevelUpWeapon (int,int) (at Assets/Scripts/Player/PlayerInventory.cs:266)
    PlayerInventory/<>c__DisplayClass21_1:<ApplyUpgradeOptions>b__1 () (at Assets/Scripts/Player/PlayerInventory.cs:349)
    UnityEngine.EventSystems.EventSystem:Update () (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/EventSystem.cs:514)</code>
    View post on imgur.com

    But again if i get First Pummarola to Level 1, and then upgrade Garlic to Level 2, it works jsut fine.

    So if i first meet the passive catalyst requiremets it works fine, but if i start firt with meeting weapon catalyst requirements, something goes wrong.

    Also this message pops up when i first upgrade Garlic to level 2 without having Pammarola in inventory.

    View post on imgur.com

    Evolution Failed. Missing Pummarola

    <code>UnityEngine.Debug:LogWarning (object)
    Item:CanEvolve (ItemData/Evolution,int) (at Assets/Scripts/Passive Items/Item.cs:54)
    Item:AttemptEvolution (ItemData/Evolution,int) (at Assets/Scripts/Passive Items/Item.cs:64)
    Item:DoLevelUp () (at Assets/Scripts/Passive Items/Item.cs:109)
    Weapon:DoLevelUp () (at Assets/Scripts/Weapons/Weapon.cs:102)
    AuraWeapon:DoLevelUp () (at Assets/Scripts/Weapons/AuraWeapon.cs:34)
    PlayerInventory:LevelUpWeapon (int,int) (at Assets/Scripts/Player/PlayerInventory.cs:266)
    PlayerInventory/<>c__DisplayClass21_1:<ApplyUpgradeOptions>b__1 () (at Assets/Scripts/Player/PlayerInventory.cs:349)
    UnityEngine.EventSystems.EventSystem:Update () (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/EventSystem.cs:514)</code>

    I think its something with the order of catalysts requrements for evolution.

    Thank you for your quick responses, your wisdom is much appreciated.

    #15973
    Terence
    Level 30
    Keymaster
    Helpful?
    Up
    0
    ::

    You need to add the Evolution data on both sides. The Garlic requires the Pummarola, and on the Pummarola you need to add the Garlic as well.

    #15974
    Grant Totinov
    Level 3
    Participant
    Helpful?
    Up
    0
    ::

    I think i did that. Isnt this the right way to do it?

    View post on imgur.com
    #15981
    Terence
    Level 30
    Keymaster
    Helpful?
    Up
    0
    ::

    Can you add the following line to the CanEvolve() function and show me the output on your Console when you try evolving it the other way?

        // Checks if a specific evolution is possible
        public virtual bool CanEvolve(ItemData.Evolution evolution, int levelUpAmount = 1)
        {
            // Cannot evolve if the item hasnt reached the level to evolve
            if (evolution.evolutionLevel > currentLevel + levelUpAmount)
            {
                Debug.LogWarning(string.Format("Evolution Failed. Current level {0}, evolution level {1}", currentLevel, evolution.evolutionLevel));
                return false;
            }
    
            // Checks to see if all the catalysts are in the inventory
            foreach(ItemData.Evolution.Config c in evolution.catalysts)
            {
                Item item = inventory.Get(c.itemType);
                print($"Trying to evolve {c.itemType}. Current level is {item.currentLevel} and requirement is {c.level}.");
                if(!item || item.currentLevel < c.level)
                {
                    Debug.LogWarning(string.Format("Evolution Failed. Missing {0}", c.itemType.name));
                    return false;
                }
            }
            return true;
        }
    #15989
    Grant Totinov
    Level 3
    Participant
    Helpful?
    Up
    0
    ::

    Hello boss. This is what pops up when i click the upgrade the garlic to level 2 without having Pummarola.

    View post on imgur.com
    <code>NullReferenceException: Object reference not set to an instance of an object
    Item.CanEvolve (ItemData+Evolution evolution, System.Int32 levelUpAmount) (at Assets/Scripts/Passive Items/Item.cs:54)
    Item.AttemptEvolution (ItemData+Evolution evolutionData, System.Int32 levelUpAmount) (at Assets/Scripts/Passive Items/Item.cs:67)
    Item.DoLevelUp () (at Assets/Scripts/Passive Items/Item.cs:112)
    Weapon.DoLevelUp () (at Assets/Scripts/Weapons/Weapon.cs:90)
    AuraWeapon.DoLevelUp () (at Assets/Scripts/Weapons/AuraWeapon.cs:35)
    PlayerInventory.LevelUpWeapon (System.Int32 slotIndex, System.Int32 upgradeIndex) (at Assets/Scripts/Player/PlayerInventory.cs:266)
    PlayerInventory+<>c__DisplayClass21_1.<ApplyUpgradeOptions>b__1 () (at Assets/Scripts/Player/PlayerInventory.cs:349)
    UnityEngine.Events.InvokableCall.Invoke () (at <914d6100afbb4dcbb0365e05b2154b62>:0)
    UnityEngine.Events.UnityEvent.Invoke () (at <914d6100afbb4dcbb0365e05b2154b62>:0)
    UnityEngine.UI.Button.Press () (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Button.cs:70)
    UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Button.cs:114)
    UnityEngine.EventSystems.ExecuteEvents.Execute (UnityEngine.EventSystems.IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/ExecuteEvents.cs:57)
    UnityEngine.EventSystems.ExecuteEvents.Execute[T] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.ExecuteEvents+EventFunction
    1[T1] functor) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/ExecuteEvents.cs:272)
    UnityEngine.EventSystems.EventSystem:Update() (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/EventSystem.cs:514)</code>

    And now its not giving me to upgrade the Garlic to level 2. Again if i first get Pammarola first, no problem at sight. Thank you for giving your time for me.

    Item.cs

    <code>using System.Collections;
    using System.Collections.Generic;
    using UnityEditor.Build;
    using UnityEngine;
    
    public abstract class Item : MonoBehaviour
    {
        public int currentLevel = 1, maxLevel = 1;
        protected ItemData.Evolution[] evolutionData;
        protected PlayerInventory inventory;
        protected PlayerStats owner;
    
        public PlayerStats Owner { get { return owner; } }
    
        public virtual void Initialise(ItemData data)
        {
            maxLevel = data.maxLevel;
            // Store the evolution data as we have to track whether all catalysts are in the inventory so we can evolve
            evolutionData = data.evolutionData;
    
            // NOTE: Have to find a better way to refference the player inventory in future, this is inefficiant
            inventory = FindObjectOfType<PlayerInventory>();
            owner = FindObjectOfType<PlayerStats>();
        }
    
        // Call this function to get all the evolutions that the wepaon can currently evolve to
        public virtual ItemData.Evolution[] CanEvolve()
        {
            List<ItemData.Evolution> possibleEvolutions = new();
    
            // Check each listed evolution and whether it is on the inventory
            foreach(ItemData.Evolution e in evolutionData)
            {
                if(CanEvolve(e))
                    possibleEvolutions.Add(e);
            }
            return possibleEvolutions.ToArray();
        }
    
        // Checks if a specific evolution is possible
        public virtual bool CanEvolve(ItemData.Evolution evolution, int levelUpAmount = 1)
        {
            // Cannot evolve if the item hasnt reached the level to evolve
            if (evolution.evolutionLevel > currentLevel + levelUpAmount)
            {
                Debug.LogWarning(string.Format("Evolution Failed. Current level {0}, evolution level {1}", currentLevel, evolution.evolutionLevel));
                return false;
            }
            // Checks to see if all the catalysts are in the inventory
    
            foreach(ItemData.Evolution.Config c in evolution.catalysts)
            {
                Item item = inventory.Get(c.itemType);
                print($"Trying to evolve {c.itemType}. Current level is {item.currentLevel} and requirement is {c.level}.");
                if (!item || item.currentLevel < c.level)
                {
                    Debug.LogWarning(string.Format("Evolution Failed. Missing {0}", c.itemType.name));
                    return false;
                }
            }
            return true;
        }
    
        // AttemptEvolution will spawn a new weapon for the character,a nd remove all the weapons that are supposed to be consumed
        public virtual bool AttemptEvolution(ItemData.Evolution evolutionData, int levelUpAmount = 1)
        {
            if(!CanEvolve(evolutionData, levelUpAmount))
                return false;
    
            // should passives/weapons be consumed?
            bool consumePassives = (evolutionData.consumes & ItemData.Evolution.Consumption.passives) > 0;
            bool consumeWeapons = (evolutionData.consumes & ItemData.Evolution.Consumption.weapons) > 0;
    
            // Loop through the catalysts and check if we should consume them
            foreach(ItemData.Evolution.Config c in evolutionData.catalysts)
            {
                if (c.itemType is PassiveData && consumePassives)
                    inventory.Remove(c.itemType, true);
    
                if (c.itemType is WeaponData && consumeWeapons)
                    inventory.Remove(c.itemType, true);
            }
    
            // Should we consume ourselves as well
            if (this is Passive && consumePassives)
                inventory.Remove((this as Passive).data, true);
    
            else if (this is Weapon && consumeWeapons)
                inventory.Remove((this as Weapon).data, true);
    
            // Ad the new weapon onto inventory
            inventory.Add(evolutionData.outcome.itemType);
    
            return true;
        }
    
        public virtual bool CanLevelUp()
        {
            return currentLevel <= maxLevel;
        }
    
        // Whenever an item levels up, attemp to evolve
        public virtual bool DoLevelUp()
        {
            if (evolutionData == null)
                return true;
            // Tries to evolve into every listed evolution of this weapon if the weapons evolution condition is levelinh ip
            foreach(ItemData.Evolution e in evolutionData)
            {
                if(e.condition == ItemData.Evolution.Condition.auto)
                    AttemptEvolution(e);
            }
            return true;
        }
    
        // What effects owner recieve on equiping an item
        public virtual void OnEquip() { }
    
    
        // What effects are removed on unequiping an utem
        public virtual void OnUnequip() { }
    
    }</code>
    #15992
    Terence
    Level 30
    Keymaster
    Helpful?
    Up
    0
    ::

    My bad, the null reference isn’t supposed to happen. It’s an oversight with my line of code. Can you move it into the if condition again and tell me what it prints?

        // Checks if a specific evolution is possible
        public virtual bool CanEvolve(ItemData.Evolution evolution, int levelUpAmount = 1)
        {
            // Cannot evolve if the item hasnt reached the level to evolve
            if (evolution.evolutionLevel > currentLevel + levelUpAmount)
            {
                Debug.LogWarning(string.Format("Evolution Failed. Current level {0}, evolution level {1}", currentLevel, evolution.evolutionLevel));
                return false;
            }
    
            // Checks to see if all the catalysts are in the inventory
            foreach(ItemData.Evolution.Config c in evolution.catalysts)
            {
                Item item = inventory.Get(c.itemType);
                print($"Trying to evolve {c.itemType}. Current level is {item.currentLevel} and requirement is {c.level}.");
                if(!item || item.currentLevel < c.level)
                {
                    print($"Trying to evolve {c.itemType}. Current level is {item.currentLevel} and requirement is {c.level}.");
                    Debug.LogWarning(string.Format("Evolution Failed. Missing {0}", c.itemType.name));
                    return false;
                }
            }
            return true;
        }
    #15993
    Grant Totinov
    Level 3
    Participant
    Helpful?
    Up
    0
    ::
    <code>NullReferenceException: Object reference not set to an instance of an object
    Item.CanEvolve (ItemData+Evolution evolution, System.Int32 levelUpAmount) (at Assets/Scripts/Passive Items/Item.cs:56)
    Item.AttemptEvolution (ItemData+Evolution evolutionData, System.Int32 levelUpAmount) (at Assets/Scripts/Passive Items/Item.cs:67)
    Item.DoLevelUp () (at Assets/Scripts/Passive Items/Item.cs:112)
    Weapon.DoLevelUp () (at Assets/Scripts/Weapons/Weapon.cs:90)
    AuraWeapon.DoLevelUp () (at Assets/Scripts/Weapons/AuraWeapon.cs:37)
    PlayerInventory.LevelUpWeapon (System.Int32 slotIndex, System.Int32 upgradeIndex) (at Assets/Scripts/Player/PlayerInventory.cs:266)
    PlayerInventory+<>c__DisplayClass21_1.<ApplyUpgradeOptions>b__1 () (at Assets/Scripts/Player/PlayerInventory.cs:349)
    UnityEngine.Events.InvokableCall.Invoke () (at <914d6100afbb4dcbb0365e05b2154b62>:0)
    UnityEngine.Events.UnityEvent.Invoke () (at <914d6100afbb4dcbb0365e05b2154b62>:0)
    UnityEngine.UI.Button.Press () (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Button.cs:70)
    UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Button.cs:114)
    UnityEngine.EventSystems.ExecuteEvents.Execute (UnityEngine.EventSystems.IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/ExecuteEvents.cs:57)
    UnityEngine.EventSystems.ExecuteEvents.Execute[T] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.ExecuteEvents+EventFunction1[T1] functor) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/ExecuteEvents.cs:272)
    UnityEngine.EventSystems.EventSystem:Update() (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/EventSystem.cs:514)</code>
    View post on imgur.com

    The same thing boss :(

    #15995
    Kai
    Level 13
    Bronze Supporter (Patron)
    Helpful?
    Up
    0
    ::

    Hi, I have the same problem, my pummarola is blocked from leveling up to lv2(max level to evolve), it popped up NullReferenceException when I try to select the upgrade. The error is at this line Item item = inventory.Get(c.itemType); Item.cs

    <code>
    using System.Collections.Generic;
    using UnityEngine;
    
    /// <summary>
    /// Base class for both the Passive and the Weapon classes. It is primarily intended
    /// to handle weapon evolution, as we want both weapons and passives to be evolve-able.
    /// </summary>
    public abstract class Item : MonoBehaviour
    {
        public int currentLevel = 1, maxLevel = 1;
        [HideInInspector] public ItemData data;
        protected ItemData.Evolution[] evolutionData;
        protected PlayerInventory inventory;
        protected PlayerStats owner;
    
        public PlayerStats Owner { get { return owner; } }
    
        [System.Serializable]
        public class LevelData
        {
            public string name, description;
        }
    
        public virtual void Initialise(ItemData data)
        {
            maxLevel = data.maxLevel;
    
            // Store the evolution data as we have to track whether
            // all the catalysts are in the inventory so we can evolve.
            evolutionData = data.evolutionData;
    
            // We have to find a better way to reference the player inventory
            // in future, as this is inefficient.
            inventory = GetComponentInParent<PlayerInventory>();
            owner = GetComponentInParent<PlayerStats>();
        }
    
        // Call this function to get all the evolutions that the weapon
        // can currently evolve to.
        public virtual ItemData.Evolution[] CanEvolve()
        {
            List<ItemData.Evolution> possibleEvolutions = new List<ItemData.Evolution>();
    
            // Check each listed evolution and whether it is in
            // the inventory.
            foreach (ItemData.Evolution e in evolutionData)
            {
                if (CanEvolve(e)) possibleEvolutions.Add(e);
            }
    
            return possibleEvolutions.ToArray();
        }
    
        // Checks if a specific evolution is possible.
        public virtual bool CanEvolve(ItemData.Evolution evolution, int levelUpAmount = 1)
        {
            // Cannot evolve if the item hasn't reached the level to evolve.
            if (evolution.evolutionLevel > currentLevel + levelUpAmount)
            {
                Debug.LogWarning(string.Format("Evolution failed. Current level {0}, evolution level {1}", currentLevel, evolution.evolutionLevel));
                return false;
            }
    
            // Checks to see if all the catalysts are in the inventory.
            foreach (ItemData.Evolution.Config c in evolution.catalysts)
            {
                Item item = inventory.Get(c.itemType);
                if (!item || item.currentLevel < c.level)
                {
    
                    Debug.LogWarning(string.Format("Evolution failed. Missing {0}", c.itemType.name));
                    return false;
                }
            }
    
            return true;
        }
    
        // AttemptEvolution will spawn a new weapon for the character, and remove all
        // the weapons that are supposed to be consumed.
        public virtual bool AttemptEvolution(ItemData.Evolution evolutionData, int levelUpAmount = 1)
        {
            if (!CanEvolve(evolutionData, levelUpAmount))
                return false;
    
            // Should we consume passives / weapons?
            bool consumePassives = (evolutionData.consumes & ItemData.Evolution.Consumption.passives) > 0;
            bool consumeWeapons = (evolutionData.consumes & ItemData.Evolution.Consumption.weapons) > 0;
    
            // Loop through all the catalysts and check if we should consume them.
            foreach (ItemData.Evolution.Config c in evolutionData.catalysts)
            {
                if (c.itemType is PassiveData && consumePassives) inventory.Remove(c.itemType, true);
                if (c.itemType is WeaponData && consumeWeapons) inventory.Remove(c.itemType, true);
            }
    
            // Should we consume ourselves as well?
            if (this is Passive && consumePassives) inventory.Remove((this as Passive).data, true);
            else if (this is Weapon && consumeWeapons) inventory.Remove((this as Weapon).data, true);
    
            // Add the new weapon onto our inventory.
            inventory.Add(evolutionData.outcome.itemType);
    
            return true;
        }
    
        public virtual bool CanLevelUp()
        {
            return currentLevel <= maxLevel;
        }
    
        // Whenever an item levels up, attempt to make it evolve.
        public virtual bool DoLevelUp()
        {
            if (evolutionData == null) return true;
    
            // Tries to evolve into every listed evolution of this weapon,
            // if the weapon's evolution condition is levelling up.
            foreach (ItemData.Evolution e in evolutionData)
            {
                if (e.condition == ItemData.Evolution.Condition.auto)
                    AttemptEvolution(e);
            }
            return true;
        }
    
        // What effects you receive on equipping an item.
        public virtual void OnEquip() { }
    
        // What effects are removed on unequipping an item.
        public virtual void OnUnequip() { }
    }
    </code>

    #15999
    Terence
    Level 30
    Keymaster
    Helpful?
    Up
    0
    ::

    It looks like inventory.Get() isn’t working properly. Can you add these messages onto the Get() function in your PlayerInventory script and test this again?

        // Find a passive of a certain type in the inventory
        public Passive Get(PassiveData type)
        {
            print("Calling Get() for Passive");
            foreach(Slot s in passiveSlots)
            {
                Passive p = s.item as Passive;
                if(p && p.data == type)
                    return p;
            }
            return null;
        }
    
        //Find a weapon of certain type in the inventory
        public Weapon Get(WeaponData type)
        {
            print("Calling Get() for Weapon");
            foreach (Slot s in weaponSlots)
            {
                Weapon w = s.item as Weapon;
                if (w && w.data == type)
                    return w;
            }
            return null;
        }
    
        public Item Get(ItemData type)
        {
            print("Calling Get() for with undetermined Item type");
            if(type is WeaponData)
                return Get(type as WeaponData);
    
            else if(type is PassiveData)
                return Get(type as PassiveData);
    
            return null;
        }
    
    #16002
    Terence
    Level 30
    Keymaster
    Helpful?
    Up
    0
    ::

    Kai, your issue seems to be different. It seems like your Item script is unable to find the PlayerInventory, causing the inventory variable to be null. That is why when you do inventory.Get(), you get a NullReferenceException.

    Make sure that your items are parented under the player GameObject, and that the PlayerInventory script is on the player GameObject, because the items use GetComponentInParent() to find the PlayerInventory script.

    #16009
    Grant Totinov
    Level 3
    Participant
    Helpful?
    Up
    0
    ::

    Hello boss. So i start the game as a Garlic character and the controller is set up right:

    View post on imgur.com

    After i kill the first enemy and player level goes to 2 and the Upgrade window shows up this is in console:

    After i pick Garlic Level 2 this shows up:

    After i get Pummarola the evolve doesnt happen and this shows up in the console:

    Heres the whole console if i get Garlic Level 1 > Garlic Level 2 > Pummarola Level 1 – the evolve doesnt happen:

    And heres the whole console if i go Garlic Level 1 > Pummarola Level 1 > Garlic Level 2 – the evolve does happen:

    I tried with more weapons but the result is the same if i go weapon first then passive the evolve doesnt happen. Here is the test with the knife. Im really demotivated rn. Trying to solve this for a weak :(

    Thank you for your time, and for trying helping me.

    #16013
    Terence
    Level 30
    Keymaster
    Helpful?
    Up
    0
    ::

    Do you mind sending your project files to me over Google Drive? I am streaming tomorrow and I can do the debugging on stream tomorrow so you can see how I find the issue, if you don’t mind. Zip up your Asset, ProjectSettings and Packages folder and share the zip using a Google Drive link.

    #16015
    Grant Totinov
    Level 3
    Participant
    Helpful?
    Up
    0
    ::

    My project

    It would be interresting watching the stream to see there did i screw up :). What timezone are you in boss?

    Also there is another problem that i cant deal with it. In Levelup screen when there is the upgrade option template. when there are 4 options, the top one is the template with the default text and images, and the other 3 are overrited with the correct item data. Idk why the template doenst show itemdata. If the upgrade options are 3, there is no such a problem.

Viewing 15 posts - 1 through 15 (of 16 total)
  • You must be logged in to reply to this topic.

Go to Login Page →


Advertisement below: