Forum begins after the advertisement:


[Part 10] – Struggling with getting listeners to work

Home Forums Video Game Tutorial Series Creating a Rogue-like Shoot-em Up in Unity [Part 10] – Struggling with getting listeners to work

Viewing 8 posts - 1 through 8 (of 8 total)
  • Author
    Posts
  • #18037
    Nathaniel
    Level 10
    Silver Supporter (Patron)
    Helpful?
    Up
    1
    ::

    Hi, I’m getting some weird errors half way through part 10. It appears my buttons are null despite being set in inspector.

    NullReferenceException: Object reference not set to an instance of an object
    InventoryManager.ApplyUpgradeOptions () (at Assets/Scripts/Player/InventoryManager.cs:154)
    InventoryManager.RemoveAndApplyUpgrades () (at Assets/Scripts/Player/InventoryManager.cs:211)
    GameManager.StartLevelUp () (at Assets/Scripts/GameManager.cs:235)
    PlayerStats.LevelUpChecker () (at Assets/Scripts/Player/PlayerStats.cs:216)
    PlayerStats.IncreaseExperience (System.Int32 amount) (at Assets/Scripts/Player/PlayerStats.cs:195)
    Exp.Collect () (at Assets/Scripts/Pickups/Exp.cs:11)
    PlayerCollector.OnTriggerEnter2D (UnityEngine.Collider2D col) (at Assets/Scripts/Player/PlayerCollector.cs:28)

    My inventory manager code:

    using System.Collections.Generic;
    using TMPro;
    using UnityEngine;
    using UnityEngine.UI;
    
    
    public class InventoryManager : MonoBehaviour
    {
        public List<WeaponController> weaponSlots = new List<WeaponController>(6);
        public int [] weaponLevels = new int[6];
        public List<Image> weaponUISlots = new List<Image>(6);
        public List<PassiveItem> passiveItemSlots = new List<PassiveItem>(6);
        public int [] passiveItemLevels = new int[6];
        public List<Image> passiveItemUISlots = new List<Image>(6);
    
        [System.Serializable]
        public class WeaponUpgrade
        {
            public GameObject initalWeapon;
            public WeaponsScriptableObject weaponData;
        }
    
        [System.Serializable]
        public class PassiveItemUpgrade
        {
            public GameObject initalPassiveItem;
            public PassiveItemScriptableObject passiveItemData;
        }
    
        [System.Serializable]
        public class UpgradeUI
        {
            public TextMeshProUGUI upgradeNameDisplay;
            public TextMeshProUGUI upgradeDescriptionDisplay;
            public Image upgradeIcon;
            public UnityEngine.UI.Button upgradeButton;
        }
    
        public List<WeaponUpgrade>weaponUpgradeOptions = new();
        public List<PassiveItemUpgrade>passiveItemUpgradeOptions = new();
        public List<UpgradeUI> upgradeUIOptions = new();
    
        PlayerStats player;
    
        void Start()
        {
            player = GetComponent<PlayerStats>();
        }
    
        public void AddWeapon(int slotIndex, WeaponController weapon)
        {
            weaponSlots[slotIndex] = weapon;
            weaponLevels[slotIndex] = weapon.weaponData.Level;
            weaponUISlots[slotIndex].enabled = true;
            weaponUISlots[slotIndex]. sprite = weapon.weaponData.Icon;
    
            if (GameManager.instance != null && GameManager.instance.isChoosingUpgrade)
            {
                GameManager.instance.EndLevelUp();
            }
        }
    
        public void AddPassiveItem(int slotIndex, PassiveItem passiveItem)
        {
            passiveItemSlots[slotIndex] = passiveItem;
            passiveItemLevels[slotIndex] = passiveItem.passiveItemData.Level;
            passiveItemUISlots[slotIndex].enabled = true;
            passiveItemUISlots[slotIndex]. sprite = passiveItem.passiveItemData.Icon;
    
            if (GameManager.instance != null && GameManager.instance.isChoosingUpgrade)
            {
                GameManager.instance.EndLevelUp();
            }
        } 
    
        public void LevelUpWeapon(int slotIndex)
        {
            if (weaponSlots.Count > slotIndex)
            {
                WeaponController weapon = weaponSlots[slotIndex];
                if (!weapon.weaponData.NextLevelPrefab)
                {
                    Debug.LogError("No next level for " + weapon.name);
                    return;
                }
                GameObject upgradedWeapon = Instantiate(weapon.weaponData.NextLevelPrefab, transform.position, Quaternion.identity);
                upgradedWeapon.transform.SetParent(transform);
                AddWeapon(slotIndex, upgradedWeapon.GetComponent<WeaponController>());
                Destroy(weapon.gameObject);
                weaponLevels[slotIndex] = upgradedWeapon.GetComponent<WeaponController>().weaponData.Level;
            }
    
            if (GameManager.instance != null && GameManager.instance.isChoosingUpgrade)
            {
                GameManager.instance.EndLevelUp();
            }
        }
    
        public void LevelUpPassiveItem(int slotIndex)
        {
            if (passiveItemSlots.Count > slotIndex)
            {
                PassiveItem passiveItem = passiveItemSlots[slotIndex];
                if (!passiveItem.passiveItemData.NextLevelPrefab)
                {
                    Debug.LogError("No next level for " + passiveItem.name);
                    return;
                }
                GameObject upgradedPassiveItem = Instantiate(passiveItem.passiveItemData.NextLevelPrefab, transform.position, Quaternion.identity);
                upgradedPassiveItem.transform.SetParent(transform);
                AddPassiveItem(slotIndex, upgradedPassiveItem.GetComponent<PassiveItem>());
                Destroy(passiveItem.gameObject);
                passiveItemLevels[slotIndex] = upgradedPassiveItem.GetComponent<PassiveItem>().passiveItemData.Level;
            }
    
            if (GameManager.instance != null && GameManager.instance.isChoosingUpgrade)
            {
                GameManager.instance.EndLevelUp();
            }
        }
    
        void ApplyUpgradeOptions()
        {
            foreach (var upgradeOption in upgradeUIOptions)
            {
                int upgradeType = Random.Range(1, 3);
                if (upgradeType == 1)
                {
                    WeaponUpgrade chosenWeaponUpgrade = weaponUpgradeOptions[Random.Range(0, weaponUpgradeOptions.Count)];
    
                    if (chosenWeaponUpgrade != null)
                    {
                        bool newWeapon = false;
                        for (int i = 0; i < weaponSlots.Count; i++)
                        {
                            if (weaponSlots[i] != null && weaponSlots[i].weaponData == chosenWeaponUpgrade.weaponData)
                            {
                                newWeapon = false;
                                if (!newWeapon)
                                {
                                    upgradeOption.upgradeButton.onClick.AddListener(() => LevelUpWeapon(i));
                                    upgradeOption.upgradeNameDisplay.text = chosenWeaponUpgrade.weaponData.NextLevelPrefab.GetComponent<WeaponController>().weaponData.Name;
                                    upgradeOption.upgradeDescriptionDisplay.text = chosenWeaponUpgrade.weaponData.NextLevelPrefab.GetComponent<WeaponController>().weaponData.Description;                  
                                }
                                break;
                            }
                            else
                            {
                                newWeapon = true;
                            }
                        }
                        if (newWeapon)
                        {
                            upgradeOption.upgradeButton.onClick.AddListener(() => player.SpawnWeapon(chosenWeaponUpgrade.initalWeapon));
                            upgradeOption.upgradeNameDisplay.text = chosenWeaponUpgrade.weaponData.Name;
                            upgradeOption.upgradeDescriptionDisplay.text = chosenWeaponUpgrade.weaponData.Description;
                        }
    
                        upgradeOption.upgradeIcon.sprite = chosenWeaponUpgrade.weaponData.Icon;
                    }
                }
                else if (upgradeType == 2)
                {
                    PassiveItemUpgrade chosenPassiveItemUpgrade = passiveItemUpgradeOptions[Random.Range(0, passiveItemUpgradeOptions.Count)];
    
                    if (chosenPassiveItemUpgrade != null)
                    {
                        bool newPassiveItem = false;
                        for (int i = 0; i < passiveItemSlots.Count; i++)
                        {
                            if (passiveItemSlots[i] != null && passiveItemSlots[i].passiveItemData == chosenPassiveItemUpgrade.passiveItemData)
                            {
                                newPassiveItem = false;
                                if (!newPassiveItem)
                                {
                                    upgradeOption.upgradeButton.onClick.AddListener(() => LevelUpPassiveItem(i));
                                    upgradeOption.upgradeNameDisplay.text = chosenPassiveItemUpgrade.passiveItemData.NextLevelPrefab.GetComponent<PassiveItem>().passiveItemData.Name;
                                    upgradeOption.upgradeDescriptionDisplay.text = chosenPassiveItemUpgrade.passiveItemData.NextLevelPrefab.GetComponent<PassiveItem>().passiveItemData.Description;
                                }
                                break;
                            }
                            else
                            {
                                newPassiveItem = true;
                            }
                        }
                        if (newPassiveItem)
                        {
                            upgradeOption.upgradeButton.onClick.AddListener(() => player.SpawnPassiveItem(chosenPassiveItemUpgrade.initalPassiveItem));
                            upgradeOption.upgradeNameDisplay.text = chosenPassiveItemUpgrade.passiveItemData.Name;
                            upgradeOption.upgradeDescriptionDisplay.text = chosenPassiveItemUpgrade.passiveItemData.Description;
                        }
    
                        upgradeOption.upgradeIcon.sprite = chosenPassiveItemUpgrade.passiveItemData.Icon;
                    }
                }
            }
        }
    
        void RemoveUpgradeOptions()
        {
            foreach (var upgradeOption in upgradeUIOptions)
            {
                //upgradeOption.upgradeButton.onClick.RemoveAllListeners();
            }
        }
    
        public void RemoveAndApplyUpgrades()
        {
            RemoveUpgradeOptions();
            ApplyUpgradeOptions();
        }
    }

    I put some debug prompts in:

    private void RemoveUpgradeOptions()
    {
        if (upgradeUIOptions == null)
        {
            Debug.LogError("[InventoryManager] upgradeUIOptions list itself is NULL!");
            return;
        }
    
        for (int i = 0; i < upgradeUIOptions.Count; i++)
        {
            var option = upgradeUIOptions[i];
            if (option == null)
            {
                Debug.LogError($"[InventoryManager] upgradeUIOptions[{i}] is null—no UpgradeUI object at that index!");
                continue;
            }
    
            if (option.upgradeButton == null)
            {
                Debug.LogError($"[InventoryManager] upgradeUIOptions[{i}].upgradeButton is null!");
                continue;
            }
    
            // Safe to remove listeners now
            option.upgradeButton.onClick.RemoveAllListeners();
            Debug.Log($"[InventoryManager] Cleared listeners on upgradeUIOptions[{i}].upgradeButton");
        }
    }

    It returned:

    [InventoryManager] upgradeUIOptions[0].upgradeButton is null!
    UnityEngine.Debug:LogError (object)
    InventoryManager:RemoveUpgradeOptions () (at Assets/Scripts/Player/InventoryManager.cs:219)
    InventoryManager:RemoveAndApplyUpgrades () (at Assets/Scripts/Player/InventoryManager.cs:231)
    GameManager:StartLevelUp () (at Assets/Scripts/GameManager.cs:235)
    PlayerStats:LevelUpChecker () (at Assets/Scripts/Player/PlayerStats.cs:216)
    PlayerStats:IncreaseExperience (int) (at Assets/Scripts/Player/PlayerStats.cs:195)
    Exp:Collect () (at Assets/Scripts/Pickups/Exp.cs:11)
    PlayerCollector:OnTriggerEnter2D (UnityEngine.Collider2D) (at Assets/Scripts/Player/PlayerCollector.cs:28)
    
    [InventoryManager] upgradeUIOptions[1].upgradeButton is null!
    UnityEngine.Debug:LogError (object)
    InventoryManager:RemoveUpgradeOptions () (at Assets/Scripts/Player/InventoryManager.cs:219)
    InventoryManager:RemoveAndApplyUpgrades () (at Assets/Scripts/Player/InventoryManager.cs:231)
    GameManager:StartLevelUp () (at Assets/Scripts/GameManager.cs:235)
    PlayerStats:LevelUpChecker () (at Assets/Scripts/Player/PlayerStats.cs:216)
    PlayerStats:IncreaseExperience (int) (at Assets/Scripts/Player/PlayerStats.cs:195)
    Exp:Collect () (at Assets/Scripts/Pickups/Exp.cs:11)
    PlayerCollector:OnTriggerEnter2D (UnityEngine.Collider2D) (at Assets/Scripts/Player/PlayerCollector.cs:28)
    
    [InventoryManager] upgradeUIOptions[2].upgradeButton is null!
    UnityEngine.Debug:LogError (object)
    InventoryManager:RemoveUpgradeOptions () (at Assets/Scripts/Player/InventoryManager.cs:219)
    InventoryManager:RemoveAndApplyUpgrades () (at Assets/Scripts/Player/InventoryManager.cs:231)
    GameManager:StartLevelUp () (at Assets/Scripts/GameManager.cs:235)
    PlayerStats:LevelUpChecker () (at Assets/Scripts/Player/PlayerStats.cs:216)
    PlayerStats:IncreaseExperience (int) (at Assets/Scripts/Player/PlayerStats.cs:195)
    Exp:Collect () (at Assets/Scripts/Pickups/Exp.cs:11)
    PlayerCollector:OnTriggerEnter2D (UnityEngine.Collider2D) (at Assets/Scripts/Player/PlayerCollector.cs:28)
    
    [InventoryManager] upgradeUIOptions[3].upgradeButton is null!
    UnityEngine.Debug:LogError (object)
    InventoryManager:RemoveUpgradeOptions () (at Assets/Scripts/Player/InventoryManager.cs:219)
    InventoryManager:RemoveAndApplyUpgrades () (at Assets/Scripts/Player/InventoryManager.cs:231)
    GameManager:StartLevelUp () (at Assets/Scripts/GameManager.cs:235)
    PlayerStats:LevelUpChecker () (at Assets/Scripts/Player/PlayerStats.cs:216)
    PlayerStats:IncreaseExperience (int) (at Assets/Scripts/Player/PlayerStats.cs:195)
    Exp:Collect () (at Assets/Scripts/Pickups/Exp.cs:11)
    PlayerCollector:OnTriggerEnter2D (UnityEngine.Collider2D) (at Assets/Scripts/Player/PlayerCollector.cs:28)

    Any help would be appreciated!

      1 anonymous person
    has upvoted this post.
    #18038
    Alp Apustaja
    Level 7
    AI Assistant
    (BETA)
    Helpful?
    Up
    1
    ::

    Based on the reference information and the code provided, the issue is likely that the upgradeUIOptions list is not being populated correctly in the Inspector.

    To resolve this:

    1. Ensure that in the Unity Inspector, you have manually assigned the UI elements to the upgradeUIOptions list for the InventoryManager component.

    2. Double-check that each UpgradeUI object in the list has its upgradeButton properly assigned.

    3. Add a debug method in Start() to verify the list is populated:

    void Start()
    {
        player = GetComponent();
    
        // Debug check
        Debug.Log($"UpgradeUI Options Count: {upgradeUIOptions.Count}");
        foreach (var option in upgradeUIOptions)
        {
            if (option.upgradeButton == null)
            {
                Debug.LogError("Upgrade button is null!");
            }
        }
    }

    Would you like me to clarify how to properly set up the upgrade UI options in the Inspector?

      1 anonymous person
    has upvoted this post.
    #18039
    Nathaniel
    Level 10
    Silver Supporter (Patron)
    Helpful?
    Up
    1
    ::

    Inspector is definitely correct, I have reset and repopulated it many times now.

    It’s worth mentioning in my GameManager.cs I had to change the SendMessage() to:

       public void StartLevelUp()
        {
            ChangeState(GameState.LevelUp);
            playerObject.GetComponent<InventoryManager>()?.RemoveAndApplyUpgrades();
        }

    Send message was not working for me.

    SendMessage RemoveAndApplyUpgrades has no receiver!
    UnityEngine.GameObject:SendMessage (string)
    GameManager:StartLevelUp () (at Assets/Scripts/GameManager.cs:235)
    PlayerStats:LevelUpChecker () (at Assets/Scripts/Player/PlayerStats.cs:216)
    PlayerStats:IncreaseExperience (int) (at Assets/Scripts/Player/PlayerStats.cs:195)
    Exp:Collect () (at Assets/Scripts/Pickups/Exp.cs:11)
    PlayerCollector:OnTriggerEnter2D (UnityEngine.Collider2D) (at Assets/Scripts/Player/PlayerCollector.cs:28)
      1 anonymous person
    has upvoted this post.
    #18040
    Alp Apustaja
    Level 7
    AI Assistant
    (BETA)
    Helpful?
    Up
    1
    ::

    Thank you for the clarification! Given that the Inspector setup is confirmed correct and you’re using GetComponent instead of SendMessage, it’s crucial to ensure that the playerObject is indeed the correct GameObject that contains the InventoryManager component.

    Here are a few additional steps to troubleshoot:

    1. Check playerObject Assignment: Verify that playerObject is assigned correctly in the GameManager script. If it’s null or not the right GameObject, GetComponent() will return null.

    2. Debugging playerObject: Add a debug log to ensure playerObject is not null and is the expected GameObject:

       public void StartLevelUp()
       {
           ChangeState(GameState.LevelUp);
      
           if (playerObject == null)
           {
               Debug.LogError("playerObject is null!");
               return;
           }
      
           Debug.Log($"Starting level up for: {playerObject.name}");
           playerObject.GetComponent()?.RemoveAndApplyUpgrades();
       }
    3. Verify GameObject Hierarchy: Ensure that playerObject actually has the InventoryManager component attached. You can do this by checking the GameObject hierarchy in the Unity Editor.

    4. Check for Multiple Instances: Ensure that there are not multiple instances of InventoryManager in your scene, as this may lead to unexpected behavior.

    5. Null Checks in RemoveAndApplyUpgrades: Add null checks before calling RemoveAndApplyUpgrades in case the InventoryManager component is not found:

       var inventoryManager = playerObject.GetComponent();
       if (inventoryManager != null)
       {
           inventoryManager.RemoveAndApplyUpgrades();
       }
       else
       {
           Debug.LogError("InventoryManager component not found on playerObject!");
       }

    Try these suggestions and let me know if anything changes or if you encounter any new errors!

      1 anonymous person
    has upvoted this post.
    #18041
    Nathaniel
    Level 10
    Silver Supporter (Patron)
    Helpful?
    Up
    1
    ::

    I’ve done some more debugging and I think I’ve narrowed it down to I’m not getting the player object hence no no way to remove and apply upgrades.

      1 anonymous person
    has upvoted this post.
    #18042
    Alp Apustaja
    Level 7
    AI Assistant
    (BETA)
    Helpful?
    Up
    1
    ::

    Based on the limited information provided, it seems like the core issue is that the player object is not being correctly retrieved or assigned in the GameManager script.

    To help diagnose this, could you share:

    1. How are you currently trying to get the player object?
    2. Can you show the relevant code in your GameManager script where you’re attempting to access the player object?
    3. In your scene hierarchy, what is the name and structure of the GameObject that represents the player?
      1 anonymous person
    has upvoted this post.
    #18045
    Nathaniel
    Level 10
    Silver Supporter (Patron)
    Helpful?
    Up
    1
    ::

    I fixed it!

    I was either spelling the SendMessage call function wrong or didn’t assign the player correctly. Between those two things it seems to be working now.

    This is why we don’t stay up till 4AM coding haha.

      1 anonymous person
    has upvoted this post.
    #18046
    Alp Apustaja
    Level 7
    AI Assistant
    (BETA)
    Helpful?
    Up
    0
    ::

    Great job solving the issue! It’s always satisfying to track down and fix a tricky bug. And you’re absolutely right – late-night coding can lead to subtle mistakes that are hard to spot.

    Would you like to share more details about what specifically you changed to resolve the player object and SendMessage issues?

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

Go to Login Page →


Advertisement below: