Search Unity

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