Unity RPG Offhand/Shield equipment slot (W/ added Dual Wielding)

,

That would do it. Good job getting that sorted!

2 Likes

I’ll leave a note here to other people so that the shield cannot be equipped with dual weapons…(EquipmentSlotUI.cs) Just had to copy the solution for two-handed weapons.

public int MaxAcceptable(InventoryItem item)
    {
        EquipableItem equipableItem = item as EquipableItem;
        if (equipableItem == null) return 0;
        if ((equipLocation == EquipLocation.Weapon) && item is WeaponConfig weaponConfig)
        {
            if (weaponConfig.isTwoHanded && (playerEquipment.GetItemInSlot(EquipLocation.Offhand) != null))
                return 0;
            if (weaponConfig.isDualWield && (playerEquipment.GetItemInSlot(EquipLocation.Offhand) != null)) // this
                return 0;
        }

        if (equipLocation == EquipLocation.Offhand)
        {
            EquipableItem mainHand = playerEquipment.GetItemInSlot(EquipLocation.Weapon);
            if (mainHand is WeaponConfig mainHandConfig)
            {
                if (mainHandConfig.isTwoHanded) return 0;
                if (mainHandConfig.isDualWield) return 0; //and this
            }
        }
        //The line below only makes sense after completing the Shops and Abilities course
        //if (!equipableItem.CanEquip(equipLocation, playerEquipment)) return 0; 
        if (GetItem() != null) return 0;

        return 1;
    }
1 Like

Hello, I’m stuck with one problem, I made armor according to the principle of weapons. All armor slots work correctly spawn and are destroyed. But only the armor on the body does not want to be removed, I just don’t understand what the problem is, the code for all parts is identical. Based on your variant weapon code.

public class ArmorConfig : EquipableItem, IModifierProvider
    {
        [SerializeField] Armor equippedArmor = null;
        [SerializeField] Armor equippedArmor2 = null;

        [SerializeField]
        Modifier[] additiveModifiers;
        [SerializeField]
        Modifier[] percentageModifiers;

        [System.Serializable]
        struct Modifier
        {
            public Stat stat;
            public float value;
        }
        public enum ArmorVariant { Helmet, Necklace, Body, Trousers, Boots, Gloves}
        [SerializeField] ArmorVariant armorVarianter; 
       
        const string EquipNameHelmet = "Helmet";
        const string EquipNameNecklace = "Necklace";
        const string EquipNameBody = "Body";
        const string EquipNameTrousers = "Trousers";
        const string EquipNameBoots = "Boots";//right
        const string EquipNameBootsL = "BootsL";//left
        const string EquipNameGloves = "Gloves"; //right
        const string EquipNameGlovesL = "GlovesL"; //left

        Transform oldEquip;
        Transform oldEquip2;
        public Armor Spawn(Transform Helmet, Transform Necklace, Transform Body, Transform Trousers, Transform Boots, Transform Left_Boots, Transform Gloves, Transform Left_Gloves)
        {
            //Debug.Log("Spawn");
            DestroyOldArmor(Helmet, Necklace, Body, Trousers, Boots, Left_Boots, Gloves, Left_Gloves);

            Armor equipment = null;
            Armor equipment2 = null;
            if (equippedArmor != null)
            {
                Transform armorTransform = GetTransform(Helmet, Necklace, Body, Trousers, Boots, Gloves);
                Transform armorTransfromDouble = GetDoubleTransfrom(Left_Boots, Left_Gloves);
                switch (armorVarianter)
                {
                    case ArmorVariant.Helmet:
                        equipment = Instantiate(equippedArmor, armorTransform);
                        equipment.gameObject.name = EquipNameHelmet;
                        break;
                    case ArmorVariant.Necklace:
                        equipment = Instantiate(equippedArmor, armorTransform);
                        equipment.gameObject.name = EquipNameNecklace;
                        break;
                    case ArmorVariant.Body:
                        equipment = Instantiate(equippedArmor, armorTransform);
                        equipment.gameObject.name = EquipNameBody;
                        break;
                    case ArmorVariant.Trousers:
                        equipment = Instantiate(equippedArmor, armorTransform);
                        equipment.gameObject.name = EquipNameTrousers;
                        break;
                    case ArmorVariant.Boots:
                        equipment = Instantiate(equippedArmor, armorTransform);
                        equipment2 = Instantiate(equippedArmor2, armorTransfromDouble);
                        equipment.gameObject.name = EquipNameBoots;
                        equipment2.gameObject.name = EquipNameBootsL;
                        break;
                    case ArmorVariant.Gloves:
                        equipment = Instantiate(equippedArmor, armorTransform);
                        equipment2 = Instantiate(equippedArmor2, armorTransfromDouble);
                        equipment2.gameObject.name = EquipNameGlovesL;
                        equipment.gameObject.name = EquipNameGloves;
                        break;
                }             

            }

            return equipment;
        }
       
        private void DestroyOldArmor(Transform Helmet, Transform Necklace, Transform Body, Transform Trousers, Transform Boots, Transform Left_Boots, Transform Gloves, Transform Left_Gloves)
        {
            switch (armorVarianter)
            {
                case ArmorVariant.Helmet:
                    Debug.Log("Destroing Helmet.");
                    oldEquip = Helmet.Find(EquipNameHelmet);
                    break;
                case ArmorVariant.Necklace:
                    Debug.Log("Destroing Necklace.");
                    oldEquip = Necklace.Find(EquipNameNecklace);
                    break;
                case ArmorVariant.Body:
                    Debug.LogWarning("Destroing Body???");
                    oldEquip = Body.Find(EquipNameBody);
                    break;
                case ArmorVariant.Trousers:
                    Debug.Log("Destroing Trousers.");
                    oldEquip = Trousers.Find(EquipNameTrousers);
                    break;
                case ArmorVariant.Boots:
                    Debug.Log("Destroing Boots.");
                    oldEquip = Boots.Find(EquipNameBoots);
                    oldEquip2 = Left_Boots.Find(EquipNameBootsL);
                    break;
                case ArmorVariant.Gloves:
                    Debug.Log("Destroing Gloves.");
                    oldEquip = Gloves.Find(EquipNameGloves);
                    oldEquip2 = Left_Gloves.Find(EquipNameGlovesL);
                    break;
            }
            if (oldEquip == null) return;
            if (oldEquip2 != null)
            {
                oldEquip2.name = "DESTROYING2";
                Destroy(oldEquip2.gameObject);
            }

            oldEquip.name = "DESTROYING";
            Destroy(oldEquip.gameObject);
        }
        private Transform GetDoubleTransfrom(Transform L_Boots, Transform L_Gloves)
        {
            if (armorVarianter == ArmorVariant.Boots) return L_Boots;
            if (armorVarianter == ArmorVariant.Gloves) return L_Gloves;
            else return null;
        }
        private Transform GetTransform(Transform Helmet, Transform Necklace, Transform Body, Transform Trousers, Transform Boots, Transform Gloves)
        {
            //Transform armorTransform;
            if (armorVarianter == ArmorVariant.Helmet) return Helmet;
            if (armorVarianter == ArmorVariant.Necklace) return Necklace;
            if (armorVarianter == ArmorVariant.Body) return Body;
            if (armorVarianter == ArmorVariant.Trousers) return Trousers;
            if (armorVarianter == ArmorVariant.Boots)  return Boots;
            if (armorVarianter == ArmorVariant.Gloves) return Gloves;
            else return null;
        }

        public IEnumerable<float> GetAdditiveModifiers(Stat stat)
        {
            foreach (var modifier in additiveModifiers)
            {
                if (modifier.stat == stat)
                {
                    yield return modifier.value;
                }
            }
        }

        public IEnumerable<float> GetPercentageModifiers(Stat stat)
        {
            foreach (var modifier in percentageModifiers)
            {
                if (modifier.stat == stat)
                {
                    yield return modifier.value;
                }
            }
        }
    }

Honestly, I’m not sure. The code is identical between the different locations. Is the body armor being renamed to DESTROYING?

1 Like

Now I’m completely confused, I didn’t change anything at all, Yesterday only the armor on the body did not work, now everything is not removed… And the helmet does not even spawn, it’s absurd… No, no renamed…
I will write all parts of the armor script…
Fighter.cs

public class Fighter : MonoBehaviour, IAction
{

    
    [SerializeField] Transform armorTransformHelmet = null;
    [SerializeField] Transform armorTransformNecklace = null;
    [SerializeField] Transform armorTransformBody = null;
    [SerializeField] Transform armorTransformTrousers = null;
    [SerializeField] Transform armorTransformBoots_Left = null;
    [SerializeField] Transform armorTransformBoots_Right = null;
    [SerializeField] Transform armorTransformGloves_Left = null;
    [SerializeField] Transform armorTransformGloves_Right = null;


    [SerializeField] ArmorConfig defaultarmorHelmet = null;
    [SerializeField] ArmorConfig defaultarmorNecklace = null;
    [SerializeField] ArmorConfig defaultarmorBody = null;
    [SerializeField] ArmorConfig defaultarmorTrousers = null;
    [SerializeField] ArmorConfig defaultarmorBoots = null;
    [SerializeField] ArmorConfig defaultarmorGloves = null;


    ArmorConfig currentArmorConfig;
    LazyValue<Armor> currentArmor;
   

    private void Awake()
    {
        
        currentArmorConfig = defaultarmorHelmet;
        currentArmor = new LazyValue<Armor>(SetupDefaultArmor);
        

        

        equipment = GetComponent<Equipment>();
        if (equipment)
        {
            equipment.equipmentUpdated += UpdateWeapon;
            equipment.equipmentUpdated += UpdateEquipment;
        }
    }
    //armor
    private Armor SetupDefaultArmor()
    {
        return AttachArmor(defaultarmorHelmet);
    }
    public void EquipArmor(ArmorConfig armor)
    {
        currentArmorConfig = armor;
        currentArmor.value = AttachArmor(armor);

    }
    private Armor AttachArmor(ArmorConfig armor)
    {
        

        return armor.Spawn(armorTransformHelmet, armorTransformNecklace, armorTransformBody, armorTransformTrousers, armorTransformBoots_Left, armorTransformBoots_Right, armorTransformGloves_Right, armorTransformGloves_Left);
    }
    public void UpdateEquipment()
    {
        var Helmet = equipment.GetItemInSlot(EquipLocation.Helmet) as ArmorConfig;
        var Body = equipment.GetItemInSlot(EquipLocation.Body) as ArmorConfig;
        var Trousers = equipment.GetItemInSlot(EquipLocation.Trousers) as ArmorConfig;
        var Boots = equipment.GetItemInSlot(EquipLocation.Boots) as ArmorConfig;
        var Gloves = equipment.GetItemInSlot(EquipLocation.Gloves) as ArmorConfig;
        var Necklace = equipment.GetItemInSlot(EquipLocation.Necklace) as ArmorConfig;
        if (Helmet == null) EquipArmor(defaultarmorHelmet);        
        else EquipArmor(Helmet);
        if (Body == null) EquipArmor(defaultarmorBody);
        else EquipArmor(Body);
        if (Trousers == null) EquipArmor(defaultarmorTrousers);
        else EquipArmor(Trousers);
        if (Boots == null) EquipArmor(defaultarmorBoots);
        else EquipArmor(Boots);
        if (Gloves == null) EquipArmor(defaultarmorGloves);
        else EquipArmor(Gloves);
        if (Necklace == null) EquipArmor(defaultarmorNecklace);
        else EquipArmor(Necklace);
       
    }

One thing I didn’t enquire about… as most armor systems (like the Synty Modular Hero Set or InfinityPBR’s Armor system) actually use individual skinned mesh components that are all set up to work with the skeleton, and components are added/removed by activating/deactivating those components… Is this system a collection of armor that is attached to the skeleton, or is it more like what I just described?

1 Like

Fully weapon system principle, same spawn.


All parts of the armor are separate objects. These parts are tied to body parts. And I didn’t use skeleton animation.

I’m not seeing a reason these wouldn’t be spawning/unspawning from the code presented. I would probably refactor this a bit, however…

private void DestroyOldArmor(Transform slot, string armorName)
{
    var oldItem = slot.Find(armorName);
    if(oldItem)
    {
        oldItem.Name = "DESTROYING";
        Destroy(oldItem);
    }
}

private Armor Spawn(Transform slot, string itemName, bool equip2 = false)
{
     if(!slot)
     {
          Debug.Log($"Attemping to spawn slot {itemName}, but no transform is defined");
          return null;
      }
     DestroyOldArmor(slot, itemName);
     var ItemToInstantiate = equip2? equippedArmor2:equippedArmor;
     Armor armor = Instantiate(ItemToInstantiate, slot);
     armor.name = itemName;
     return armor;
}

public Armor Spawn(Transform Helmet, Transform Necklace, Transform Body,  Transform Trousers, Transform Boots, Transform Left_Boots, Transform Gloves, Transform Left_Gloves);
{
     switch(armorVarianter)
     case ArmorVariant.Helmet:
          return Spawn(Helmet, EquipNameHelmet);
     case ArmorVariant.Necklace:
          return Spawn(Necklace, EquipNameNecklace);
     case ArmorVariant.Body:
          return Spawn(Body, EquipNameBody);
     case ArmorVariant.Trousers:
          return Spawn(Trousers, EquipNameTrousers;
     case ArmorVariant.Boots:
          Spawn(Left_Boots, EquipNameBootsL, true); //spawns left boot
          return Spawn(Boots, EquipNameBoots);
     case ArmorVariant.Gloves:
          Spawn(Left_Gloves, EquipNameGlovesL, true);
          return Spawn(Gloves, EquipNameGloves);
}
1 Like

Tried to change to your version, still does not work completely. I just can’t figure out what to do…
I’m sorry to bother you so much…
The weapon just now stopped working, after the changes.

“The Object you want to instantiate is null”
This would seem to indicate that in one or more of your ArmorConfig instances, the equippedArmor or equippedArmor2 is null…

Add this to Armor.Spawn (the private one with the single transform and string)

if(equippedArmor==null)
{
    Debug.Log($"Armor {name} is trying to equip an {itemName}, but does not have an equippedArmor assigned.");
    return null;
}
if(equip2 && equippedArmor2==null)
{
    Debug.Log($"Armor {name} is trying to equip {itemName}, but has no equippedArmor2 assigned");
    return null;
} 
1 Like

Thanks, Spawn now work, but destroing no work and no renamed to “DESTROYING”…

When the items are spawned, are they being renamed to the itemName?

1 Like

Yes, items renamed to the itemName, maybe after ranamed no work find this item?

That is, I believe, the problem. What I’m unsure of is why.

Let’s make a brute force method to try to ensure that the item is found:

private Transform FindByName(Transform slot, string nameToFind)
{
    foreach(Transform child in slot)
    {
         if(child.name == nameToFind) return child;
    }
    return null;
}

Then replace

var oldItem = slot.Find(armorName);

with

var oldItem = FindByName(slot, armorName);

It’s all strange…

public class ArmorConfig : EquipableItem, IModifierProvider
    {
        [SerializeField] Armor equippedArmor = null;
        [SerializeField] Armor equippedArmor2 = null;

        [SerializeField]
        Modifier[] additiveModifiers;
        [SerializeField]
        Modifier[] percentageModifiers;

        [System.Serializable]
        struct Modifier
        {
            public Stat stat;
            public float value;
        }
        public enum ArmorVariant { Helmet, Necklace, Body, Trousers, Boots, Gloves}
        [SerializeField] ArmorVariant armorVarianter; 
       
        const string EquipNameHelmet = "Helmet";
        const string EquipNameNecklace = "Necklace";
        const string EquipNameBody = "Body";
        const string EquipNameTrousers = "Trousers";
        const string EquipNameBoots = "Boots";//right
        const string EquipNameBootsL = "BootsL";//left
        const string EquipNameGloves = "Gloves"; //right
        const string EquipNameGlovesL = "GlovesL"; //left

        Transform oldEquip;
        Transform oldEquip2;
        
         private Armor Spawn(Transform slot, string itemName, bool equip2 = false)
         {

             if (!slot)
             {
                 Debug.Log($"Attemping to spawn slot {itemName}, but no transform is defined");
                 return null;
             }
             if (equippedArmor == null)
             {
                 Debug.Log($"Armor {name} is trying to equip an {itemName}, but does not have an equippedArmor assigned.");
                 return null;
             }
             if (equip2 && equippedArmor2 == null)
             {
                 Debug.Log($"Armor {name} is trying to equip {itemName}, but has no equippedArmor2 assigned");
                 return null;
             }
             DestroyOldArmor(slot, itemName);
             var ItemToInstantiate = equip2 ? equippedArmor2 : equippedArmor;
             Armor armor = Instantiate(ItemToInstantiate, slot);
             armor.name = itemName;
             return armor;
         }
         public Armor Spawn(Transform Helmet, Transform Necklace, Transform Body, Transform Trousers, Transform Boots, Transform Left_Boots, Transform Gloves, Transform Left_Gloves)
         {
             switch (armorVarianter) {
                 case ArmorVariant.Helmet:
                     return Spawn(Helmet, EquipNameHelmet);
                 case ArmorVariant.Necklace:
                     return Spawn(Necklace, EquipNameNecklace);
                 case ArmorVariant.Body:
                     return Spawn(Body, EquipNameBody);
                 case ArmorVariant.Trousers:
                     return Spawn(Trousers, EquipNameTrousers);
                 case ArmorVariant.Boots:
                     Spawn(Left_Boots, EquipNameBootsL, true); //spawns left boot
                     return Spawn(Boots, EquipNameBoots);
                 case ArmorVariant.Gloves:
                     Spawn(Left_Gloves, EquipNameGlovesL, true);
                     return Spawn(Gloves, EquipNameGloves);
             }
             return null;
         }
        private Transform FindByName(Transform slot, string nameToFind)
        {
            foreach (Transform child in slot)
            {
                if (child.name == nameToFind) return child;
            }
            return null;
        }
        private void DestroyOldArmor(Transform slot, string armorName)
         {
             var oldItem = FindByName(slot, armorName);
             if (oldItem)
             {
                 oldItem.name = "DESTROYING";
                 Destroy(oldItem.gameObject);
             }
         }
        

        public IEnumerable<float> GetAdditiveModifiers(Stat stat)
        {
            foreach (var modifier in additiveModifiers)
            {
                if (modifier.stat == stat)
                {
                    yield return modifier.value;
                }
            }
        }

        public IEnumerable<float> GetPercentageModifiers(Stat stat)
        {
            foreach (var modifier in percentageModifiers)
            {
                if (modifier.stat == stat)
                {
                    yield return modifier.value;
                }
            }
        }
    }
public class Fighter : MonoBehaviour, IAction
{
    [SerializeField] float timeBetweenAttacks = 1f;
    [SerializeField] Transform rightHandTransform = null;
    [SerializeField] Transform leftHandTransform = null;
    [SerializeField] WeaponConfig defaultWeapon = null;
    [SerializeField] ShieldConfig defaultShield = null;
    [SerializeField] float autoAttackRange = 4f;

    //armor
    [SerializeField] Transform armorTransformHelmet = null;
    [SerializeField] Transform armorTransformNecklace = null;
    [SerializeField] Transform armorTransformBody = null;
    [SerializeField] Transform armorTransformTrousers = null;
    [SerializeField] Transform armorTransformBoots_Left = null;
    [SerializeField] Transform armorTransformBoots_Right = null;
    [SerializeField] Transform armorTransformGloves_Left = null;
    [SerializeField] Transform armorTransformGloves_Right = null;


    [SerializeField] ArmorConfig defaultarmorHelmet = null;
    [SerializeField] ArmorConfig defaultarmorNecklace = null;
    [SerializeField] ArmorConfig defaultarmorBody = null;
    [SerializeField] ArmorConfig defaultarmorTrousers = null;
    [SerializeField] ArmorConfig defaultarmorBoots = null;
    [SerializeField] ArmorConfig defaultarmorGloves = null;


    ArmorConfig currentArmorConfig;
    LazyValue<Armor> currentArmor;
    //armor

    Health target;
    Equipment equipment;
    float timeSinceLastAttack = Mathf.Infinity;
    WeaponConfig currentWeaponConfig;
    LazyValue<Weapon> currentWeapon;

    ShieldConfig currentShield;
    LazyValue<Shield> currentEquippedShield;
    

    private void Awake()
    {
        
        currentArmorConfig = defaultarmorHelmet;
        currentArmor = new LazyValue<Armor>(SetupDefaultArmor);

        currentWeaponConfig = defaultWeapon;
        currentWeapon = new LazyValue<Weapon>(SetupDefaultWeapon);

        currentShield = defaultShield;
        currentEquippedShield = new LazyValue<Shield>(null);

        equipment = GetComponent<Equipment>();
        if (equipment)
        {
            equipment.equipmentUpdated += UpdateWeapon;
            equipment.equipmentUpdated += UpdateEquipment;
        }
    }
    //armor
    private Armor SetupDefaultArmor()
    {
        return AttachArmor(defaultarmorHelmet);
    }
    public void EquipArmor(ArmorConfig armor)
    {
        currentArmorConfig = armor;
        currentArmor.value = AttachArmor(armor);

    }
    private Armor AttachArmor(ArmorConfig armor)
    {
        //Debug.Log("AttachArmor");

        return armor.Spawn(armorTransformHelmet, armorTransformNecklace, armorTransformBody, armorTransformTrousers, armorTransformBoots_Left, armorTransformBoots_Right, armorTransformGloves_Right, armorTransformGloves_Left);
    }
    public void UpdateEquipment()
    {
        var Helmet = equipment.GetItemInSlot(EquipLocation.Helmet) as ArmorConfig;
        var Body = equipment.GetItemInSlot(EquipLocation.Body) as ArmorConfig;
        var Trousers = equipment.GetItemInSlot(EquipLocation.Trousers) as ArmorConfig;
        var Boots = equipment.GetItemInSlot(EquipLocation.Boots) as ArmorConfig;
        var Gloves = equipment.GetItemInSlot(EquipLocation.Gloves) as ArmorConfig;
        var Necklace = equipment.GetItemInSlot(EquipLocation.Necklace) as ArmorConfig;
        if (Helmet == null) EquipArmor(defaultarmorHelmet);        
        else EquipArmor(Helmet);
        if (Body == null) EquipArmor(defaultarmorBody);
        else EquipArmor(Body);
        if (Trousers == null) EquipArmor(defaultarmorTrousers);
        else EquipArmor(Trousers);
        if (Boots == null) EquipArmor(defaultarmorBoots);
        else EquipArmor(Boots);
        if (Gloves == null) EquipArmor(defaultarmorGloves);
        else EquipArmor(Gloves);
        if (Necklace == null) EquipArmor(defaultarmorNecklace);
        else EquipArmor(Necklace);
       
    }
    //armor
}

Let’s modify this a bit to see what information we’re getting from the FindByName

        private Transform FindByName(Transform slot, string nameToFind)
        {
            Debug.Log($"{name} removing existing {nameToFind} from {slot}");
            foreach (Transform child in slot)
            {
                Debug.Log($"Testing child {child.name} against {nameToFind}");
                if (child.name == nameToFind) return child;
            }
            return null;
        }

If you install a different helmet, does the old one remain with the new one?

It occurs to me, we may not even be attempting to unequip the item in the first place if it is dragged away…
With the weapon, if you drag away the sword, then the default weapon of Unarmored is generally spawned in it’s place… that’s a WeaponConfig with a blank GameObject (just the Weapon script, no model).

Are you checking to see if the slot is now empty, and if so, equipping an “unarmored”/empty WeaponConfg?

1 Like

No, the old one is destroy, the new one is spawn.
Now i will try checking.

So here’s what I believe is happening… if your default equipment is null, then nothing is telling the old armor (or weapon) to destroy itself…
For each armor slot, create an Unarmored type ArmorConfig… So an UnarmoredHelment, UnarmoredNecklace, UnarmoredBody, etc.
In those Unarmored configs, fill everything out as far as ArmorVariant, and fill the needed Armor fields with Armor Prefabs with no models in them. You won’t need the models for this.

Then in every character’s defaultarmorxxx field, put the appropriate Unarmored ArmorConfig.

Now when you remove a piece of armor, but don’t replace it, it should despawn correctly.

1 Like

Privacy & Terms