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!
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!
Coroutine.
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?)
There are multiple ways to do this.
I created a simple RayCaster class to simplify ray casting (see below).
How to use the class:
private RayCaster ray;
private float rayHitStart = 0f;
void Start() {
ray = new RayCaster();
ray.OnRayEnter += Ray_OnEnter;
ray.OnRayStay += Ray_OnStay;
ray.OnRayExit += Ray_OnExit;
// ray.LayerMask = RayCaster.GetLayerMask("Wall"); // OPTIONAL
ray.StartTransform = startObject.transform;
ray.EndTransform = endObject.transform;
}
void LateUpdate() {
ray.CastRay();
// ray.CastLine(); // If you want to use a Line Caster instead.
}
void Ray_OnEnter(Collider collider) {
if (collider.name == "ObjectName") {
rayHitStart = Time.time;
}
}
void Ray_OnStay(Collider collider) {
if (collider.name == "ObjectName") {
if (Time.time - rayHitStart > 5f) {
// Object has been hit for five seconds - do something!
}
}
}
void Ray_OnExit(Collider collider) {
if (collider.name == "ObjectName") {
rayHitStart = 0f;
}
}
RayCaster class:
using System;
using System.Collections;
using UnityEngine;
public class RayCaster {
public Transform StartTransform;
public Transform EndTransform;
public Vector3 Direction;
public float RayLength;
public int LayerMask = 0;
public event Action<Collider> OnRayEnter;
public event Action<Collider> OnRayStay;
public event Action<Collider> OnRayExit;
Collider previous;
RaycastHit hit = new RaycastHit();
public bool CastRay() {
Physics.Raycast(StartTransform.position, Direction, out hit, RayLength, LayerMask);
ProcessCollision(hit.collider);
return hit.collider != null ? true : false;
}
public bool CastLine() {
Physics.Linecast(StartTransform.position, EndTransform.position, out hit, LayerMask);
ProcessCollision(hit.collider);
return hit.collider != null ? true : false;
}
private void ProcessCollision(Collider current) {
// No collision this frame.
if (current == null) {
// But there was an object hit last frame.
if (previous != null) {
DoEvent(OnRayExit, previous);
}
}
// The object is the same as last frame.
else if (previous == current) {
DoEvent(OnRayStay, current);
}
// The object is different than last frame.
else if (previous != null) {
DoEvent(OnRayExit, previous);
DoEvent(OnRayEnter, current);
}
// There was no object hit last frame.
else {
DoEvent(OnRayEnter, current);
}
// Remember this object for comparing with next frame.
previous = current;
}
private void DoEvent(Action<Collider> action, Collider collider) {
if (action != null) {
action(collider);
}
}
public static int GetLayerMask(string layerName, int existingMask=0) {
int layer = LayerMask.NameToLayer(layerName);
return existingMask | (1 << layer);
}
}
[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.