0
\$\begingroup\$

I'm stuck trying to figure out how I can select the top most GameObject in a stack of GameObjects. In the picture below, I have a Green and Yellow circle stacked on top of each other. If I try to select the top most gameobject (the green one), it selects the yellow circle. Is there a way that I can make sure that when I go to select a circle, it selects the top most one? I'm currently using the OnMouseDown() function built into unity.

Update Sorting the colors on the z axis did not solve the problem. I'm still trying to figure out a solution

enter image description here

\$\endgroup\$
  • 1
    \$\begingroup\$ Have you considered separating your objects on the z axis, so there's a consistent ordering to both the display and raycast queries? \$\endgroup\$ – DMGregory Feb 23 at 18:28
  • \$\begingroup\$ I have and it was still doing the same thing. It didn't seem to matter on where they were placed on the z axis \$\endgroup\$ – Michael Hampshire Feb 23 at 18:42
0
\$\begingroup\$

Instead of putting a script with an OnMouseDown method on every single game object, create one game object with an update-function which

  1. uses Input.GetMouseButtonDown(0), Input.GetAxis("Mouse X") and Input.GetAxis("Mouse Y") to read the mouse state
  2. converts the mouse position on the screen into a ray from the camera positon into the scene using Camera.ScreenPointToRay.
  3. Detects the first collider which touches that ray using Physics.Raycast or Physics2D.Raycast depending on whether your objects have 3d or 2d colliders.

This, of course, requires that the render order of your SpriteRenderers is managed by their z-position, not by render layeres or orders in those render layers.

Code example (untested!)

void Update() {

      if (Input.GetMouseButtonDown(0)) {
            Vector3 mousePosition = new Vector3(Input.GetAxis("Mouse X"),
                                                Input.GetAxis("Mouse Y"),
                                                0.0f);
            Ray mouseRay = Camera.main.ScreenPointToRay(mousePosition); 
            RaycastHit hit;
            if(Physics.Raycast(mouseRay, out hit)) {
                  GameObject clickedObject = hit.collider.gameObject;
                  // do what you want to do with clickedObject
            };
      }
}

One advantage of this architecture over OnMouseDown is that you decouple the input logic from the game mechanics. If you later want to add different ways to select objects, you don't need to implement that logic in the scripts which handle the game mechanics of selectable objects. You can contain these selection methods in separate scripts. The clicked object might know it is selected, but doesn't need to know how exactly it was selected.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Thank you for the reply, I will give it a shot when I get home! \$\endgroup\$ – Michael Hampshire Feb 26 at 14:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.