2
\$\begingroup\$

So essentially I'm attempting to implement a "security" system by using an object with no mesh collider to act as an invisible trigger (stretched across a doorway or something) which sets off an audible alarm sound. The feature I want to add is for it not to keep restarting the alarm loop every time you touch the collider, as that just doesn't happen IRL. I've tried everything from countdown timers with Time.deltaTime, OnTriggerExit booleans even a Thread.Sleep hack which just froze the whole game engine up while the function executed. Is there a nice way to achieve this kind of behaviour? If not, what's a better way of implementing a similar system? It's fairly generic and could be applied to more than just alarm systems.

EDIT:

public class Sensor : MonoBehaviour
{

public AudioClip alertLoop;
float timer = 3f;
bool isTriggered = false;

public void OnTriggerEnter(Collider col)
{
    if(!isTriggered)
    {
        isTriggered = true;
        AudioManager.instance.PlayOneShot(alertLoop);
        print("Alarm Triggered!");
    }

}
public void OnTriggerExit(Collider col)
{
    timer -= Time.deltaTime;
    if(timer == 0)
    {
        isTriggered = false;
    }
}
}

That's my current attempt, I've deleted pretty much everything else I tried. Anything that required me to use the update function for the timer confused me, as the OnTriggerEnter is already MonoBehaviour, not a custom function.

\$\endgroup\$
  • \$\begingroup\$ Why not just temporarily disable the object -- save when it is disabled -- and after a certain amount of time, re-enable the object? \$\endgroup\$ – bpgeck Nov 3 '15 at 23:23
  • \$\begingroup\$ Or, disable the object until some in game character (i.e. a security guard) turns off the alarm, thus causing the object to re-enable \$\endgroup\$ – bpgeck Nov 3 '15 at 23:24
  • \$\begingroup\$ You're definitely on the right track for implementation for what you want. What you're trying to implement is called a "Cool Down Timer". It would help to post your source code for the OnTrigger to see why it is not working. That OnTriggerEnter/OnTriggerExit method does indeed work, but there are some logical gotchas you have to be aware of. If you post your code I can help with that specifically. You can also use a free Tween library like DOTween in Unity and wait until the tween is complete to restart the "Security" system. DOTween url: dotween.demigiant.com \$\endgroup\$ – Ben BearFish Nov 3 '15 at 23:59
2
\$\begingroup\$

How about you just use a System.Timers.Timer (https://msdn.microsoft.com/en-us/library/system.timers.timer.aspx)?

If not isTriggered, you start the Timer and have the elapsed time to your delay for the alarm (it uses milliseconds, so 3000?).

You can then set the elapsed event to reset your isTriggered back to false. Make sure you set the auto reset to false, so the Timer doesn't star again until the player triggers it (https://msdn.microsoft.com/en-us/library/system.timers.timer.elapsed.aspx).

So, pseudo code

System.Timers.Timer timer;

public Sensor()
{
    timer = new System.Timers.Timer();
    timer.Interval = 3000;
    timer.AutoReset = false;
    timer.Enabled = false;
    timer.Elapsed += OnTimerTick;
}

private void OnTimerTick(object sender, System.Timers.ElapsedEventArgs e)
{
    isTriggered = false;
}

public void OnTriggerEnter(Collider col)
{
     if (!isTriggered) {
        isTriggered = true;
       AudioManager.instance.PlayOneShot(alertLoop);
        print("Alarm Triggered!");     
        timer.Start();
     }
}

That's the general idea at least.

\$\endgroup\$
1
\$\begingroup\$

One problem I see is that your timer only decreases on OnTriggerExit. OnTriggerExit only happens as an object leaves the trigger area. On subsequent frames, OnTriggerExit isn't being called again, so the timer is no longer going down.

You want your timer to go down as long as it's not touching the trigger, right? So I'd put in another bool (call it, touchingTrigger, for example). Set it to true in OnTriggerEnter and false in OnTriggerExit.

Then have your countdown go down in Update. Something like this:

float cooldownTime = 3f;

public void Update()
{
    // alarm has been triggered, but we're no longer touching it?
    if (isTriggered && !touchingTrigger)
    {
        // countdown!
        timer -= Time.deltaTime;
        // time's up?
        if (timer <= 0)
        {
            isTriggered = false;
            timer = cooldownTime; // reset the timer; you could do this in OnTriggerEnter, instead
        }
    }
}

I hope that's helpful :)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.