Hi, I have an object with a BoxCollider2D (lets call this box1) trying to detect whether it is touching a layer called “Wall” which is essentially another BoxCollider2D (lets call this box2 - but it is set as a trigger), and it does not seem to be picking it up correctly.
if (ground.GetComponent<BoxCollider2D>().IsTouchingLayers(wallLayer))
{
print("Y"); //Never appears
}
I would use OnTriggerEnter2D() but for this specific scenario I am Instantiating the object with box1 and randomising its position, and then checking if it is touching the box2 and if so, randomise the position again, until it is not touching this layer - hence I am unsure how to use OnTriggerEnter2D() mid-code while relocating the object.
I have tried reversing the order of operations by checking if box2 is touching box1 (incase the trigger is the problem - as I have another script which is this same scenario and it works fine but it is a trigger looking for a solid collider instead)
I’m guessing this should all happen in an instant, which won’t happen. If you instantiate an object onto another, even if they were colliding now, the collision event callbacks won’t run until after the next time FixedUpdate ran which is almost certainly not going to happen in the same frame but in one of the next frames.
Even if you used raycasts (or spherecast etc) these won’t detect collision until after the next physics update, if I recall correctly.
You can defer the check with a coroutine that first yield return new WaitForFixedUpdate(); and after that you perform the raycast, spherecast or any other “cast”.
I see, that makes a lot more sense now! I am still getting my head around how Coroutines and Raycasting works but I might need to look into that.
Is there possibly another method I could use to check if box1 overlaps with an x-position/range, given that the Wall layer holds a consistent x position. I know there are some useful functions under Physics2D but I’m now wondering if that will be the same issue where it would not register in the same frame it was instantiated. If that is not plausible I think I will have to try Coroutines
You can use Physics2D.OverlapBox using the same values as the box collider to detect if you’re hitting the wall. If the wall is already there (i.e. it has not just been instantiated in this frame too) it should be detected.
If you’re just wanting to place walls on the ground then a more efficient approach is to raycast downwards from above the ground and instantiate a box/wall just above the detected position. Doing this prevents your game from potentially freezing up trying to search for empty locations.
BTW - when you instantiate something then the physics world is updated immediately. Whereas if you move something after instantiating it then the physics world won’t be updated until the next FixedUpdate. So if you’re placing multiple walls then it’s much better to instantiate them in the correct location rather than moving them around after instantiating them.
If you want to use a collider to check if it’s overlapping i.e. do an intersection test then use Collider2D.Overlap.
You create it then immediately check if it’s touching? As per the scripting docs here:
It is important to understand that checking if colliders are touching or not is performed against the last physics system update i.e. the state of touching colliders at that time. If you have just added a new Collider2D or have moved a Collider2D but a physics update has not yet taken place then the colliders will not be shown as touching. The touching state is identical to that indicated by the physics collision or trigger callbacks.
The “IsTouching” calls are querying the current contacts. Those are calculated when the simulation runs so IsTouchingLayers is indeed working.
NOTE: One point of correction from previous posts; when you add a collider or move it, if you perform a query then you’ll see it immediately, a simulation step is not needed. The critical part is that colliders don’t move, only Rigidbody2D because colliders are attached to them. If you move a Rigidbody2D via its position/rotation then it’ll be immediately updated for queries etc. Devs often get confused about this because they write to the Transform and wonder why the physics knows nothing about it. When a Transform changes, nothing in Unity beyond the Transform knows about it. The systems only know about it when they check. You’re not supposed to drive physics via the Transform.
As I said, you should never use the Transform like this. Colliders don’t move, they are recreated if you do this. If you wanted it to actually move then you can add a Rigidbody2D and change its position property, it’d be there instantly. There’s a body-type option for a reason and in this case, it could be made Static. There is no overhead in doing this, quite the opposite, it’s faster.
Thanks everyone for the input/advice! I tried a few different methods around using the transform of the rigidbody or trying to find a way to do the reposition check after the next physics update but my lack of knowledge and experience made this all seem very convoluted and beyond me.
I ended up coming to a simple realisation that I should have thought of before any of this, which was to use the localscale and position (because it was a rectangle) to deduce the x-pos of where the collider ended and whether it was in the x-range I was looking for.
Well note that there’s no such thing as this. Sure there’s a Transform on the GameObject but it’s not of the Rigidbody2D. The Rigidbody2D will write to it when the simulation runs.
As I said above, if you want to know if a collider overlaps then get the collider and simply use Collider2D.Overlap. You don’t need to be forming rectangles from boxes and performing box intersection tests, the defeats the whole purpose of using a collider.
Anyway, if you have something you want to use then that’s good but note that things like “bounds” are NOT the collider and that colliders are scaled by more than “localScale”, can be offset, can be rotated etc so this is fragile.
For example, below you could call the “CheckOverlap” method passing in a collider, position and angle and it’d check for you. It stores the results in the list and reuses the list but if you’re not interested you can just use the return value which is how many results it found, in this case if it’s >0 then it’s overlapping. You can configure the “WallFilter” in the inspector to select your Wall Layer (ensure you check UseLayers too).
Note that this collider doesn’t need to be position, it can be away from the scene and kept and just used for this purpose. You should add a Rigidbody2D with its “Simulated” property unchecked so it doesn’t do anything to the simulation (it’s ignored).
class Test : MonoBehaviour
{
public ContactFilter2D WallFilter; // Configure to use "wall" layer in the inspector.
private List<Collider2D> m_Results = new List<Collider2D>();
...
private bool CheckOverlap(Collider2D col, Vector2 position, float angle) => col.Overlap(position, angle, WallFilter, m_Results) > 0;
...
}