Search Unity

Touch Point to World Point

Discussion in 'Scripting' started by renman3000, Jan 17, 2012.

  1. renman3000

    renman3000

    Joined:
    Nov 7, 2011
    Posts:
    6,699
    Hi there,
    what is the best way to convert a touch point in iOS (or other) to a world point?

    Currently I am using...
    Code (csharp):
    1.  
    2.         var i : Vector2 = Input.GetTouch(0).position;
    3.         print("i " +  i);
    4.         var p : Vector3 = Camera.main.ScreenToWorldPoint (Vector3 (i.x,i.y,0));
    5.         print("p " + p);
    6.  
    but it is crashing the system. I am sure var p is the issue.


    Thanks
     
  2. svenskefan

    svenskefan

    Joined:
    Nov 26, 2008
    Posts:
    282
    you need to check that you actually have some touch data to work on first.
    Check you Input.touchcount or similar, otherwise you will be working on null data...
     
  3. renman3000

    renman3000

    Joined:
    Nov 7, 2011
    Posts:
    6,699
    Well,
    Like i said,
    The first var definitly exsists.
    It returns.
    When i add in the second line, xcode gives me a gdb crash.
     
  4. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Either way - sven is correct just for the sake of preventing the code from executing when there is no touch - regardless of whether or not it returns a value.

    Also -
    var p : Vector3 = Camera.main.ScreenToWorldPoint (Vector3 (i.x,i.y,0));
    should probably be
    var p : Vector3 = Camera.main.ScreenToWorldPoint (new Vector3(i.x,i.y,0));
     
  5. renman3000

    renman3000

    Joined:
    Nov 7, 2011
    Posts:
    6,699
    Thanks,
    It solved the crash. I was not expecting to see "new" being the answer. I was completely unaware that that was even an option.

    However, this is resulting in bad results. Meaning, that everytime I enter the touch position, my return in world space via....

    var i : Vector2 = Input.GetTouch(0).position;
    print("i " + i);
    var p : Vector3 = Camera.main.ScreenToWorldPoint (new Vector3 (i.x,i.y,0));
    print("p " + p);
    ... p is always (0.0, 0.0, -10.0).




    :.?
     
    Last edited: Jan 18, 2012
  6. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Vector3(,,,) would attempt to cast the values in parenthesis as a Vector3. Since Vector3 is a struct and structs by definition are immutable this doesn't work very well. new Vector3(,,,) explicitly creates a new Vector3 with the given values.

    What you have is really not a good pattern as its not specific enough. I would go this route

    Code (csharp):
    1.  
    2. void Update()
    3. {
    4.     for (int i = 0; i < Input.touchCount; i++)
    5.     {
    6.         if (Input.GetTouch(i).phase == TouchPhase.Began)
    7.         {
    8.             Vector3 p = Camera.main.ScreenToWorldPoint(Input.GetTouch(i).position);
    9.             Debug.Log(p);
    10.         }
    11.     }
    12. }
    13.  
     
  7. renman3000

    renman3000

    Joined:
    Nov 7, 2011
    Posts:
    6,699
    ok,
    As of now, I am using this...
    Code (csharp):
    1.  
    2.  
    3. function Update ()
    4. {
    5.  
    6.     if (Input.touchCount == 1)
    7.     {
    8.         ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
    9.         if (Physics.Raycast(ray, hit))
    10.         {
    11.             print("wpn realm hit");
    12.             var i : Vector2 = Input.GetTouch(0).position;
    13.             print("i " +  i);
    14.             var p : Vector3 = Camera.main.ScreenToWorldPoint (Input.GetTouch(0).position);
    15.             print("p " + p);
    16.         }
    17.     }
    18. }
    19.  
    however the crash has returned.






    edit:
    I adjusted it to this tho...
    Code (csharp):
    1.        
    2. print("wpn realm hit");
    3.             var i : Vector2 = Input.GetTouch(0).position;
    4.             var p : Vector3 = Camera.main.ScreenToWorldPoint (new Vector3(i.x, i.y, 0) );
    5.             print("p " + p);
    6.  
    ...and p returns 0,0,-10.


    stumped at the moment.
     
    Last edited: Jan 18, 2012
  8. Diviner

    Diviner

    Joined:
    May 8, 2010
    Posts:
    677
    You can try and do the reverse (which doesn't include raycasting btw).

    You can get the position of an object in world space, translate its coordinates to screen coordinates, put them in the form of a rect struct (by applying width and height to your discretion) and check via the Contains method if the touch position is contained within that rectangle. I am going to provide the code below out the top of my head so you might need to do a bit of testing to make sure it works as intended.

    Code (csharp):
    1.  
    2. function Start( ) {
    3.       var thisObject : Transform = GameObject.Find("Foo").transform;
    4. }
    5.  
    6. function Update ( ) {
    7.        var thisPosition : Vector3 = Camera.main.WorldToScreenPoint (thisObject.position);
    8.        thisPosition.y = Screen.height - thisPosition.y;
    9.        var thisRect : Rect = new Rect(thisPosition.x,thisPosition,y,50,50);
    10.        for (int i = 0; i < Input.touchCount; i++) {
    11.             if (Input.GetTouch(i).phase == TouchPhase.Began  thisRect.Contains(Input.GetTouch(i).position)) {
    12.                   print("Touch detected");
    13.                   //Do something
    14.             }
    15.        }
    16. }
    17.  
    The benefit of this method is that we can circumvent the physics engine and only check for objects that are registered as "clickable". This increases performance greatly. The example above applies only to one object, but you can just as easily make a cycle through an array of objects that register on start-up as clickable to that array. This is the equivalent of using layermasks and working with raycasting, with the difference that you don't need to bother yourself managing layers.
     
  9. renman3000

    renman3000

    Joined:
    Nov 7, 2011
    Posts:
    6,699
    Ok. Thanks Diviner. That may be useful for certain scenarios. However, in my game, there is only one item, on screen, in world, beyond gui that is clickable. Essentially, my level has a large empty cube. It is invisable to the eye. Its scale extends to the size of the entire level. It simply acts as a object that will dectect when input is made and where in the world the touch was made.

    The purpose of this is to determine what angle to fire at.

    When I use this in editor, it works fine. Here I use mouse position tho.


    I have been struggling with this for far too long. It seems like it should not be this difficult.


    I had one ray of hope. It seemed for sometime my y was returning accurately, but not my x. So I thought my field of view was too small, as in world soace my screen view was about 5 units either side of 0. So I pulled back my camera, from 10 units to 70 and tested. However, the clickable returns were null.


    I am scratching my head.
    Again, I am not disregarding what you have suggested diviner, I am just not sure how, your method is more efficient or how it works. All I need is to be able to change the screen touch pos into an accurate world pos. Thats it!






    edit,
    I just remebered I had this before and I am pretty sure I had it working on my device, but I can not find the old project and script. Maybe the forums have it. D'oh!