• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
9
Question by brant · Dec 17, 2013 at 08:19 AM · collider2d-physicsunity 4.3

How do you set an order for 2D Colliders that overlap?

Using Unity 4.3.1f1 I am making a game where I hide a character behind a door. I want to be able to click the door animate the door and its collider out of the way, and then be able to click on the character when he is visible. I have everything rendering and showing on screen correctly in sorting layers and stuff, but the character gets the click, not the door even though the door draws on top of the character. Obviously transforming the z doesn't work as that is how I would have solved the problem in 2DTK. Is there some kind of collision z-index that can be used to set raycast and click preference? One more piece, the door and character animations and collisions work properly on their own when they are not overlapped.

Comment
Add comment · Show 3
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image iwaldrop · Dec 17, 2013 at 05:27 PM 0
Share

There seems to be some kind of big with it right now where colliders behind the top one gets the event. It's rather annoying. I'm not sure if there's a work around, but you could also try a google search for unity 2d collider ordering workaround.

avatar image Romano · Jan 29, 2014 at 06:15 PM 0
Share

Here is a possible workaround (incomplete, sorry). I'm not very experienced with Unity, but I've had the same problem and hopefully this will shed some light on it:

     // Store the point where the user has clicked as a Vector3
     var clickPosition : Vector3 = Camera.main.ScreenToWorldPoint(Input.mousePosition);
     // Retrieve all raycast hits from the click position and store them in an array called "hits"
     var hits : RaycastHit2D[] = Physics2D.RaycastAll (clickPosition, clickPosition);
 
     if (hits != null)
     {
         // Say which gameObject has been clicked (currently this code only works if there are TWO objects in the path of the raycast)
         Debug.Log("The clicked object is "+ hits[0].collider.gameObject);
         Debug.Log("The clicked object is "+ hits[1].collider.gameObject);
         
         // In here we'd want something like: if hit 1's sorting layer is higher than hit 0 then return hit 1
     }

So this code in place of your current raycast code will return the player and the door and then you'll need something to choose the object that's on the correct sorting layer.

I realise this looks like a pig's arse and is badly explained but just thought I'd post it and see if it helped. I'd be very interested to find out how it goes!

avatar image isteffy · Sep 08, 2015 at 04:53 PM 0
Share

Is it me or do these answers feel incredibly long for something simple such as this. If something is placed above another gameobject, it should be clicked first. Why is this so hard for Unity?

7 Replies

· Add your reply
  • Sort: 
avatar image
27

Answer by Ultroman · Apr 05, 2016 at 10:00 PM

After a bit of testing, I've come to a discovery, which might cast some light on this "problem".

TL;DR: Go to where it says "For 2D in Unity" in bold text, if you don't want to learn, but just get the facts.

None of the physics layers, sprite sorting layers or sorting orders seem to have ANY impact on which object a ray hits first. The sprite-stuff only makes a difference to which order the sprites are rendered in, and the physics layers just let you define which objects can collide with each other. It kind of has to be this way, because otherwise these things would be tied together! An objects' colliders could be on a parent or child object, and there could even be one collider acting on one physics layer only, and another one acting on another layer only. It makes sense that they don't factor into which object is in front of the other.

Example: Let's say we have two objects; "Front" and "Back". They both have a BoxCollider2D and a SpriteRenderer.

I set "Front" to Sprite Sorting Layer "Foreground", and sprite "Back" to Sprite Sorting Layer "Background". Now "Front" is always rendered on top of "Back", but they both still have the same Z-position, so the ray hits either of them seemingly at random.

Now, if I set the Z-axis of "Front" to be 10 (deeper into the screen), which will make it move BEHIND sprite "Back" in the Scene-view, it will still be rendered AFTER i.e. ON TOP of sprite "Back", because of the order of the Sprite Sorting Layers, but a screen-ray (see GetRayIntersection() below) will always hit sprite "Back" first, because its Z-position is closer to the camera.

It's sort of the same with the physics layers. If you used them to control which object is in front of another, then you'd be locked into some irritating situations.

For 2D in Unity:

Physics sorting layers = help you control which types of colliders can hit which types of colliders, and also which of them should ignore raycasts i.e. which of them should be ignored when we do our raycast-clicks (more on them further down).

Sprite sorting layers and sorting orders = control the sprite rendering queue, so the sprites are rendered in the correct order, and makes it possible for you to help Unity batch properly.

Z-position = lets you control which gameobjects are "physically" in front of the others, without affecting sprite rendering order or physics interactions, but affects which 2D collider is considered closest to the screen when casting a ray into the screen as opposed to across the screen.

2D Raycasting = casts a ray through the (x,y) world space coordinate system i.e. across the screen, using given start- and end-coordinates, and returns information about the first collider it hits, if any. If two or more objects have a collider at the exact same coordinates, it will be a luck of the draw. Makes total sense.

GetRayIntersection() = just like raycasting, but can cast a ray "into" the screen of a 2D game, returning information about the first collider it hits.

Solution: Don't put several objects, that are all supposed to be clickable, on top of each other with the same Z-position. And to find the frontmost collider, DO NOT use Physics2D.Raycast. That is for casting rays in (x,y) space, you know, across the screen.

For hitting the frontmost collider at a screen point, use something like this:

 Vector3 worldPoint = Camera.main.ScreenToWorldPoint(Input.mousePosition);
 worldPoint.z = Camera.main.transform.position.z;
 Ray ray = new Ray(worldPoint, new Vector3(0, 0, 1));
 RaycastHit2D hitInfo = Physics2D.GetRayIntersection(ray);

Code stolen from this stackoverflow post.

It can definitely be shortened to alleviate some instantiation. The "new Vector3(0, 0, 1)" makes the ray shoot directly into the screen, from the clicked position (worldPoint), after worldPoint has had its Z-position changed to that of the camera, instead of the default 0. So it sort of "shoots from the screen" and "into the game", hitting the first collider it meets. You can go ahead and filter the layers it can hit, by using some of the overloaded versions of Physics2D.GetRayIntersection.

2021 Update:

For getting the frontmost collider where you've clicked, you can use Physics2D.OverlapPoint() instead:

 Collider2D colliderHit = Physics2D.OverlapPoint(Camera.main.ScreenToWorldPoint(Input.mousePosition));

You can check if colliderHit is null, and if it isn't, then it is the frontmost thing it hit. You can adjust the Z-range it should search in and which layers to search in, by using the other parameters for the Physics2D.OverlapPoint() function.

For finding all the colliders under the point where you clicked, you can use Physics2D.OverlapPointAll() or Physics2D.OverlapPointNonAlloc() the latter of which is preferred for memory reasons. It requires you to supply an array of sufficient size to put the results in, which you then clear after you've used it. Since people click a lot, you don't want to garbage collect results for every click, thus we use the NonAlloc version and eat the cost of keeping our little array around; it should not need to be very large, anyway. You can see an example in kboudai's answer below, where results[0] is the frontmost thing hit and any subsequent hits in the array are in Z-order, positive to negative. The actual declaration of the "results" array is missing from kboudai's answer, but it'd just be something like this in your class:

 private Collider2D[] results = new Collider2D[5];

5 is the size of the array, but also the "depth" i.e. the maximum number of collisions we want to detect. OverlapPointNonAlloc simply writes the collisions into the array in order, and if the array is not large enough, it just skips the rest, so we only get the first 5. Then you MUST clear that array (set all its places to null) after you've used it. Otherwise, if you detected 5 collisions last time, but only 3 this time, then you'll have an array with the 3 new ones and the last 2 of the 5 from the last click. It's annoying, but it saves A LOT of garbage collection!

Comment
Add comment · Show 5 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image shieldgenerator7 · May 17, 2017 at 01:24 AM 2
Share

Thanks for mentioning the Physics layers. I set one of my objects to the IgnoreRayCast layer and now it works just fine.

avatar image Ultroman shieldgenerator7 · Jan 13, 2019 at 02:55 PM 0
Share

That's a good point! I added something to that effect to the post. Thanks :)

avatar image bab202 shieldgenerator7 · Sep 07, 2021 at 03:04 PM 0
Share

It will not work in case your back object still need detect touch by raycast.

avatar image PhilaPhan80 · Jul 14, 2017 at 08:40 PM 2
Share

Thank you for this excellent explanation!

avatar image christh · Apr 25 at 08:00 AM 0
Share

Great explanation and research! I wrestled for a few hours yesterday trying to get a 'tooltip' system working on non-UI gameobjects using the various built-in Unity events, but I'm not 100% happy with the result.

So I'm pretty sure I'll need to use raycasts but that'll be a rearchitecting job for a rainy day whilst referring to this excellent answer ;)

avatar image
10

Answer by kboudai · Sep 19, 2014 at 10:29 PM

I made it work by putting them on the same layer then making their z-position closer to the camera.

No need for 3D.

For example:

 GameObject A;
 GameObject B;
 
 int Layer = 2;
 
 void Start(){
     A.layer = Layer;
     A.transform.position.z = -1;
     B.layer = Layer;
     B.transform.position.z = 0;
 }
 
 void onClick(){
     Vector2 p = Camera.main.ScreenToWorldPoint(pos);
     int hitNum = Physics2D.OverlapPointNonAlloc(p, results, 1<<Layer);
     if(hitNum > 0){
         // Should be A, assuming the camera's z is -10
         Collider2D hit = results[0];
     }
 }



Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image lslu · Sep 02, 2020 at 10:03 AM 0
Share

Thanks it helps

avatar image
1
Wiki

Answer by kolenda · Jun 11, 2014 at 12:40 PM

I've just found out that in such situations you can use 3D colliders, which will support correct z-ordering. You may have problems using 2D and 3D colliders at once, in such case you'll need to move entirely to 3D colliders.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image isteffy · Sep 08, 2015 at 04:59 PM 0
Share

Is it me or does this seem like a silly issue for Unity 2d to be struggling with? Unity not accounting that some gameobjects must be clicked over others is kind of sad

avatar image
0

Answer by isteffy · Sep 11, 2015 at 04:46 PM

There is no straight-forward answer to solve this without a complicated work-around.

Personally i would just switch my 2DColliders to 3D ones. The change might be a bit of a hassle but IMO much easier than adding these complicated raycasts to every click event in your game.

You can also my obviously see how a collider interacts within it's own space. You can still make everything else look 2D with no complication at all.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Relaxidaizical · Jan 07, 2021 at 04:04 PM 0
Share

This works for me; however, I'm using On$$anonymous$$ouseOver() instead of raycasting. I assume this would work for that whole set of functions (On$$anonymous$$ouseOver, On$$anonymous$$ouseDown, On$$anonymous$$ouseUp etc.).

avatar image
-1

Answer by guitarxe · Dec 17, 2013 at 05:40 PM

Try the example here

http://docs.unity3d.com/Documentation/Components/Layers.html Read where it says "Casting Rays Selectively".

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Romano · Jan 29, 2014 at 05:11 PM 0
Share

I'm not sure the Casting rays selectively section helps in a situation where both items must be clickable at the same time. Is there still no work around for this?

  • 1
  • 2
  • ›

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

30 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

OnTriggerEnter2d() Not Triggering While Animating. 1 Answer

is it better to make one collider for a large landmass made of many tiles, or make each of the tiles have their own colliders? 2 Answers

2d space gravity? 2 Answers

I am walking through/onto my tree when it has a 2D box collider and i dont know y. plz help.,I am walking through my tree when it has a 2D box collider on it and i do not know y? 1 Answer

Unity 2D Collider Safe Sizes 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges