Can't get IRaycastable to work on any components outside of the course

I have been trying for about two weeks now to get the IRaycastable interface to work on a script I have created from scratch:

{
    public class CropGrower : MonoBehaviour, IRaycastable
    {
        [SerializeField] PlantConfig crop = null;
        [SerializeField] GameObject cropStage = null;
        [SerializeField] UnityEvent harvestEvent;
        int daysSincePlanted = 0;
        public bool isHarvestable = false;
        InventoryItem harvestableItem;
        bool wasHarvested = false;

        public void GrowthStatus(FarmPlot soil)
        {
            daysSincePlanted++;
            print(daysSincePlanted);
            if (daysSincePlanted == crop.DaysUntilSeedling())
            {
                Destroy(transform.GetChild(0).gameObject);
                GameObject cropStage = Instantiate(crop.SpawnSeedling(), transform.parent.position, Quaternion.identity);
                cropStage.transform.parent = transform;
            }
            else if (daysSincePlanted == crop.DaysUntilSprout())
            {
                Destroy(transform.GetChild(0).gameObject);
                GameObject cropStage = Instantiate(crop.SpawnSprout(), transform.parent.position, Quaternion.identity);
                cropStage.transform.parent = transform;
            }
            else if (daysSincePlanted == crop.DaysUntilBudding())
            {
                Destroy(transform.GetChild(0).gameObject);
                GameObject cropStage = Instantiate(crop.SpawnBudding(), transform.parent.position, Quaternion.identity);
                cropStage.transform.parent = transform;
            }
            else if (daysSincePlanted == crop.DaysUntilHarvest())
            {
                Destroy(transform.GetChild(0).gameObject);

                GameObject cropStage = Instantiate(crop.SpawnHearvestable(), transform.parent.position, Quaternion.identity);
                cropStage.transform.parent = transform;
                isHarvestable = true;
                harvestableItem = crop.SpawnHarvestedPickup();
                print(isHarvestable);
            }

        }

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

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

        //public void HandleRaycast()
        //{
        //    RaycastHit hit;
        //    if (Physics.Raycast(GetMouseRay(), out hit))
        //    {
        //        if (hit.collider.gameObject.tag == "Harvest")
        //        {
        //            print(hit);
        //            CropGrower cropGrower = hit.transform.parent.gameObject.GetComponent<CropGrower>();
        //            if (ReferenceEquals(cropGrower, cropGrower))
        //            GetCrop(cropGrower);
        //        }
        //    }
        //}

        //public void GetCrop(CropGrower cropGrower)
        //{
        //    if (!cropGrower.isHarvestable) return;
        //    if (cropGrower.isHarvestable)
        //    {
        //        GameObject player = GameObject.FindGameObjectWithTag("Player");
        //        bool success = player.GetComponent<Inventory>().AddToFirstEmptySlot(cropGrower.harvestableItem, 1); //adds item to first empty slot
        //        if (!success)
        //        {
        //            player.GetComponent<ItemDropper>().DropItem(cropGrower.harvestableItem, 1); //or drops it on the ground if inventory is full
        //        }
        //        Destroy(cropGrower.gameObject);
        //        cropGrower.GetComponentInParent<FarmPlot>().ResetCropStage();
        //    }
            
        //}

        public CursorType GetCursorType()
        {
            return CursorType.Harvest;
        }

        public bool HandleRaycast(PlayerController callingController)
        {
            if (!isHarvestable) return false;
            if (Input.GetMouseButtonDown(0))
            {
                Debug.Log("hit");

                bool success = callingController.GetComponent<Inventory>().AddToFirstEmptySlot(harvestableItem, 1); //adds item to first empty slot
                if (!success)
                {
                    GetComponent<ItemDropper>().DropItem(harvestableItem, 1); //or drops it on the ground if inventory is full
                }
                Destroy(gameObject);
                GetComponentInParent<FarmPlot>().ResetCropStage();
            }
            return true;
        }
    }
}

The problem is that neither the cursortype nor the handleraycast seem to get called for this component when I press mouse button 0.

I have implemented the interface and provided instructions that are substantially the same as those used in weapon pickup or combat target, but unity just won’t call this HandleRaycast. Why exactly doesn’t this work the way the other components do? Surely this should be able to interact with the PlayerController component the same way all the other components do?

Here is the PlayerController script I am using. I feel like this should get called through InteractWithComponent, just like AIConversant, CombatTarget, and ClickablePickup do in the other RPG courses.

{
    public class PlayerController : MonoBehaviour
    {
        [System.Serializable]
        public struct CursorMapping
        {
            public CursorType type;
            public Texture2D texture;
            public Vector2 hotspot;
        }

        [SerializeField] CursorMapping[] cursorMappings = null;
        [SerializeField] float maxNavMeshProjectionDistance = 1f;
        [SerializeField] float raycastRadius = 1f;

        bool movementStarted = false;
        bool isDraggingUI = false;

        private void Update()
        {
            if (Input.GetMouseButtonUp(0))
            {
                movementStarted = false;
            }

            if (InteractWithUI()) return;
            if (InteractWithComponent()) return;
            if (InteractWithMovement()) return;

            SetCursor(CursorType.None);
        }

        private bool InteractWithUI()
        {
            if (Input.GetMouseButtonUp(0))
            {
                isDraggingUI = false;
            }

            if (EventSystem.current.IsPointerOverGameObject())
            {
                if (Input.GetMouseButtonDown(0))
                {
                    isDraggingUI = true;
                }
                SetCursor(CursorType.UI);
                return true;
            }
            if (isDraggingUI)
            {
                return true;
            }
            return false;
        }

        RaycastHit[] RaycastAllSorted()
        {
            RaycastHit[] hits = Physics.SphereCastAll(GetMouseRay(), raycastRadius);
            float[] distances = new float[hits.Length];
            for (int i = 0; i < hits.Length; i++)
            {
                distances[i] = hits[i].distance;
            }
            Array.Sort(distances, hits);
            return hits;
        }

        private bool InteractWithComponent()
        {
            RaycastHit[] hits = RaycastAllSorted();
            foreach (RaycastHit hit in hits)
            {
                IRaycastable[] raycastables = hit.transform.GetComponents<IRaycastable>();
                foreach (IRaycastable raycastable in raycastables)
                {
                    if (raycastable.HandleRaycast(this))
                    {
                        SetCursor(raycastable.GetCursorType());
                        return true;
                    }
                }
            }
            return false;
        }

        private bool InteractWithMovement()
        {
            Vector3 target;
            bool hasHit = RaycastNavMesh(out target);
            if (hasHit)
            {
                if (!GetComponent<Mover>().CanMoveTo(target)) return false;

                if (Input.GetMouseButtonDown(0))
                {
                    movementStarted = true;
                }
                if (Input.GetMouseButton(0) && movementStarted)
                {
                    GetComponent<Mover>().StartMoveAction(target, 1f);
                }
                SetCursor(CursorType.Movement);
                return true;
            }
            return false;
        }

        private bool RaycastNavMesh(out Vector3 target)
        {
            target = new Vector3();

            RaycastHit hit;
            bool hasHit = Physics.Raycast(GetMouseRay(), out hit);
            if (!hasHit) return false;

            NavMeshHit navMeshHit;
            bool hasCastToNavMesh = NavMesh.SamplePosition(
                hit.point, out navMeshHit, maxNavMeshProjectionDistance, NavMesh.AllAreas);
            if (!hasCastToNavMesh) return false;

            target = navMeshHit.position;

            return true;
        }

        private void SetCursor(CursorType type)
        {
            CursorMapping mapping = GetCursorMapping(type);
            Cursor.SetCursor(mapping.texture, mapping.hotspot, CursorMode.Auto);
        }

        private CursorMapping GetCursorMapping(CursorType type)
        {
            foreach (CursorMapping mapping in cursorMappings)
            {
                if (mapping.type == type)
                {
                    return mapping;
                }
            }
            return cursorMappings[0];
        }

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

I think I have it solved for now, the gameobject in question was set to Ignore Raycasts. I changed its layer to default and now it is working.

I will try to move this logic to a different component to see if I can still get it to work.

1 Like

That would definitely do it. I would slip a Debug.Log in the first line of HandleRayCast() to be sure that the item was getting scooped up in the InteractWithComponents/GetRayCastAllSorted group. That would have yielded no debug with the ignore raycast checked.

Privacy & Terms