I have been struggling with what was supposed to be a very simple logic problem for the last two hours. I finally managed to make it work but I wonder if there’s a more elegant solution (forgive me for the horizontal rules but for the life of me I can’t figure out how to write paragraph breaks here, double space at the end doesn’t work).
What I’m looking for is a trigger Collider2D which can report at all times if something is touching it (or inside its zone). Because any number from 0 to 10 objects might be in the zone at any given time, I can’t do it with OnTriggerEnter2D and OnTriggerExit2D, for two reasons: (1) I don’t want to keep a list or a count variable because I don’t need them for anything else (2) With Enter and Exit I get less predictable behaviour if the trigger is enabled when something is already touching it, or if an object gets destroyed while inside the trigger.
So I’m going with OnTriggerStay2D instead. But I don’t want it to continuously send a message when there’s a collider present. I just need it to report once if something is in there or not, as soon as the script is enabled and at any point after that. I also don’t need to check it every single frame (0.1 seconds is more than enough in my case). So I managed to do this with two booleans (after hours of trying to figure out the ‘if’ structure of the current and last check):
using UnityEngine;
public class SafeZone : MonoBehaviour {
private Collider2D col;
private bool isClearThisCheck;
private bool isClearLastCheck;
private float checkInterval;
private float timeSinceLastCheck;
void Awake()
{
col = GetComponent<Collider2D>();
isClearLastCheck = true;
checkInterval = 0.5f;
}
private void FixedUpdate()
{
if (Time.time > timeSinceLastCheck + checkInterval)
{
if (isClearThisCheck && !isClearLastCheck)
{
Debug.Log("FREE");
// Send a message.
isClearLastCheck = true;
}
isClearThisCheck = true;
timeSinceLastCheck = Time.time;
}
}
private void OnTriggerStay2D(Collider2D collision)
{
isClearThisCheck = false;
if (isClearLastCheck)
{
Debug.Log("OCCUPIED");
// Send a message here too.
isClearLastCheck = false;
}
}
}
This works and does what it’s supposed to do. It does feel like reinventing the wheel, though, and I wonder if there’s a simpler boolean check possible (or a Unity check I’m not aware of). Also, this only works because FixedUpdate is called before the collision. If I put this in Update instead, the whole logic gets reversed and it doesn’t work. Is there any way to do this with less code?
P.S. For some reason, this code outputs free whenever I deactivate the script in the Inspector while the trigger is in the occupied state. Not a big deal, but I don’t really understand why this happens.