- Home /
How to apply OnMouseDown on sprites according to z position...
Hi! 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);
}
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.
are you attaching collider with this sprite... you need to!
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);
}
}
}
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.
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 }
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 :)
@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);
}
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;
}
}
Hi Omer, did you have any luck with this? Are you using Orthographic or Perspective camera?
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 ...
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
Follow this Question
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
How do we instantiate random sprites from an array... 1 Answer