Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice
  4. Dismiss Notice

Resolved How to find specific colliders using RaycastHit?

Discussion in 'Physics' started by Jasan_Alan, Apr 24, 2021.

  1. Jasan_Alan

    Jasan_Alan

    Joined:
    Apr 24, 2021
    Posts:
    2
    I'm trying to make the AI for my horror game chase the player, but a NullRef keeps popping up in the logs telling me that an object isn't set to a reference - the 'object' in this case being the FoundPlayer hitInfo in a raycast. Can anyone help figure out how to find whether a specific collider has been hit?

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.AI;
    5.  
    6. public class EnemyScript : MonoBehaviour
    7. {
    8.     public enum _State
    9.     {
    10.         Roaming,
    11.         Stalking,
    12.         Chasing
    13.     }
    14.     public _State State;
    15.  
    16.     public Transform[] RoomsToVisit;
    17.  
    18.     public MeshCollider ViewCone;
    19.     public GameObject Target;
    20.     public CapsuleCollider TargetBody;
    21.     public NavMeshAgent Enemy;
    22.     public Transform Destination;
    23.     public Transform LooksAtPlayer;
    24.     public float WalkingSpeed = 3f;
    25.     public float RunningSpeed = 14f;
    26.  
    27.     // Start is called before the first frame update
    28.     void Start()
    29.     {
    30.         ViewCone.GetComponent<MeshRenderer>().enabled = false;
    31.         TargetBody = Target.GetComponent<CapsuleCollider>();
    32.     }
    33.  
    34.     // Update is called once per frame
    35.     void Update()
    36.     {
    37.         if (ViewConeScript.TouchingPlayer)
    38.         {
    39.             PlayerIsInView();
    40.         }
    41.         bool SamePosX = Mathf.Approximately(Enemy.transform.position.x, Destination.transform.position.x);
    42.         bool SamePosY = Mathf.Approximately(Enemy.transform.position.y, Destination.transform.position.y);
    43.         bool SamePosZ = Mathf.Approximately(Enemy.transform.position.z, Destination.transform.position.z);
    44.         switch (State)
    45.         {
    46.             case _State.Roaming:
    47.                 if (SamePosX && SamePosY && SamePosZ)
    48.                 {
    49.                     int RandomNumber = Mathf.RoundToInt(Random.Range(0, RoomsToVisit.Length - 1));
    50.                     Destination.SetPositionAndRotation(RoomsToVisit[RandomNumber].position, RoomsToVisit[RandomNumber].rotation);
    51.                 }
    52.                 Enemy.SetDestination(Destination.position);
    53.                 Enemy.speed = WalkingSpeed;
    54.                 Enemy.acceleration = 1000f;
    55.                 break;
    56.             case _State.Stalking:
    57.                 Enemy.SetDestination(Destination.position);
    58.                 Enemy.speed = WalkingSpeed;
    59.                 Enemy.acceleration = 1000f;
    60.                 break;
    61.             case _State.Chasing:
    62.                 Enemy.SetDestination(Destination.position);
    63.                 Enemy.speed = RunningSpeed;
    64.                 Enemy.acceleration = 18f;
    65.                 //Enemy.transform.LookAt(Target.transform);
    66.                 if (SamePosX && SamePosY && SamePosZ)
    67.                 {
    68.                     State = _State.Roaming; //Set to Stalking and have enemy search rooms for player
    69.                 }
    70.                 break;
    71.             default:
    72.                 break;
    73.         }
    74.     }
    75.  
    76.     void PlayerIsInView()
    77.     {
    78.         LooksAtPlayer.LookAt(Target.transform);
    79.         float DistFromTarget = Vector3.Distance(Target.transform.position, Enemy.transform.position);
    80.         LayerMask mask = LayerMask.GetMask("Player Layer");
    81.         RaycastHit FoundPlayer;
    82.         Physics.Raycast(origin: Enemy.transform.position, direction: LooksAtPlayer.rotation.eulerAngles, hitInfo: out FoundPlayer, maxDistance: 160f, layerMask: mask);
    83.         if (FoundPlayer.collider.transform.position == TargetBody.transform.position) //This is the problem child in question
    84.         {
    85.             State = _State.Chasing;
    86.             Destination.SetPositionAndRotation(Target.transform.position, Target.transform.rotation);
    87.             Debug.Log("Player is in sight");
    88.         }
    89.         else
    90.         {
    91.             Debug.Log("There is no player in sight");
    92.         }
    93.     }
    94. }
     
  2. AlTheSlacker

    AlTheSlacker

    Joined:
    Jun 12, 2017
    Posts:
    326
    Physics.Raycast will return true if it has hit something, so use it with if to wrap up the raycast hit logic, then you won't try to process null hitInfo:

    e.g.
    Code (CSharp):
    1. if(Physics.Raycast(origin: Enemy.transform.position, direction: LooksAtPlayer.rotation.eulerAngles, hitInfo: out FoundPlayer, maxDistance: 160f, layerMask: mask))
    2. {// process raycast hitInfo here}
    From https://docs.unity3d.com/ScriptReference/RaycastHit.html you can see you can get lots of useful information, e.g. collider will tell you which collider you have hit.

    e.g.
    Code (CSharp):
    1. Debug.Log("Hit: " + hitInfo.collider.name);
    To debug your raycasting you will find it useful to use https://docs.unity3d.com/ScriptReference/Debug.DrawRay.html (ensure gizmos are on and watch the game in scene view - the ray is not rendered in game view). Note, apply your raycast length as a scalar to the direction in Debug.DrawRay.

    I would guess that your problem is related to one of the following:
    a) Your ray is not being cast from where you expect it to be cast from.
    b) Your ray direction is not what you are expecting it to be.
    c) Is all of the player in the Player Layer? E.g. does he have an accessory that is not in that layer.

    EDIT
    You can use hitinfo.point to get a position and then move a marker object (e.g. small sphere) to that point, this may help you understand where a ray is colliding with your player.
     
    Last edited: Apr 24, 2021
  3. Jasan_Alan

    Jasan_Alan

    Joined:
    Apr 24, 2021
    Posts:
    2
    Thanks so much for this! Turns out the ray direction was way off because it was being fed Euler angles for rayDirection. Although I ended up using LineCast instead, your tips on using DrawRay and wrapping up the raycast logic were very insightful.
     
    AlTheSlacker likes this.
  4. CrinkleCruft

    CrinkleCruft

    Joined:
    Jun 28, 2022
    Posts:
    1
    This might not be relevant to your question but I had some trouble finding the answer to a similar question that led me here and I figured I might be able to help other lost souls. If you have multiple colliders attached to a single object, you can get the specific
    RaycastHit.collider
    by casting the collider to the type that you are expecting to find. For instance, I needed a box collider so in order to get the properties for it, I had to use
    raycastHit.collider as BoxCollider