- Home /
Other function that is similar to OnTriggerStay
Hello,
I need something to detect like "OnTriggerStay" does, but that I could call whenever I want.
I need to detect objects in a specific zone, but not every frame because it consume too much CPU.
Any Ideas?
Thank You.
Answer by Statement · Dec 22, 2010 at 06:56 PM
Try this code on. It will call the method < callbackName > with a callback of your choosing. framesToSkip is the number of frames that should be skipped until the next callback is raised.
public class TriggerFrameSkip : MonoBehaviour { public string callbackName = "OnTriggerFrameSkip"; public int framesToSkip = 1;
int elapsedFrames;
List<Collider> colliders = new List<Collider>();
void Update()
{
if (elapsedFrames++ < framesToSkip) return;
elapsedFrames = 0;
RaiseCallback();
}
void RaiseCallback()
{
foreach (var collider in colliders)
SendMessage(callbackName, collider,
SendMessageOptions.DontRequireReceiver);
}
void OnTriggerEnter(Collider collider)
{
colliders.Add(collider);
}
void OnTriggerExit(Collider collider)
{
colliders.Remove(collider);
}
}
Or if you'd rather have it time based:
public class TriggerTimeSkip : MonoBehaviour { public string callbackName = "OnTriggerTimeSkip"; public float interval = 5.0f;
List<Collider> colliders = new List<Collider>();
void Start()
{
InvokeRepeating("RaiseCallback", float.Epsilon, interval);
}
void RaiseCallback()
{
foreach (var collider in colliders)
SendMessage(callbackName, collider,
SendMessageOptions.DontRequireReceiver);
}
void OnTriggerEnter(Collider collider)
{
colliders.Add(collider);
}
void OnTriggerExit(Collider collider)
{
colliders.Remove(collider);
}
}
Then your others scripts can be implemented such as:
function OnTriggerTimeSkip(collider : Collider)
{
// called like OnTriggerStay but only every x seconds.
}
Note that you can rename the callback you want to use. Don't use OnTriggerStay, OnTriggerEnter or OnTriggerExit since the latter two will produce errors and the first will cause unwanted behaviour.
In case you want to control when to send the event yourself, you could use this base class:
public class TriggerBase : MonoBehaviour { List<Collider> colliders = new List<Collider>();
protected sealed void RaiseCallback(string callbackName)
{
foreach (var collider in colliders)
SendMessage(callbackName, collider,
SendMessageOptions.DontRequireReceiver);
}
protected virtual void OnTriggerEnter(Collider collider)
{
colliders.Add(collider);
}
protected virtual void OnTriggerExit(Collider collider)
{
colliders.Remove(collider);
}
}
I think you need to override OnTriggerEnter and OnTriggerExit to call base.OnTriggerEnter and base.OnTriggerExit in your script. I am too lazy to check this now. I marked RaiseCallback sealed because there isn't really any intention for you to change its behaviour. Your code should instead just call RaiseCallback("OnTriggerWhatever"); whenever you find it fitting.
Caveat: $$anonymous$$ake sure you clean out colliders of any null values if objects are deleted while in the area. I am not certain if they send OnTriggerExit before they are destroyed.
Another Caveat: This will cause your callbacks to arrive in another order than the usual "triggers first-update later". Now you can't tell which will come first. It probably doesn't do you any harm though, it all depends on what you want to do in the callback.
Answer by Jan Helleman · Nov 30, 2010 at 01:02 AM
you could turn it around and make the zone a trigger and not the objects
The zone is a Trigger, which check the presence of objects within if they meet some condition. The problem, OnTriggerStay is called every frame, which is very CPU intensive. So I need the exact same functionality, but called every 5 second or so.
Answer by BitMiller · Dec 22, 2010 at 05:51 PM
You could assign it to a variable and turn the gameObject having the trigger on once every 5 seconds.