Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

RaycastHit2D does not hit the object on top

Discussion in 'Scripting' started by pKallv, Jun 22, 2014.

  1. pKallv

    pKallv

    Joined:
    Mar 2, 2014
    Posts:
    1,122
    I am trying to select an object on top that have the highest sortingOrder (25 of 25 objects), which i fix in another part of the code and that works.

    Here is the sequence:

    1. I have 25 cards placed on the game board
    2. If i double click/raycast on an object i put it on top, as in the picture below were i have selected Queen of Hearts, as well as recalculate the sortingOrder so the card on top always have the highest (25) and the other lower (works)
    3. I then click on the Queen of Hearts (HQ), which is on top, and here is were it fails and HQ is not selected



    Here is the code i use:

    Code (csharp):
    1.  
    2. void SingleTap (Tap Gesture gesture) {
    3.     //Select only the objects below the mouse x & y vector
    4.     LayerMasktheLayer;
    5.     theLayer = (1 << LayerMask.NameToLayer("Cards")); //set the layer to be clickable
    6.     Vector2 clickedPos = Camera.main.ScreenToWorldPoint (Input.mousePosition);
    7.     //Get current worldspace position of mouse cursor
    8.     RaycastHit2D[] hits = Physics2D.LinecastAll(clickedPos,clickedPos,theLayer);
    9.  
    10.     int oo = hits.Length;
    11.  
    12.     for (int tt = 0; tt < oo; tt++) {
    13.         print ("Single: " + tt + ": " + hits[tt].transform.tag + " /// " + hits[tt].transform.name);
    14.      }
    15. }
    16.  
    The result i get when i click/raycast on the Queen of Hearts, it is located at index = 4 rather than index = 0 which i would expect:

    Code (csharp):
    1.  
    2. Single: 0: S3 /// S3(Clone)
    3. Single: 1: S4 /// S4(Clone)
    4. Single: 2: SA /// SA(Clone)
    5. Single: 3: S2 /// S2(Clone)
    6. Single: 4: HQ /// HQ(Clone)
    7. Single: 5: HK /// HK(Clone)
    8. Single: 6: H10 /// H10(Clone)
    9. Single: 7: HJ /// HJ(Clone)
    10. Single: 8: H8 /// H8(Clone)
    11. Single: 9: H9 /// H9(Clone)
    12. Single: 10: H6 /// H6(Clone)
    13. Single: 11: H7 /// H7(Clone)
    14. Single: 12: H4 /// H4(Clone)
    15. Single: 13: H5 /// H5(Clone)
    16. Single: 14: H3 /// H3(Clone)
    17.  
    They all have BoxCollider2D that cover the full object:



    I would assume the the HQ should be selected as the #1 (index 0) and do not understand why it is not and how to select, in this example, the HQ.

    I would really appreciate some help.
     

    Attached Files:

    • ex.png
      ex.png
      File size:
      130 KB
      Views:
      759
  2. TylerPerry

    TylerPerry

    Joined:
    May 29, 2011
    Posts:
    5,577
    I haven't used the 2D collision stuff but I would assume that RayCast2D is used for checking stuff horizontally and vertically, but for depth its probably not appropriate. You might want to try OverlapPoint instead, using your clickedPos.
     
  3. Fluzing

    Fluzing

    Joined:
    Apr 5, 2013
    Posts:
    815
    Why not disable the colliders of the cards that are not on top?
     
  4. TylerPerry

    TylerPerry

    Joined:
    May 29, 2011
    Posts:
    5,577
    The sorting layers might only be relevant to the renderer, you could try adding something so that when you space them out they actually are placed in increments of 0.1 or something like that so the top one is actually physically clearly on top.
     
  5. pKallv

    pKallv

    Joined:
    Mar 2, 2014
    Posts:
    1,122
    I thought of that but what to do if the player click on another object?
     
  6. zaxvax

    zaxvax

    Joined:
    Jun 9, 2012
    Posts:
    220
    Can you change debug message a lil bit and put here output?

    Code (JavaScript):
    1.  print ("Single: " + tt + ": " + hits[tt].transform.tag + " : " + hits[tt].point + " /// " + hits[tt].transform.name);
     
    Last edited: Jun 22, 2014
  7. pKallv

    pKallv

    Joined:
    Mar 2, 2014
    Posts:
    1,122
    Code (csharp):
    1.  
    2. Single: 0: S7 : (-0.1, -0.1, 5.0) /// S7(Clone)
    3. Single: 1: S5 : (-0.3, -0.3, 5.0) /// S5(Clone)
    4. Single: 2: S6 : (-0.2, -0.2, 5.0) /// S6(Clone)
    5. Single: 3: S3 : (-0.5, -0.5, 5.0) /// S3(Clone)
    6. Single: 4: S4 : (-0.4, -0.4, 5.0) /// S4(Clone)
    7. Single: 5: SA : (-0.7, -0.7, 5.0) /// SA(Clone)
    8. Single: 6: S2 : (-0.6, -0.6, 5.0) /// S2(Clone)
    9. Single: 7: HQ : (-0.9, -0.9, 5.0) /// HQ(Clone)
    10. Single: 8: HK : (-0.8, -0.8, 5.0) /// HK(Clone)
    11. Single: 9: H10 : (-1.1, -1.1, 5.0) /// H10(Clone)
    12. Single: 10: HJ : (-1.0, -1.0, 5.0) /// HJ(Clone)
    13. Single: 11: H8 : (-1.3, -1.3, 5.0) /// H8(Clone)
    14. Single: 12: H9 : (-1.2, -1.2, 5.0) /// H9(Clone)
    15. Single: 13: H6 : (-1.5, -1.5, 5.0) /// H6(Clone)
    16. Single: 14: H7 : (-1.4, -1.4, 5.0) /// H7(Clone)
    17.  
     
  8. zaxvax

    zaxvax

    Joined:
    Jun 9, 2012
    Posts:
    220
    Aha so z is the same.. well you can use z to sort the stack of cards. LinecastAll by default will go through all of the z layers.
    This way even if cards in hits[] are unsorted, you can sort hits[] collection by hits[].transform.position.z
    Or just go through all of them to select one with biggest z, if you only search for a top card.
     
  9. pKallv

    pKallv

    Joined:
    Mar 2, 2014
    Posts:
    1,122
    This is driving me crazy and to make it more simple i have created a new project with basic code to test this. The following is the new scene, the cross indicates were i click:



    SortingOrder and z is 0 (HA) to 12 (HK with cross).

    When i click on the cross (HK) the result is "hit: H5".

    The full code is:

    Code (csharp):
    1.  
    2. usingUnityEngine;
    3. usingSystem.Collections;
    4. usingSystem.Collections.Generic;
    5. usingSystem.Linq;
    6.  
    7. public class MainScript : MonoBehaviour {
    8.  
    9.     public static List<string> cardDeckList = new List<string> {
    10.     "HA", "H2", "H3", "H4", "H5", "H6", "H7", "H8", "H9", "H10", "HJ", "HQ", "HK",};
    11.  
    12.     public static List<GameObject> master_GameObject_List = newList<GameObject> ();
    13.     private static List<string> temporary_CardDeck_List = newList<string> ();
    14.     private GameObject tempGameObject;
    15.     public float posPointer = -2.0f;
    16.     public float addPositionDifferentiator = 0.3f;
    17.     private float zDepthCounter = 0f;
    18.     private int sortOrderLoop = 0;
    19.     private int nrOfCardsInTheGame;
    20.     public Vector3 objectScale_v3 = new Vector3(1.2f, 1.2f, 1.0f);
    21.  
    22.     voidStart () {
    23.  
    24.         foreach (stringaCardincardDeckList) {
    25.             tempGameObject = Resources.Load(aCard) asGameObject;
    26.             tempGameObject.transform.position = newVector3(posPointer, posPointer, zDepthCounter);
    27.             tempGameObject.renderer.sortingOrder = sortOrderLoop;
    28.             tempGameObject.transform.localScale = objectScale_v3;
    29.             Instantiate(tempGameObject);
    30.  
    31.             sortOrderLoop++;
    32.             zDepthCounter++;
    33.             posPointer = posPointer + addPositionDifferentiator;
    34.  
    35.             master_GameObject_List.Add(tempGameObject);
    36.         }
    37.      }
    38.  
    39.     void DoubleTap(TapGesturegesture) {
    40.         print ("<<<DoubleTap>>>");
    41.  
    42.         RaycastHit2Dhit = Physics2D.Raycast(transform.position, -Vector2.up);
    43.         if (hit.collider != null) {
    44.             print ("hit: " + hit.collider.tag);
    45.         }
    46.     }
    47. }
    48.  
     
  10. pKallv

    pKallv

    Joined:
    Mar 2, 2014
    Posts:
    1,122
    I updated the DoubleTap and changed the ray cast to linecastall:
    Code (csharp):
    1.  
    2. void DoubleTap(TapGesturegesture) {
    3.     LayerMask theLayer;
    4.     theLayer = (1 << LayerMask.NameToLayer("Card"));
    5.     Vector2 clickedPos = Camera.main.ScreenToWorldPoint (Input.mousePosition);
    6.     RaycastHit2D[] hits = Physics2D.LinecastAll(clickedPos,clickedPos,theLayer);
    7.  
    8.     int oo = hits.Length;
    9.  
    10.     for (int tt = 0; tt < oo; tt++) {
    11.         print ("Single: " + tt + ": " + hits[tt].transform.tag + " /// " + hits[tt].transform.name);
    12.      }
    13. }
    14.  
    then i got the following result when clicking on the same spot:

    Code (csharp):
    1.  
    2. Single: 0: HJ /// HJ(Clone)
    3. Single: 1: HQ /// HQ(Clone)
    4. Single: 2: HK /// HK(Clone)
    5.  
    This shows that the hit array always catch the object that is clicked ends up in the end of the array. I also tested with a higher density in the card layout so there was more cards under the linecast with the same result and I can select the last object in the array. I guess this means that i will be able to work from here and problem solved (i think). Thanks :)
     
  11. zaxvax

    zaxvax

    Joined:
    Jun 9, 2012
    Posts:
    220
    here is a small demo for you about z layers :)
     

    Attached Files:

    pKallv and TylerPerry like this.
  12. pKallv

    pKallv

    Joined:
    Mar 2, 2014
    Posts:
    1,122
    Thank you zaxvax very nice of you :)
     
  13. pKallv

    pKallv

    Joined:
    Mar 2, 2014
    Posts:
    1,122
    I finally succeeded to create what i needed: 1.) Always hit the correct and the whole BoxCollider2D, 2.) Always move the selected object to the top.

    Here is the code:

    Code (csharp):
    1.  
    2. List<GameObject> RefreshSortOrderAndZandPutObjectOnTop (List<GameObject>theList, GameObject selectedGO) {
    3.  
    4.     List<GameObject> dummyTheList = newList<GameObject> ();
    5.     float zz = 0;
    6.     int sorting = 0;
    7.  
    8.     //Fix sortingorder
    9.     foreach (GameObject aGO in theList) {
    10.         tempGameObject = GameObject.FindWithTag(aGO.tag);
    11.  
    12.         if (tempGameObject.tag == selectedGO.tag) {
    13.             tempGameObject.renderer.sortingOrder = 500;
    14.         }
    15.         dummyTheList.Add(tempGameObject);
    16.     }
    17.  
    18.     //Sort List on SortingOrder
    19.     dummyTheList = dummyTheList.OrderBy(go=>go.renderer.sortingOrder).ToList();
    20.  
    21.     theList.Clear ();
    22.  
    23.     foreach (GameObject aGO in dummyTheList) {
    24.         tempGameObject = GameObject.FindWithTag(aGO.tag);
    25.         tempGameObject.renderer.sortingOrder = sorting;
    26.         tempGameObject.transform.position = newVector3(tempGameObject.transform.position.x,  
    27.                              tempGameObject.transform.position.y, zz);
    28.         theList.Add(tempGameObject);
    29.         zz++;
    30.         sorting++;
    31.     }
    32.  
    33.     return theList;
    34. }
    35.  
    Maybe not the most elegant code but it works perfectly for me :)
     
    Last edited: Jun 23, 2014