Forum begins after the advertisement:


[Part 15] Weapon and passive exceeding maximum slots

Home Forums Video Game Tutorial Series Creating a Rogue-like Shoot-em Up in Unity [Part 15] Weapon and passive exceeding maximum slots

Viewing 11 posts - 1 through 11 (of 11 total)
  • Author
    Posts
  • #13566
    Cam
    Silver Supporter (Patron)

    hey guys been loving these videos
    don’t know if its just me or its broken but I’ve added a bunch of weapons and passives but now when i get to have all six weapon or passive slots full I’m still getting the choice of choosing a new weapon/passive even though the slots are full braking the game by locking it down with not being able to choose an upgrade

    #13574
    Terence
    Keymaster

    Hi Cameron, thank you for highlighting this. It is a known bug. I’ll be addressing this in the live stream next week and releasing a short video shortly after to address and fix this.

    I’ve also moved your message to our Vampire Survivors forum.

    Thank you for your Patron support as well!

    #13579
    Cam
    Silver Supporter (Patron)

    Thanks Terence been loving your work
    maybe oneday ill be home for your live streams <3

    #13580
    Cam
    Silver Supporter (Patron)

    another thing im having happen is with the aura weapons if i change the prefab on a level up its not loading the the new prefab

    ie Garlic level 1-4 is the same prefab like yours but at level 5 ive had it change to a new style(prefab) its not updating

    #13581
    Terence
    Keymaster

    another thing im having happen is with the aura weapons if i change the prefab on a level up its not loading the the new prefab

    ie Garlic level 1-4 is the same prefab like yours but at level 5 ive had it change to a new style(prefab) its not updating

    That’s a great spot Cameron. Can you add a call to OnEquip() on DoLevelUp() and let me know if it works? This forces the level up to refresh the aura.

        public override bool DoLevelUp()
        {
            if (!base.DoLevelUp()) return false;
    
            // If there is an aura attached to this weapon, we update the aura.
            if (currentAura)
            {
                OnEquip();
                currentAura.transform.localScale = new Vector3(currentStats.area, currentStats.area, currentStats.area);
            }
            return true;
        }

    Thanks Terence been loving your work
    maybe oneday ill be home for your live streams <3

    Really appreciate your support my friend :)

    #13582
    Terence
    Keymaster

    By the way, I’ve awarded you 2 bug reporter badges on your profile. Thanks again for highlighting them!

    #13583
    Cam
    Silver Supporter (Patron)

    Thanks Heaps bro.
    yes and no works kind of. It brings in the new prefab but dosnt remove the old on

    #13584
    Terence
    Keymaster

    How about if you put OnEquip() outside the conditional?

    public override bool DoLevelUp()
    {
        if (!base.DoLevelUp()) return false;
    
        OnEquip();
    
        // If there is an aura attached to this weapon, we update the aura.
        if (currentAura)
        {
            OnEquip();
            currentAura.transform.localScale = new Vector3(currentStats.area, currentStats.area, currentStats.area);
        }
        return true;
    }
    #13593
    Cam
    Silver Supporter (Patron)

    its changed my prefab so not sure if its removing the old prefab before loading in the new one buts its defiantly working some what the new weapon works

    #13596
    Terence
    Keymaster

    That’s great Cam. I’ll have a fix for the weapon and passive exceeding maximum slots soon.

    #13636
    Terence
    Keymaster

    This is the fix to prevent new weapons / passives from showing up if we have already reached the maximum number of slots. The PlayerInventory code is where we left off from Part 18, but it should work for you if your code is at Part 16 at least.

    using System;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using TMPro;
    
    public class PlayerInventory : MonoBehaviour
    {
        [System.Serializable]
        public class Slot
        {
            public Item item;
            public Image image;
    
            public void Assign(Item assignedItem)
            {
                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 List<Slot>(6);
        public List<Slot> passiveSlots = new List<Slot>(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> availableWeapons = new List<WeaponData>();    //List of upgrade options for weapons
        public List<PassiveData> availablePassives = new List<PassiveData>(); //List of upgrade options for passive items
        public List<UpgradeUI> upgradeUIOptions = new List<UpgradeUI>();    //List of ui for upgrade options present in the scene
    
        PlayerStats player;
    
        void Start()
        {
            player = GetComponent<PlayerStats>();
        }
    
        // Checks if the inventory has an item of a certain 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 && p.data == type)
                    return p;
            }
            return null;
        }
    
        // Find a weapon of a 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 .
        public bool Remove(WeaponData data, bool removeUpgradeAvailability = false)
        {
            // Remove this weapon from the upgrade pool.
            if (removeUpgradeAvailability) availableWeapons.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 .
        public bool Remove(PassiveData data, bool removeUpgradeAvailability = false)
        {
            // Remove this passive from the upgrade pool.
            if (removeUpgradeAvailability) availablePassives.Remove(data);
    
            for (int i = 0; i < weaponSlots.Count; i++)
            {
                Passive p = weaponSlots[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.
        // We also have an optional boolean to remove this item from the upgrade list.
        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 weapon of a 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 there is 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 GameObject(data.baseStats.name + " Controller");
                Weapon spawnedWeapon = (Weapon)go.AddComponent(weaponType);
                spawnedWeapon.transform.SetParent(transform); //Set the weapon to be a child of the player
                spawnedWeapon.transform.localPosition = Vector2.zero;
                spawnedWeapon.Initialise(data);
                spawnedWeapon.OnEquip();
    
                // Assign the weapon to the slot.
                weaponSlots[slotNum].Assign(spawnedWeapon);
    
                // Close the level up 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 there is no empty slot, exit.
            if (slotNum < 0) return slotNum;
    
            // Otherwise create the passive in the slot.
            // Get the type of the passive we want to spawn.
            GameObject go = new GameObject(data.baseStats.name + " Passive");
            Passive p = go.AddComponent<Passive>();
            p.Initialise(data);
            p.transform.SetParent(transform); //Set the weapon to be a child of the player
            p.transform.localPosition = Vector2.zero;
    
            // Assign the passive to the slot.
            passiveSlots[slotNum].Assign(p);
    
            if (GameManager.instance != null && GameManager.instance.choosingUpgrade)
            {
                GameManager.instance.EndLevelUp();
            }
            player.RecalculateStats();
    
            return slotNum;
        }
    
        // If we don't 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)
        {
            // Don't level up the weapon if it is already at max level.
            if (weaponSlots.Count > slotIndex)
            {
                Weapon weapon = weaponSlots[slotIndex].item as Weapon;
                if (!weapon.DoLevelUp())
                {
                    Debug.LogWarning(string.Format(
                        "Failed to level up {0}.",
                        weapon.name
                    ));
                    return;
                }
            }
        }
    
        // Overload so that we can use both ItemData or Item to level up an
        // item in the inventory.
        public bool LevelUp(ItemData data)
        {
            Item item = Get(data);
            if (item) return LevelUp(item);
            return false;
        }
    
        // Levels up a selected weapon in the player inventory.
        public bool LevelUp(Item item)
        {
            // Tries to level up the item.
            if(!item.DoLevelUp())
            {
                Debug.LogWarning(string.Format(
                    "Failed to level up {0}.",
                     item.name
                ));
                return false;
            }
    
            // Close the level up screen afterwards.
            if (GameManager.instance != null && GameManager.instance.choosingUpgrade)
            {
                GameManager.instance.EndLevelUp();
            }
    
            // If it is a passive, recalculate player stats.
            if(item is Passive) player.RecalculateStats();
            return true;
        }
    
        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();
        }
    
        // Checks a list of slots to see if there are any slots left.
        int GetSlotsLeft(List<Slot> slots)
        {
            
            int count = 0;
            foreach(Slot s in slots)
            {
                if (s.IsEmpty()) count++;
            }
            return count;
        }
    
        // Determines what upgrade options should appear.
        void ApplyUpgradeOptions()
        {
            // Make a duplicate of the available weapon / passive upgrade lists
            // so we can iterate through them in the function.
            List<WeaponData> availableWeaponUpgrades = new List<WeaponData>(availableWeapons);
            List<PassiveData> availablePassiveItemUpgrades = new List<PassiveData>(availablePassives);
    
            // Iterate through each slot in the upgrade UI.
            foreach (UpgradeUI upgradeOption in upgradeUIOptions)
            {
                // If there are no more avaiable upgrades, then we abort.
                if (availableWeaponUpgrades.Count == 0 && availablePassiveItemUpgrades.Count == 0)
                    return;
    
                // Determine whether this upgrade should be for passive or active weapons.
                int upgradeType;
                if (availableWeaponUpgrades.Count == 0)
                {
                    upgradeType = 2;
                }
                else if (availablePassiveItemUpgrades.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, then remove it so that we don't get it twice.
                    WeaponData chosenWeaponUpgrade = availableWeaponUpgrades[UnityEngine.Random.Range(0, availableWeaponUpgrades.Count)];
                    availableWeaponUpgrades.Remove(chosenWeaponUpgrade);
    
                    // Ensure that the selected weapon data is valid.
                    if (chosenWeaponUpgrade != null)
                    {
                        // Turns on the UI slot.
                        EnableUpgradeUI(upgradeOption);
    
                        // Loops through all our existing weapons. If we find a match, we will
                        // hook an event listener to the button that will level up the weapon
                        // when this 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 the 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)); //Apply button functionality
                                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 we will be adding a new weapon, instead of
                        // upgrading an existing weapon.
                        if (!isLevelUp)
                        {
                            upgradeOption.upgradeButton.onClick.AddListener(() => Add(chosenWeaponUpgrade)); //Apply button functionality
                            upgradeOption.upgradeDescriptionDisplay.text = chosenWeaponUpgrade.baseStats.description;  //Apply initial description
                            upgradeOption.upgradeNameDisplay.text = chosenWeaponUpgrade.baseStats.name;    //Apply initial name
                            upgradeOption.upgradeIcon.sprite = chosenWeaponUpgrade.icon;
                        }
                    }
                }
                else if (upgradeType == 2)
                {
                    // NOTE: We have to recode this system, as right now it disables an upgrade slot if
                    // we hit a weapon that has already reached max level.
                    PassiveData chosenPassiveUpgrade = availablePassiveItemUpgrades[UnityEngine.Random.Range(0, availablePassiveItemUpgrades.Count)];
                    availablePassiveItemUpgrades.Remove(chosenPassiveUpgrade);
    
                    if (chosenPassiveUpgrade != null)
                    {
                        // Turns on the UI slot.
                        EnableUpgradeUI(upgradeOption);
    
                        // Loops through all our existing passive. If we find a match, we will
                        // hook an event listener to the button that will level up the weapon
                        // when this upgrade option is clicked.
                        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 the max level, do not allow upgrade.
                                if (chosenPassiveUpgrade.maxLevel <= p.currentLevel)
                                {
                                    DisableUpgradeUI(upgradeOption);
                                    isLevelUp = true;
                                    break;
                                }
                                upgradeOption.upgradeButton.onClick.AddListener(() => LevelUpPassiveItem(i, i)); //Apply button functionality
                                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)); //Apply button functionality
                            Passive.Modifier nextLevel = chosenPassiveUpgrade.baseStats;
                            upgradeOption.upgradeDescriptionDisplay.text = nextLevel.description;  //Apply initial description
                            upgradeOption.upgradeNameDisplay.text = nextLevel.name;  //Apply initial name
                            upgradeOption.upgradeIcon.sprite = chosenPassiveUpgrade.icon;
                        }
                    }
                }
            }
        }
    
        // Determines what upgrade options should appear.
        void ApplyUpgradeOptions()
        {
            //  is the list of possible upgrades that we will populate from
            // , which is a list of all available weapons and passives.
            List<ItemData> availableUpgrades = new List<ItemData>(availableWeapons.Count + availablePassives.Count);
            List<ItemData> allPossibleUpgrades = new List<ItemData>(availableWeapons);
            allPossibleUpgrades.AddRange(availablePassives);
    
            // We need to know how many weapon / passive slots are left.
            int weaponSlotsLeft = GetSlotsLeft(weaponSlots);
            int passiveSlotsLeft = GetSlotsLeft(passiveSlots);
    
            // Filters through the available weapons and passives and add those
            // that can possibly be an option.
            foreach(ItemData data in allPossibleUpgrades)
            {
                // If a weapon of this type exists, allow for the upgrade if the
                // level of the weapon is not already maxed out.
                Item obj = Get(data);
                if(obj)
                {
                    if (obj.currentLevel < data.maxLevel) availableUpgrades.Add(data);
                }
                else
                {
                    // If we don't have this item in the inventory yet, check if
                    // we still have enough slots to take new items.
                    if (data is WeaponData && weaponSlotsLeft > 0) availableUpgrades.Add(data);
                    else if (data is PassiveData && passiveSlotsLeft > 0) availableUpgrades.Add(data);
                }
            }
    
            // Iterate through each slot in the upgrade UI and populate the options.
            foreach (UpgradeUI upgradeOption in upgradeUIOptions)
            {
                // If there are no more available upgrades, then we abort.
                if (availableUpgrades.Count <= 0) return;
    
                // Pick an upgrade, then remove it so that we don't get it twice.
                ItemData chosenUpgrade = availableUpgrades[UnityEngine.Random.Range(0, availableUpgrades.Count)];
                availableUpgrades.Remove(chosenUpgrade);
    
                // Ensure that the selected weapon data is valid.
                if (chosenUpgrade != null)
                {
                    // Turns on the UI slot.
                    EnableUpgradeUI(upgradeOption);
    
                    // If our inventory already has the upgrade, we will make it a level up.
                    Item item = Get(chosenUpgrade);
                    if(item)
                    {
                        upgradeOption.upgradeButton.onClick.AddListener(() => LevelUp(item)); //Apply button functionality
                        if (item is Weapon)
                        {
                            Weapon.Stats nextLevel = ((WeaponData)chosenUpgrade).GetLevelData(item.currentLevel + 1);
                            upgradeOption.upgradeDescriptionDisplay.text = nextLevel.description;
                            upgradeOption.upgradeNameDisplay.text = chosenUpgrade.name + " - " + nextLevel.name;
                            upgradeOption.upgradeIcon.sprite = chosenUpgrade.icon;
                        }
                        else
                        {
                            Passive.Modifier nextLevel = ((PassiveData)chosenUpgrade).GetLevelData(item.currentLevel + 1);
                            upgradeOption.upgradeDescriptionDisplay.text = nextLevel.description;
                            upgradeOption.upgradeNameDisplay.text = chosenUpgrade.name + " - " + nextLevel.name;
                            upgradeOption.upgradeIcon.sprite = chosenUpgrade.icon;
                        }
                    }
                    else
                    {
                        if(chosenUpgrade is WeaponData)
                        {
                            WeaponData data = chosenUpgrade as WeaponData;
                            upgradeOption.upgradeButton.onClick.AddListener(() => Add(chosenUpgrade)); //Apply button functionality
                            upgradeOption.upgradeDescriptionDisplay.text = data.baseStats.description;  //Apply initial description
                            upgradeOption.upgradeNameDisplay.text = data.baseStats.name;    //Apply initial name
                            upgradeOption.upgradeIcon.sprite = data.icon;
                        }
                        else
                        {
                            PassiveData data = chosenUpgrade as PassiveData;
                            upgradeOption.upgradeButton.onClick.AddListener(() => Add(chosenUpgrade)); //Apply button functionality
                            upgradeOption.upgradeDescriptionDisplay.text = data.baseStats.description;  //Apply initial description
                            upgradeOption.upgradeNameDisplay.text = data.baseStats.name;    //Apply initial name
                            upgradeOption.upgradeIcon.sprite = data.icon;
                        }
                        
                    }
                }
            }
        }
    
        void RemoveUpgradeOptions()
        {
            foreach (UpgradeUI upgradeOption in upgradeUIOptions)
            {
                upgradeOption.upgradeButton.onClick.RemoveAllListeners();
                DisableUpgradeUI(upgradeOption);    //Call the DisableUpgradeUI method here to disable all UI options before applying upgrades to them
            }
        }
    
        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);
        }
    
    }

    A summary of the changes:

    1. Main change is with ApplyUpgradeOptions(). I added a new version of it that scans through all available upgrade options and removes unsuitable upgrades, instead of the old version which just considers all upgrades as suitable without checking (which is what causes the bugs).
    2. There is a new LevelUp() function which works for both weapons and passives, replacing LevelUpWeapon() and LevelUpPassive().
    3. Some bugfixes for the Get() functions for both weapons and passives.
Viewing 11 posts - 1 through 11 (of 11 total)
  • You must be logged in to reply to this topic.

Go to Login Page →


Advertisement below: