Search Unity

Raycast ignoring obstructions if the player stays inside the range of the raycast

Discussion in 'Scripting' started by VileGoo, Aug 17, 2018.

  1. VileGoo

    VileGoo

    Joined:
    Apr 29, 2017
    Posts:
    220
    The title basically says it all. I have a script that gets the range of a light source and uses that as the maxDistance variable for the raycast. This works well, until an obstruction gets inside of the radius. Suddenly the ray will shoot out in an infinite distance if the ray is intersecting with the obstruction before reaching the player. However if the player walks into the range of the raycast while still obstructed, nothing will happen as it should. But if the player moves into the view of the ray and triggers it before moving back behind the obstruction while staying inside the radius, the raycast will remain true and totally ignore the obstruction. Even if the player moves out of the radius after doing this the raycast will still hit the player as if they're in the radius and not behind an obstruction. How can I prevent this?

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. [ExecuteInEditMode]
    6. public class LightDarknessController : MonoBehaviour
    7. {
    8.     Light lightObject;
    9.     GameObject player;
    10.     RaycastHit hit;
    11.     float lightRange;
    12.  
    13.     void Start()
    14.     {
    15.         player = GameObject.FindGameObjectWithTag("Player");
    16.  
    17.         lightObject = GetComponent<Light>();
    18.     }
    19.  
    20.     void Update()
    21.     {
    22.         float range = lightObject.range;
    23.         lightRange = range / 1.1f;
    24.  
    25.         Vector3 rayDirection = player.transform.position - transform.position;
    26.  
    27.         if (Physics.Raycast(transform.position, rayDirection, out hit, lightRange))
    28.         {
    29.             Debug.DrawRay(transform.position, rayDirection, Color.yellow);
    30.  
    31.             if (hit.collider.tag == "Player")
    32.             {
    33.                 Debug.Log("In Light");
    34.             }
    35.         }
    36.         else
    37.         {
    38.             Debug.Log("In Darkness");
    39.         }
    40.     }
    41.  
    42.     void OnDrawGizmos()
    43.     {
    44.         Gizmos.color = Color.red;
    45.         Gizmos.DrawWireSphere(transform.position, lightRange);
    46.     }
    47. }
    48.  
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,749
    I'm not 100% clear what you're trying to do: are you just checking if the player is within the light sphere so he is visible to enemies or not? Or are you trying to do your own occlusion/shadowcasting of objects between you and the light?

    If the former, why don't you just use that MaxRange to decide if you're in light or not.

    If the latter, then just raycast "farther away" than the player by a small amount such that if the player is slightly at or in the obstruction, your cast will still hit the obstruction.
     
  3. MSplitz-PsychoK

    MSplitz-PsychoK

    Joined:
    May 16, 2015
    Posts:
    1,278
    Physics.Raycast() will report any object the ray passes through, but only one object. When your ray passes through both your obstacle and player, it is hard to determine which one will be reported.

    Instead, I recommend you use Physics.RaycastAll() and loop through the array of "hits" to find which one has your player tag. If none have the player tag, then the ray didn't pass through your player.
    https://docs.unity3d.com/ScriptReference/Physics.RaycastAll.html
     
    Kurt-Dekker likes this.
  4. VileGoo

    VileGoo

    Joined:
    Apr 29, 2017
    Posts:
    220
    That's not what I want. I need the ray to get stopped by the obstructions, if something is blocking the ray (like a wall) so it can't reach the player, I want the ray to stop and output false.
     
  5. VileGoo

    VileGoo

    Joined:
    Apr 29, 2017
    Posts:
    220
    Yes it's the former. I need the ray to get stopped if something if blocking direct line of sight with the player (like a wall) but like I said, if the obstruction is within the lightRange radius, the ray does some weird things and seems to ignore the wall as it looks for the player.
     
  6. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Physx raycasts do not check a collider if they originate inside that collider. Is this related to your problem?
     
  7. MSplitz-PsychoK

    MSplitz-PsychoK

    Joined:
    May 16, 2015
    Posts:
    1,278

    You can still use the method I recommend, and use another variable to keep track of the closest hit object by checking the hit.distance of each hit. If the closest hit object is not the player, you can output false and skip the "raycast hit player" logic.
     
  8. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358