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

Raycasting for a period of time

Discussion in 'Scripting' started by fredyyanez, Jul 28, 2015.

  1. fredyyanez

    fredyyanez

    Joined:
    Jul 8, 2014
    Posts:
    33
    Ive tried looking this up and i haven't found anything helpful.

    Im using raycasting and I want to know if this ray has hit an object for lets say 5 or more seconds.

    Whats the best way to do this?

    Thanks!
     
  2. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Coroutine.
     
  3. fredyyanez

    fredyyanez

    Joined:
    Jul 8, 2014
    Posts:
    33
    How exactly, if i understood the documentation correctly it is essentially a function that resumes after each frame, how would I handle the timing issue? How do I record the initial time the ray hits the object and compare that with the current time? ( I know how to do this but how do i reset the initial time after the raycast exits the object?)
     
  4. DougMcFarlane

    DougMcFarlane

    Joined:
    Apr 25, 2009
    Posts:
    197
    There are multiple ways to do this.
    I created a simple RayCaster class to simplify ray casting (see below).
    How to use the class:
    Code (CSharp):
    1. private RayCaster ray;
    2. private float rayHitStart = 0f;
    3.  
    4. void Start() {
    5.     ray = new RayCaster();
    6.     ray.OnRayEnter += Ray_OnEnter;
    7.     ray.OnRayStay += Ray_OnStay;
    8.     ray.OnRayExit += Ray_OnExit;
    9.     // ray.LayerMask = RayCaster.GetLayerMask("Wall");  // OPTIONAL
    10.     ray.StartTransform = startObject.transform;
    11.     ray.EndTransform = endObject.transform;
    12. }
    13.  
    14. void LateUpdate() {
    15.     ray.CastRay();
    16.     // ray.CastLine();  // If you want to use a Line Caster instead.
    17. }
    18.  
    19.  
    20. void Ray_OnEnter(Collider collider) {
    21.     if (collider.name == "ObjectName") {
    22.         rayHitStart = Time.time;
    23.     }
    24. }
    25.  
    26. void Ray_OnStay(Collider collider) {
    27.     if (collider.name == "ObjectName") {
    28.         if (Time.time - rayHitStart > 5f) {
    29.             // Object has been hit for five seconds - do something!
    30.         }
    31.     }
    32. }
    33.  
    34. void Ray_OnExit(Collider collider) {
    35.     if (collider.name == "ObjectName") {
    36.         rayHitStart = 0f;
    37.     }
    38. }
    RayCaster class:
    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using UnityEngine;
    4.  
    5. public class RayCaster {
    6.  
    7.     public Transform StartTransform;
    8.     public Transform EndTransform;
    9.     public Vector3 Direction;
    10.     public float RayLength;
    11.     public int LayerMask = 0;
    12.  
    13.     public event Action<Collider> OnRayEnter;
    14.     public event Action<Collider> OnRayStay;
    15.     public event Action<Collider> OnRayExit;
    16.  
    17.     Collider previous;
    18.     RaycastHit hit = new RaycastHit();
    19.  
    20.     public bool CastRay() {
    21.         Physics.Raycast(StartTransform.position, Direction, out hit, RayLength, LayerMask);
    22.         ProcessCollision(hit.collider);
    23.         return hit.collider != null ? true : false;
    24.     }
    25.  
    26.     public bool CastLine() {
    27.         Physics.Linecast(StartTransform.position, EndTransform.position, out hit, LayerMask);
    28.         ProcessCollision(hit.collider);
    29.         return hit.collider != null ? true : false;
    30.     }
    31.  
    32.     private void ProcessCollision(Collider current) {
    33.         // No collision this frame.
    34.         if (current == null) {
    35.             // But there was an object hit last frame.
    36.             if (previous != null) {
    37.                 DoEvent(OnRayExit, previous);
    38.             }
    39.         }
    40.  
    41.         // The object is the same as last frame.
    42.         else if (previous == current) {
    43.             DoEvent(OnRayStay, current);
    44.         }
    45.  
    46.         // The object is different than last frame.
    47.         else if (previous != null) {
    48.             DoEvent(OnRayExit, previous);
    49.             DoEvent(OnRayEnter, current);
    50.         }
    51.  
    52.         // There was no object hit last frame.
    53.         else {
    54.             DoEvent(OnRayEnter, current);
    55.         }
    56.  
    57.         // Remember this object for comparing with next frame.
    58.         previous = current;
    59.     }
    60.  
    61.     private void DoEvent(Action<Collider> action, Collider collider) {
    62.         if (action != null) {
    63.             action(collider);
    64.         }
    65.     }
    66.  
    67.     public static int GetLayerMask(string layerName, int existingMask=0) {
    68.         int layer = LayerMask.NameToLayer(layerName);
    69.         return existingMask | (1 << layer);
    70.     }
    71.  
    72. }
    73.  
    [Edit] Various bug fixes and typos.
    The above code hasn't been tested (except the RayCaster class).
    I just whipped it up for a quick example, but should work.
     
    Last edited: Jul 28, 2015