Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • 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
2
Question by Hiilo · Sep 29, 2013 at 06:48 PM · 2dmouseclickordering

Best way to click on a object behind other

Hi. This is a bit more general question.

I made a quick illustration about my problem Z order, depth order illustration

And my question is: what would be the best way to ensure that when I click on any of those objects coloured area, then that object actually gets clicked/hit, even if it actually is behind other objects. Basically all the objects are simple plane meshes with some textures on them. The textures are transparent where theres no colour. So for example in my illustration if I would click in the marked point I would like the green sphere to get selected, but the problem is that it lays behind both of the other objects mesh/collider, so actually the red cross would get selected.

Now I did some research and there seem to be some solutions out there that detect if the hit point pixel is transparent or not. For example this one but Im worried that even if I could detect that I clicked on the transparent part of Object Z1 then I wouldn't know how to make the ray keep going until it hits a actual pixel. Another thought I had was to make custom meshes or even only collider meshes for each of the object's, but that seems a lot of manual labor.

So in conclusion should I go with:

  • a) Detecting pixel alphas

  • b) Custom meshes for each object

  • c) Something totally different ???

Any guidance much appreciated!

Sry if too long for Answers.

z-order-problem.png (26.6 kB)
Comment
Add comment
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

2 Replies

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

Answer by Professor Snake · Sep 29, 2013 at 06:53 PM

You can use RaycastHit.textureCoord to get the UV coordinates of the texture at the point you hit the object. Then you need to use Texture2D.GetPixel, and check that pixel's alpha value. If the alpha value is near zero (or below a transparency threshold), temporarily disable that object's collider and do another identical raycast, repeating the process until you hit something or the raycast returns false. Don't forget to re-enable the colliders once everything is finished.

Comment
Add comment · Show 2 · 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 Hiilo · Sep 29, 2013 at 07:02 PM 0
Share

Thank you for the answer. All the things you talk about seem doable. How should I deal with the objects that get they'r colliders disabled? Should I collect them in to an array? Because as in my example I should disable two objects before I get to the green sphere.

avatar image Professor Snake · Sep 30, 2013 at 01:15 PM 0
Share

You should indeed collect them in an array. If you don't want to use the Array class, use this simple function to increase the size of a "normal" array:

 function IncreaseArray(arr:Transform[]):Transform[]{
   if(arr.length==0){
     return new Transform[1];
   }
   var newArr:Transform[]=new Transform[arr.length+1];
   for(var i:int=0;i<arr.length;i++)
     newArr[i]=arr[i];
   return newArr;
 }

Then you'd just do

 disabledObjectsArray=IncreaseArray(disabledObjectsArray);
 disabledObjectsArray[disabledObjectsArray.length-1]=what we hit;
avatar image
3

Answer by Hiilo · Oct 27, 2013 at 11:40 AM

Thought I'll share my final code I got working.

 using UnityEngine;
 using System.Collections;
 using System.Linq;
 using System.Collections.Generic;
 using System;
 public class AlphaTest : MonoBehaviour {
     
     private RaycastHit[] hits;
     private Ray ray;
     Camera myCam;
     private GameObject selectedPlayer = null;
     List<GameObject> disabledGameobjects = new List<GameObject>();
     List<RaycastResult> hitList = new List<RaycastResult>();
     
     // Use this for initialization
     void Start () {
     myCam=Camera.main;
     }
     
     
     public class RaycastResult: IComparable<RaycastResult>
     {
         public float distance;
         public Collider collider;
         public Vector2 textureCoord;
         public RaycastResult(RaycastHit hit)
         {
             distance = hit.distance;
             collider = hit.collider;
             textureCoord = hit.textureCoord;
         }
      
         public int CompareTo(RaycastResult other)
         {
             return distance.CompareTo(other.distance);
         }
     }
     
     void SortDistances()
     {
         hitList.Clear();
         hits= Physics.RaycastAll(ray);
      
         foreach(RaycastHit hit in hits)
         {
             hitList.Add(new RaycastResult(hit));
         }
         hitList.Sort();
     }
     
     void Update() {
         ray = myCam.ScreenPointToRay(Input.mousePosition);
         //When mouse left button is pressed down | This Fires only once
         if(Input.GetMouseButtonDown(0)){
             SortDistances();
             
             Debug.Log("HIT-----------------------------");
             foreach(RaycastHit hit in hits){
                 Debug.Log(hit.collider.name+""+hit.distance);
                 
             }
             Debug.Log("LIST-----------------------------");
             foreach(RaycastResult listItem in hitList){
                 Debug.Log(listItem.distance);
             }
             
             
                 for(int i=0;i<hitList.Count;i++)
                 {    
                     
                     if(hitList[i].collider.tag=="Player")
                     {
                         selectedPlayer = hitList[i].collider.transform.gameObject;
                     
                         Renderer renderer = hitList[i].collider.renderer;
                         MeshCollider meshCollider = hitList[i].collider as MeshCollider;
                         if (renderer == null || renderer.sharedMaterial == null || renderer.sharedMaterial.mainTexture == null || meshCollider == null)
                             return;
                         
                         Texture2D texture = renderer.material.mainTexture as Texture2D;
                         Vector2 pixelUV = hitList[i].textureCoord;
                         pixelUV.x *= texture.width;
                         pixelUV.y *= texture.height;
                         
                         Color pixel = texture.GetPixel((int)pixelUV.x, (int)pixelUV.y);
                         //Debug.Log(pixel.a);
                         if(pixel.a < 1){
                         //We hit a transparent pixel
                             selectedPlayer.renderer.material.color = Color.black;
                             selectedPlayer.collider.enabled=false;
                             disabledGameobjects.Add(selectedPlayer);
                         }
                         else if(pixel.a >= 1){
                         //We did not hit a transparent pixel
                             selectedPlayer.renderer.material.color = Color.white;
                             //Debug.Log(selectedPlayer.name);
                             return;
                         }
                         
                     }
                 
                 }    
         
         }
         //While mouse left button is held down| This Fires every frame
         if(Input.GetMouseButton(0)){
             
         }
         //When mouse left button is released | This Fires only once
         if(Input.GetMouseButtonUp(0)){
             foreach(GameObject disabledGameobject in disabledGameobjects){
                 disabledGameobject.collider.enabled=true;
                 disabledGameobject.renderer.material.color=Color.white;
             }
             disabledGameobjects.Clear();
         
         }
         
     }
     
 }

A couple of notes. All the textures have to have Read/Write enabled and a compression format that allows alpha.For example RGBA 32 bit Also this code works only with Meshcolliders. I'm also using a IComparable to order RaycastAll results. It could be done with Linq but I had problems with Linq on IOS.

Anyway hope somebody finds this useful.

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 stephenmcintyre · May 09, 2017 at 09:55 AM 0
Share

Update for Unity 5.6:

Replace collider with GetComponent(), and renderer with GetComponent()

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

17 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

Related Questions

Trail Renderer detection 0 Answers

Hard time getting mouse click to work 2 Answers

How to prevent 2d objects go over each other? 1 Answer

IgnoreCollision doesnt work? 0 Answers

Assets/Scripts/PlayerController.cs(32,49): error CS0126: An object of a type convertible to `float' is required for the return statement 1 Answer


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