Hit a snag with Generic Raycastable Components

Hello again,

Hit a bit of a roadblock during the Final Polish sections of the Combat Creator course and I could do with some help addressing the problem.

I’m at the point in the lesson where we start to introduce Generic Rayastables for the InteractWithComponent method.

From what I can tell I’ve written the code more or less identical to what is presented in the lesson, except for replacing PlayerController with MyPlayerControlller in the IRaycastable interface and the relevant references.

As it stands - I have differennt cursors working for UI, Movement and Combat but when I hover over an item - the cursor does not change and the item is not picked up.

I cant click to move to the item location either.

I’ve checked the layer for my item pickup and its set as default.

I’m not really sure how to debug this.

Any tips would be greatly appreciated.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using RPG.Movement;
using RPG.Combat;
using RPG.Attributes;
using UnityEngine.EventSystems;

namespace RPG.Control 
{

public class MyPlayerController : MonoBehaviour
    {

        Health health;

        enum CursorType
        {
            None,
            Movement,
            Combat,
            UI
        }

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

        [SerializeField] CursorMapping[] cursorMappings = null;

        private void Awake()
        {
            health = GetComponent<Health>();

        }
        private void Update()

        {
            if (InteractWithUI()) return;
            

            if (health.IsDead())
            {
                SetCursor(CursorType.None);
                return;
            }

            if (InteractWithComponent()) return;

            if (InteractWithCombat()) return;
            if (InteractWithMovement()) return;

            SetCursor(CursorType.None);

        }

        private bool InteractWithUI()
        {
            if (EventSystem.current.IsPointerOverGameObject())
            {
                SetCursor(CursorType.UI);
                return true;
            }
            return false;
        }

        private bool InteractWithComponent()

        {
            RaycastHit[] hits = Physics.RaycastAll(GetMouseRay());
            foreach (RaycastHit hit in hits)
            {
                IRaycastable[] raycastables = hit.transform.GetComponents<IRaycastable>();
                foreach (IRaycastable raycastable in raycastables)
                {
                    if (raycastable.HandleRaycast(this))
                    {
                        SetCursor(CursorType.Combat);
                        return true;
                    }

                }
            }
            return false;
        }

        private bool InteractWithCombat()
        {
            RaycastHit[] hits = Physics.RaycastAll(GetMouseRay());
            foreach (RaycastHit hit in hits)
            {
                CombatTarget target = hit.transform.GetComponent<CombatTarget>();
                if (target == null) continue;
         
                if (!GetComponent<Fighter>().CanAttack(target.gameObject))
                {
                    continue;
                }

                if (Input.GetMouseButton(0))
                {
                    GetComponent<Fighter>().Attack(target.gameObject);
                }
                SetCursor(CursorType.Combat);
                return true;
            }
            return false;
        }

        private bool InteractWithMovement()
        {
            RaycastHit hit;
            bool hasHit = Physics.Raycast(GetMouseRay(), out hit);
            if (hasHit)

            {
                if (Input.GetMouseButton(0))

                {
                    GetComponent<Mover>().StartMoveAction(hit.point, 1f);
                }
                SetCursor(CursorType.Movement);
                return true;
                    
            }

            return false;
        }

        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);
        }
    }

}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using RPG.Control;

namespace RPG.Combat
{

    
    public class WeaponPickup : MonoBehaviour, IRaycastable
    {

        [SerializeField] Weapon weapon = null;
        [SerializeField] float respawnTime = 5f;

        private void OnTriggerEnter(Collider other)
        {
            if (other.gameObject.tag == "Player")
            {
                //Debug.Log("Testy");
                Pickup(other.GetComponent<Fighter>());
            }
        }

        private void Pickup(Fighter fighter)
        {
            fighter.EquipWeapon(weapon);
            StartCoroutine(HideForSeconds(respawnTime));
        }

        private IEnumerator HideForSeconds(float seconds)
        {
            ShowPickup(false);
            yield return new WaitForSeconds(seconds);
            ShowPickup(true);
        }

        private void ShowPickup(bool shouldShow)
        {
            GetComponent<Collider>().enabled = shouldShow;
            foreach (Transform child in transform)
            {
                child.gameObject.SetActive(shouldShow);
            }
        }

        public bool HandleRaycast(MyPlayerController callingController)
        {
            if (Input.GetMouseButtonDown(0))
            {
                Pickup(callingController.GetComponent<Fighter>());
            }
            return true;
        }
    }

}
namespace RPG.Control
{
    public interface IRaycastable
    {
        bool HandleRaycast(MyPlayerController callingController);
    }
}

I went ahead with the rest of the course and completed the remaining lessons.

I have circled back to try and address this problem before I move onto the other courses and still cant crack it.

Having updated the interact with combat behaviour to instead use Interact with Component it seems the problem is only occuring in relation to item / weapon pickups.

When I add a debug log to interact with component - it appears that when hovering over a weapon pickup - it is returning false as if there are no raycastable objects “through this particular ray”.

Can anybody think of any reason why my pickups would not be returning a raycastable object?

The pickup class implements IRaycastable interface and each pickup prefab has a weapon script attached at the root alongside a sphere collider with a trigger that has been enabled.

sorry I missed getting back to you when you first asked the question. (I read the topic at work, and then forgot it when I got home).

The code looks correct, I’m not seeing any immediate reason why the items aren’t getting picked up by a RaycastAll…
Let’s add some debugs into InteractWithComponent:

private bool InteractWithComponent()

        {
            RaycastHit[] hits = Physics.RaycastAll(GetMouseRay());
            Debug.Log($"Total Hits in InteractWithCombat: {hits.Length}");
            foreach (RaycastHit hit in hits)
            {
                Debug.Log($"Testing {hit.transform.gameObject.name}");
                IRaycastable[] raycastables = hit.transform.GetComponents<IRaycastable>();
                Debug.Log($"IRayCastables found {raycastables.Length}");
                foreach (IRaycastable raycastable in raycastables)
                {
                    Debug.Log("Raycastable found in {hit.transform.gameObject.name}!");
                    if (raycastable.HandleRaycast(this))
                    {
                        SetCursor(CursorType.Combat);
                        return true;
                    }

                }
            }
            return false;
        }

thanks for the awesome information.

Hi Brian,

My current build has the updated scripts based on the later lessons - I’ve attached a couple of short screen recordings to show what’s happening at the moment. As well as a look at the item pick up prefab itself.

Not sure if the videos will be of any help in terms of troubleshooting.

I’m not entirely sure what I am looking for - let me know if any extra information would help.

Many thanks for any support you can offer.

When it comes to code, pasting the code text directly into the reply box beats watching on YouTube every time. Same with the setups on the prefabs… a screenshot beats YouTube. It does show me, though, that for some reason the Raycast isn’t picking up the pickup when it should be.

I need to take a closer look. Zip up your project and upload it to https://gdev.tv/projectupload (be sure to remove the Library folder from the zip to conserve space. I’ll take a look and see if I can see what’s going on.

Hi Brian,

Thanks for your help. I’ll make sure to stick to code and screenshots in the future. I’ve filled out the form and sent it across. Even with the library folder removed the project exceded the upload size so I attached from my GDrive. I’ve DM’d a share link in case it didn’t attach correctly.

I scratched my head on this one for quite a while, then on a lark, I unchecked the “Is Trigger” box, and suddenly it worked…
This isn’t, however, the behaviour we want. We want the raycast to work even on a trigger…
Fortunately, there is a setting for this in Project Settings Physics3D, there is a checkbox for “Queries Hit Triggers”. Once this was checked, the triggers are now working perfectly when raycast/spherecast

Hi Brian,

Thanks very much for taking a look. I didn’t think to look at project settings as it’s not something I’d tweaked during the lessons. I think one of asset packs I am using may have changed some project settings when importing.

You’re a life saver, thanks again!

It didn’t occur to me either for quite a bit.

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

Privacy & Terms