• 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
0
Question by Omer.Hussain · Apr 22, 2014 at 08:09 AM · spritedestroyonmousedown

How to apply OnMouseDown on sprites according to z position...

alt textHi! i have a 2d flower which is made with sprite petals and those petal are organised according to z position. My camera is on -10 z position and petals position starts from suppose -4 on the last petal(petal-1), then on the second last (petal-2) -4.1 then -4.2 so they are positioned on one another... all have 2d box collider and script applied to destroy petal on onmousedown.. the problim is , when i click on the front most petal positioned suppose on -5 it destroys any of the petal positioned underneath it , like in between -4.9 to -4.1 .... what i want is . it should detect the front most collider sprite first rather then the collider applied on the underneath petals... i also have tried help form here but its not working :( ...

 function OnMouseDown()
 {
 //    print("ok");
     Destroy(gameObject);
 }

 


screenshot_2014-04-22-13-10-52-1.png (112.6 kB)
Comment
Add comment · Show 5
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 · Apr 22, 2014 at 08:22 AM 0
Share

Howdy. The code you linked to will only work if you use sorting layers, not z depth. But the code could be re-written to work for z depth.

It also looks like you're not using raycasts to handle clicks, which will make it harder to tell unity you want to click the frontmost sprite. I'd recommend switching to this method and either rewriting your code to use sorting layers or rewrite the sprite clicker to use z depth.

avatar image Tasmia · Apr 22, 2014 at 08:29 AM 0
Share

are you attaching collider with this sprite... you need to!

avatar image Omer.Hussain · Apr 22, 2014 at 08:44 AM 0
Share

@Romano how do we apply the raycast on the On$$anonymous$$ouseDown function ... i am new to unity can you change the code your are asking to change ... @Tasmia i have mentioned in my question i have applied 2d box collider ...

avatar image Omer.Hussain · Apr 22, 2014 at 08:59 AM 0
Share

ok @Romeo now i applied the below Raycast script and surprise surprise it destroy 4 5 petals on single click :'( ...

     function Update()
     {
     //check if the left mouse has been pressed down this frame
     if (Input.Get$$anonymous$$ouseButtonDown(0))
     {
     //empty RaycastHit object which raycast puts the hit details into
     var hit : RaycastHit;
     //ray shooting out of the camera from where the mouse is
     var ray : Ray = Camera.main.ScreenPointToRay(Input.mousePosition);
      
     if (Physics.Raycast(ray, hit))
     {
     //print out the name if the raycast hits something
     gameObject.active=false;
     Debug.Log(hit.collider.name);
     }
     }
     }
 
avatar image TCRyan · Apr 22, 2015 at 05:23 PM 0
Share

I had something similar on a complex game object with a trigger collider on the parent object with the logic, and sliding colliders on the child objects. It didn't seem to matter whether I used On$$anonymous$$ouseDown or RayCastHit2D. The problem was the "apparent" randomness of what collider is selected first. I've had 2 copies of the same gameobject give different results. Ultimately fixing it I did two things: I set the trigger collider game object's layer to HUD and I moved the z out (up) for each child object. Since it is using the sprite renderer sorting layers to draw, it didn't matter what Z I put it on for rendering, but it sure did for collision detection.

3 Replies

· Add your reply
  • Sort: 
avatar image
0
Best Answer

Answer by Omer.Hussain · Apr 23, 2014 at 10:45 AM

OK .... for everyone who is suffering from this problem .. Solution is ..

1) Apply 2d collider on the sprite 2) Keeps the Sprites According to the Z position. For example, if your camera is at -10 z position , your background could be at -5 , characters could be at -6 and forground at -7. 3) If 2d collider doesn't fit to the sprite position , for example if you have star or sprite like zigzag/not equal than use 2d Polygon Collider(atleast it helped me in this situation). 4) I dont know layered effect or not but try to keep the layers dafault.

Have Fun ... :) Finally i am out of The Hell of 2D Collider ... ;) and i used function OnMOuseDown(){ //////do what ever you want to do here }

Comment
Add comment · 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
0

Answer by Romano · Apr 22, 2014 at 09:02 AM

Hi Omer, you need to get rid of the OnMouseDown function altogether to use a raycasting method.

Step 1: Attach the frontmostspriteclicker script to your main camera.

Step 2: Anything with a collider that you want to be able to click on must have a script attached with a function in it called OnLeftClick. If it is one of the petals you might want something like

 function OnLeftClick(raycastHit : RaycastHit2D)
 {
 //  print("ok");
     Destroy(gameObject);
 }

Step 3: Re-writing the script to use z depth won't be too complex (afraid I don't have time to do it right now) but it would be something like, where you see this code:

 // Loop through the array of raycast hits...
                 for (var i = 0; i < hits.length; i++)
                 {
                         // Get the SpriteRenderer from each game object under the click.
                         spriteRenderer = hits[i].collider.gameObject.GetComponent(SpriteRenderer);
                
                         // Access the sortingLayerID through the SpriteRenderer and store it in the sortingLayerIDArray.
                         sortingLayerIDArray[i] = spriteRenderer.sortingLayerID;
                        
                         // Access the sortingOrder through the SpriteRenderer and store it in the sortingOrderArray.
                         sortingOrderArray[i] = spriteRenderer.sortingOrder;
                 }


Don't bother accessing the sprite renderer at all and just store the z depth in an array:

 hitDepth = hits[i].collider.transform.position;

And then where you see this code:

 // Loop through the array of sprite sorting layer IDs...
                 for (var j = 0; j < sortingLayerIDArray.length; j++)
                 {
                         // If the sortingLayerID is higher that the topSortingLayer...
                         if (sortingLayerIDArray[j] >= topSortingLayer)
                         {
                                 topSortingLayer = sortingLayerIDArray[j];
                                 indexOfTopSortingLayer = j;
                         }
                 }


Put something like:

     if (hitDepth[j] >= topSortingLayer)
                                 {
                                         topSortingLayer = hitDepth[j];
                                         hitDepthOfTopSortingLayer = j;
                                 }


Hope that helps, I wish I had more time to rewrite the code properly. Let me know how you get on, I'd love to include a link to a Z depth sorting sprite clicker on the site :)

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 Omer.Hussain · Apr 22, 2014 at 12:53 PM 0
Share

@Romano i feel like suffering from Hell ... ahhhhh why its so tough for me... i changed the code now it destroy few of the petals but doesn't destroy remaining... kindly check if i missed something in both scripts...all petals are layerd default

  function OnLeftClick(raycastHit : RaycastHit2D)
     {
     // print("ok");
     Destroy(gameObject);
     }


avatar image
0

Answer by Omer.Hussain · Apr 22, 2014 at 01:20 PM

 #pragma strict
  
 private var leftClickedObject : GameObject;
 private var rightClickedObject : GameObject;
 private var frontmostRaycastHit : RaycastHit2D;
 //private var hitDepth[]:Transform;
  
 // It's necessary to access the SpriteRenderer of a game object to be able to access its sorting layer ID
 // and sorting order ("Order in Layer" in the inspector)
 private var spriteRenderer : SpriteRenderer;
  
 function Update ()
 {
         // If the left mouse button is clicked anywhere...
         if (Input.GetMouseButtonDown(0))
         {
                 // frontmostRaycastHit stores information about the RaycastHit2D that is returned by GetFrontmostRaycastHit()
                 frontmostRaycastHit = GetFrontmostRaycastHit();
  
                 // If frontmostRaycastHit is true, i,e the user hasn't clicked on nothing, i.e GetFrontmostRaycastHit() didn't return nothing...
                 if (frontmostRaycastHit)
                 {
                         // Assigns the game object that the collider that has been clicked on to leftClickedObject.
                         leftClickedObject = frontmostRaycastHit.collider.gameObject;
                        
                         // Sends the frontmostRaycast to a function called OnLeftClick in a script attached to whatever the leftClickedObject is.
                         leftClickedObject.SendMessage("OnLeftClick", frontmostRaycastHit, SendMessageOptions.DontRequireReceiver);
                 }
         }
         // If the right mouse button is clicked anywhere...
         else if (Input.GetMouseButtonDown(1))
         {
                 // frontmostRaycastHit stores information about the RaycastHit2D that is returned by GetFrontmostRaycastHit()
                 frontmostRaycastHit = GetFrontmostRaycastHit();
  
                 // If frontmostRaycastHit is true, i,e the user hasn't clicked on nothing, i.e GetFrontmostRaycastHit() didn't return nothing...
                 if (frontmostRaycastHit)
                 {
                         // Assigns the game object that the collider that has been clicked on to rightClickedObject.
                         rightClickedObject = frontmostRaycastHit.collider.gameObject;
                        
                         // Sends the frontmostRaycast to a function called OnLeftClick in a script attached to whatever the rightClickedObject is.
                         rightClickedObject.SendMessage("OnRightClick", frontmostRaycastHit, SendMessageOptions.DontRequireReceiver);
                 }
         }
 }
  
 function GetFrontmostRaycastHit(): RaycastHit2D
 {
         // 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 (to the same click position - more a dot than a ray) and store them in an array called "hits".
         var hits : RaycastHit2D[] = Physics2D.LinecastAll (clickPosition, clickPosition);
  
         // If the raycast hits something...
         if (hits.length != 0)
         {
                 // A variable that will store the frontmost sorting layer that contains an object that has been clicked on as an int.
                 var topSortingLayer : int = 0;
                 // A variable that will store the index of the top sorting layer as an int.
                 var indexOfTopSortingLayer : int;
                 var hitDepthOfTopSortingLayer: int;
                 // An array that stores the IDs of all the sorting layers that contain a sprite in the path of the linecast.
                 var sortingLayerIDArray : int[] = new int[hits.length];
                 // An array that stores the sorting orders of each sprite that has been hit by the linecast
                 var sortingOrderArray : int[] = new int[hits.length];
                 // An array that stores the sorting order number of the frontmost sprite that has been clicked.
                 var topSortingOrder : int = 0;
                 // A variable that will store the index in the sortingOrderArray where topSortingOrder is. This index used with the hits array will give us our frontmost clicked sprite.
                 var indexOfTopSortingOrder : int;
  
                 // Loop through the array of raycast hits...
                 for (var i = 0; i < hits.length; i++)
                 {
 //                        // Get the SpriteRenderer from each game object under the click.
 //                        spriteRenderer = hits[i].collider.gameObject.GetComponent(SpriteRenderer);
 //               
 //                        // Access the sortingLayerID through the SpriteRenderer and store it in the sortingLayerIDArray.
 //                        sortingLayerIDArray[i] = spriteRenderer.sortingLayerID;
 //                       
 //                        // Access the sortingOrder through the SpriteRenderer and store it in the sortingOrderArray.
 //                        sortingOrderArray[i] = spriteRenderer.sortingOrder;
                     var    hitDepth = hits[i].collider.transform.position;
                 }
                
                 // Loop through the array of sprite sorting layer IDs...
                 for (var j = 0; j < sortingLayerIDArray.length; j++)
                 {
                         // If the sortingLayerID is higher that the topSortingLayer...
 //                        if (sortingLayerIDArray[j] >= topSortingLayer)
 //                        {
 //                                topSortingLayer = sortingLayerIDArray[j];
 //                                indexOfTopSortingLayer = j;
 //                        }
                                  if (hitDepth[j] >= topSortingLayer)
                             {
                             topSortingLayer = hitDepth[j];
                             hitDepthOfTopSortingLayer = j;
                             }
                         
                 }
  
                 // Loop through the array of sprite sorting orders...
                 for (var k = 0; k < sortingOrderArray.length; k++)
                 {
                         // If the sorting order of the sprite is higher than topSortingOrder AND the sprite is on the top sorting layer...
 //                        if (sortingOrderArray[k] >= topSortingOrder && sortingLayerIDArray[k] == topSortingLayer)
 //                        {
 //                                topSortingOrder = sortingOrderArray[k];
 //                                indexOfTopSortingOrder = k;
 //                        }
 //                        else
 //                        {
 //                                // Do nothing and continue loop.
 //                        }
                          if (hitDepth[k] >= topSortingLayer)
                             {
                             topSortingLayer = hitDepth[k];
                             hitDepthOfTopSortingLayer = k;
                                         }
                                        
                          
                 // How many sprites with colliders attached are underneath the click?
                 Debug.Log("How many sprites have been clicked on: " + hits.length);
                
                 // Which is the sorting layer of the frontmost clicked sprite?
                 Debug.Log("Frontmost sorting layer ID: "+ topSortingLayer);
                
                 // Which is the order in that sorting layer of the frontmost clicked sprite?
                 Debug.Log("Frontmost order in layer: "+ topSortingOrder);
  
                 // The indexOfTopSortingOrder will also be the index of the frontmost raycast hit in the array "hits".
                 return hits[indexOfTopSortingOrder];
         }
         }
         else // If the hits array has a length of 0 then nothing has been clicked...
         {
                 Debug.Log("Nothing clicked.");
                 return;
         }
 }
Comment
Add comment · Show 3 · 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 · Apr 23, 2014 at 10:00 AM 0
Share

Hi Omer, did you have any luck with this? Are you using Orthographic or Perspective camera?

avatar image Omer.Hussain · Apr 24, 2014 at 06:09 AM 0
Share

Hi @Romano that didn't work. may be i missed something in changing the code.. i have wrote it above... camera is set at Orthographic.. but i somehow sort out the problem.. it is written above so anyone else could use it ... :) .. i just changed the 2dbox collider into polygon collider and it worked :p ...

avatar image Romano · Apr 24, 2014 at 06:19 AM 0
Share

You would have to have re-written the depth sorting part to include z depth to make that method work. Polygon colliders would also have to be used to make it work.

Putting the code that deals with clicks in one place (i.e attached to the camera) is a good idea if you have a lot of things to click and don't want to attach the On$$anonymous$$ouseDown code to every object that needs clicked. But if there's not so many things to be clicked your method should work just fine :)

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.

Welcome to Unity Answers

The best place to ask and answer questions about development with Unity.

To help users navigate the site we have posted a site navigation guide.

If you are a new user to Unity Answers, check out our FAQ for more information.

Make sure to check out our Knowledge Base for commonly asked Unity questions.

If you are a moderator, see our Moderator Guidelines page.

We are making improvements to UA, see the list of changes.



Follow this Question

Answers Answers and Comments

23 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

Related Questions

Move Towards Target Color 2 Answers

A node in a childnode? 1 Answer

Custom Pivot Points in Sprite Editor 1 Answer

How to count numbers on onmousedown? 1 Answer

Sprite animate on start ? 1 Answer

  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges