Having trouble getting other scripts to read which item is currently equipped

I am trying to implement a “FarmPlot” class that will perform certain interactions depending on the weapon the player has equipped. The problem is that I am not entirely sure how to reference the currently equipped item. I am trying to access it using the Equipment and Weapon config class, similar to how you made Fighter.UpdateWeapon() work:

FarmPlot Class:

using System.Collections;
using System.Collections.Generic;
using RPG.Control;
using UnityEngine;
using RPG.Combat;
using GameDevTV.Inventories;

namespace RPG.Farming
{
    public class FarmPlot : MonoBehaviour
    {
        [SerializeField] bool isTilled = false;
        [SerializeField] bool isPlanted = false;
        [SerializeField] bool isWatered = false;
        [SerializeField] Material tilledSoilTexture = null;
        Equipment equipment;

        private void Awake()
        {
            equipment = GetComponent<Equipment>();
        }

        void Update()
        {
            if (Input.GetMouseButton(0))
            {
                HandleRaycast();
            }
        }

        public void HandleRaycast()
        {
            RaycastHit hit;
            if (Physics.Raycast(GetMouseRay(), out hit))
            {
                if (hit.collider.gameObject.tag == "Farm")
                {
                    FarmPlot soil = hit.collider.gameObject.GetComponent<FarmPlot>();
                    TillFarmPlot(soil);
                }
            }


        }

        public void TillFarmPlot(FarmPlot soil)
        {
            if (equipment.GetItemInSlot(EquipLocation.Weapon) == null) return;
            var weapon = equipment.GetItemInSlot(EquipLocation.Weapon) as WeaponConfig;
            Vector3 soilLocation = soil.transform.position;

            if (soil.isTilled) return;
            if (!soil.isTilled && weapon.GetTool() == "Hoe")
            {
                soil.isTilled = true;
                soil.GetComponent<MeshRenderer>().material = tilledSoilTexture;
                print("Tilling this farm plot");
            }
        }

        public void WaterFarmPlot()
        {

        }

        public void PlantinFarmPlot()
        {

        }
        private static Ray GetMouseRay()
        {
            return Camera.main.ScreenPointToRay(Input.mousePosition);
        }
    }
}

WeaponConfig class (added a series of bools and a GetTool() method)

using UnityEngine;
using RPG.Attributes;
using GameDevTV.Inventories;
using RPG.Stats;
using System.Collections.Generic;

namespace RPG.Combat
{
    [CreateAssetMenu(fileName = "Weapon", menuName = "Weapons/Make New Weapon", order = 0)]
    public class WeaponConfig : EquipableItem, IModifierProvider
    {
        [SerializeField] AnimatorOverrideController animatorOverride = null;
        [SerializeField] Weapon equippedPrefab = null;
        [SerializeField] float weaponDamage = 5f;
        [SerializeField] float percentageBonus = 0;
        [SerializeField] float weaponRange = 2f;
        [SerializeField] bool isRightHanded = true;
        [SerializeField] Projectile projectile = null;

        [SerializeField] bool canTill = false;
        [SerializeField] bool canPlant = false;
        [SerializeField] bool canWater = false;
        [SerializeField] bool canChop = false;
        [SerializeField] bool canMine = false;

        const string weaponName = "Weapon";

        public Weapon Spawn(Transform rightHand, Transform leftHand, Animator animator)
        {
            DestroyOldWeapon(rightHand, leftHand);

            Weapon weapon = null;

            if (equippedPrefab != null)
            {
                Transform handTransform = GetTransform(rightHand, leftHand);
                weapon = Instantiate(equippedPrefab, handTransform);
                weapon.gameObject.name = weaponName;
            }

            var overrideController = animator.runtimeAnimatorController as AnimatorOverrideController;
            if (animatorOverride != null)
            {
                animator.runtimeAnimatorController = animatorOverride;
            }
            else if (overrideController != null)
            {
                animator.runtimeAnimatorController = overrideController.runtimeAnimatorController;
            }

            return weapon;
        }

        private void DestroyOldWeapon(Transform rightHand, Transform leftHand)
        {
            Transform oldWeapon = rightHand.Find(weaponName);
            if (oldWeapon == null)
            {
                oldWeapon = leftHand.Find(weaponName);
            }
            if (oldWeapon == null) return;

            oldWeapon.name = "DESTROYING";
            Destroy(oldWeapon.gameObject);
        }

        private Transform GetTransform(Transform rightHand, Transform leftHand)
        {
            Transform handTransform;
            if (isRightHanded) handTransform = rightHand;
            else handTransform = leftHand;
            return handTransform;
        }

        public bool HasProjectile()
        {
            return projectile != null;
        }

        public void LaunchProjectile(Transform rightHand, Transform leftHand, Health target, GameObject instigator, float calculatedDamage)
        {
            Projectile projectileInstance = Instantiate(projectile, GetTransform(rightHand, leftHand).position, Quaternion.identity);
            projectileInstance.SetTarget(target, instigator, calculatedDamage);
        }

        public float GetDamage()
        {
            return weaponDamage;
        }

        public float GetPercentageBonus()
        {
            return percentageBonus;
        }

        public float GetRange()
        {
            return weaponRange;
        }

        public IEnumerable<float> GetAdditiveModifiers(Stat stat)
        {
            if (stat == Stat.Damage)
            {
                yield return weaponDamage;
            }
        }

        public IEnumerable<float> GetPercentageModifiers(Stat stat)
        {
            if (stat == Stat.Damage)
            {
                yield return percentageBonus;
            }
        }

        public string GetTool()
        {
            if (canTill)
            {
                return "Hoe";
            }
            return "Not a tool";
        }
    }
}

The idea is that if the weapon scriptable object has “canTill” set to true, upon clicking on the farm plot prefab it will change the texture of the soil and mark the farm plot as “isTilled”. Currently this works if I remove any references to equipment and simply click the prefab, but I get the following null reference exception if I try to reference the item in the weapon slot:


I was able to make the exception go away by adding the equipment script to the farm prefab, but it’s still not reading the current weapon.

public void TillFarmPlot(FarmPlot soil)
        {
            print(equipment.GetItemInSlot(EquipLocation.Weapon));
            if (equipment.GetItemInSlot(EquipLocation.Weapon) == null) return;
            var weapon = equipment.GetItemInSlot(EquipLocation.Weapon) as WeaponConfig;
            print(weapon);
            Vector3 soilLocation = soil.transform.position;

            if (soil.isTilled) return;
            if (!soil.isTilled && weapon.GetTool() == "Hoe")
            {
                soil.isTilled = true;
                soil.GetComponent<MeshRenderer>().material = tilledSoilTexture;
                print("Tilling this farm plot");
            }
        }

Even when an item is equipped in the weapon slot, it still returns “null”

I tried introducing the player as a serialized field and getting the equipment component through the player prefab, but it still keeps returning “null” as the equipped weapon:

public void TillFarmPlot(FarmPlot soil)
        {
            EquipableItem farmTool = player.GetComponent<Equipment>().GetItemInSlot(EquipLocation.Weapon);
            print(farmTool);
            if (farmTool == null) return;
            var weapon = farmTool as WeaponConfig;
            print(weapon);
            Vector3 soilLocation = soil.transform.position;

            if (soil.isTilled) return;
            if (!soil.isTilled && weapon.GetTool() == "Hoe")
            {
                soil.isTilled = true;
                soil.GetComponent<MeshRenderer>().material = tilledSoilTexture;
                print("Tilling this farm plot");
            }
        }

I did it! My code is hideous and clunky, but I did it:

{
    public class FarmPlot : MonoBehaviour
    {
        [SerializeField] bool isTilled = false;
        [SerializeField] bool isPlanted = false;
        [SerializeField] bool isWatered = false;
        [SerializeField] Material tilledSoilTexture = null;
        Equipment equipment;
        [SerializeField] GameObject player = null;

        private void Awake()
        {
            player = GameObject.FindGameObjectWithTag("Player");
            equipment = GetComponent<Equipment>();
        }

        void Update()
        {
            if (Input.GetMouseButton(0))
            {
                HandleRaycast();
            }
        }

        public void HandleRaycast()
        {
            RaycastHit hit;
            if (Physics.Raycast(GetMouseRay(), out hit))
            {
                if (hit.collider.gameObject.tag == "Farm")
                {
                    FarmPlot soil = hit.collider.gameObject.GetComponent<FarmPlot>();
                    TillFarmPlot(soil);
                }
            }
            

        }

        public void TillFarmPlot(FarmPlot soil)
        {
            var farmTool = player.GetComponent<Equipment>().GetItemInSlot(EquipLocation.Weapon) as WeaponConfig;
            print(farmTool);
            if (farmTool == null) return;
            Vector3 soilLocation = soil.transform.position;

            if (soil.isTilled) return;
            if (!soil.isTilled && farmTool.GetTool() == "Hoe")
            {
                soil.isTilled = true;
                soil.GetComponent<MeshRenderer>().material = tilledSoilTexture;
                print("Tilling this farm plot: " + soil.gameObject.name);
            }
        }

        public void WaterFarmPlot()
        {

        }

        public void PlantinFarmPlot()
        {

        }
        private static Ray GetMouseRay()
        {
            return Camera.main.ScreenPointToRay(Input.mousePosition);
        }
    }
}

All I changed was make it find the player prefab and get the equipment component from there, and made the type var instead of EquippableItem.

I still have other issues, namely there is a massive frame drop when I click a farmplot, but I’m sure that’s just cause I need to clean up my spaghetti code.

I’m glad you were able to get to the right answer. Remember that the best way to get Player is always to use player=GameObject.FindGameObjectWithTag(“Player”); Then you can derive the equipment from the player. You should remove the [SerializeField] from the line GameObject player = null; as you will never be using the serialized value.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms