Search Unity

Need Help ! On Math !

Discussion in 'Editor & General Support' started by Abhijit-Mukherjee, Aug 5, 2015.

  1. Abhijit-Mukherjee

    Abhijit-Mukherjee

    Joined:
    Jan 9, 2015
    Posts:
    192
    Hi Friends ,

    I am designing a 360 degree virtual control for mobile . I need some help on some kind of logical or math problem . The good news is I have all ready created the control and it is working good . But the only problem is it is not moving the player based on angular drag , it only moves on left , right, up, down, left Up, right Up , Left Down , right down based on the drag normalize vector value .

    upload_2015-8-5_11-52-18.png like this .
    I want to move it 0 to 360 degree angle .
    upload_2015-8-5_11-54-2.png

    Is It possible ?? If so how can I achieve this , Moving the player all direction .???


    Thanks,
    Abhijit M
     
  2. Not_Sure

    Not_Sure

    Joined:
    Dec 13, 2011
    Posts:
    2,610
    Dude, it says this is not a help section right in the discription for "General Discussion".

    Try posting this in the scripting section.
     
    Kiwasi likes this.
  3. Abhijit-Mukherjee

    Abhijit-Mukherjee

    Joined:
    Jan 9, 2015
    Posts:
    192
    Ok dude ..
     
  4. greggtwep16

    greggtwep16

    Joined:
    Aug 17, 2012
    Posts:
    1,511
    I'm sure this will get moved by the moderators soon, but in general you'll want the pivot of your control to be the center of the sprite. Then you will want to get where the user is touching (Vector2) and subtract that from your pivot location (also a vector2). Normailize the result (so the pixel density of the screen doesn't impact speed) so it's in a 0-1 range and now the x component is your horizontal to move and the y component is your vertical.

    Then just move the player's position accordingly.
     
    Abhijit-Mukherjee likes this.
  5. Abhijit-Mukherjee

    Abhijit-Mukherjee

    Joined:
    Jan 9, 2015
    Posts:
    192
    Thanks for the reply .. I am doing the same , I am getting the delta position (vector 2) by subtracting start Position (vector2 ) of the touch and end position of the touch , then I am doing the normalization of the delta , and then moving the player according the direction . But the problem is you will get only 8 direction to move . But can we move based on angle like 1 degree to 360 degree . Like the image i have posted above . Is it possible ? Do I need to calculate angular distance ? It should behave like Analog joystick ...
     
  6. greggtwep16

    greggtwep16

    Joined:
    Aug 17, 2012
    Posts:
    1,511
    You don't get "directions" to move but rather you get 2 floats.

    I think what you're describing is you want something similar to the right stick on a 2 stick game (for rotating the character). You generally instead of moving the character will want to use Transform.Rotate in local space for the right stick. The spinning of the character you generally just do on the Y axis on the root of the character. The looking up or down is generally applied to the camera (which is usually placed around the head of the character). That rotation would be on the X axis of the camera.
     
  7. Abhijit-Mukherjee

    Abhijit-Mukherjee

    Joined:
    Jan 9, 2015
    Posts:
    192
    Thanks Mate Again ... I don't want to rotate the player .. what i want like if I drag right upper corner with 20 degree angle then I want to move my 2d charterer (sprite ) 20 degree right up corner . Is It possible with this virtual control joystick .
     
  8. greggtwep16

    greggtwep16

    Joined:
    Aug 17, 2012
    Posts:
    1,511
    I don't have a clear picture of what you're trying to accomplish. First off, is it a 2D or 3D game? Second, describe what you want your player to do in detail when you do touch your virtual joystick. Third, you've used the term "move" at times, but at other's you mention degrees (which is usually rotation). I'm not sure if you are describing just touches, or if you are describing a "drag gesture".
     
  9. Abhijit-Mukherjee

    Abhijit-Mukherjee

    Joined:
    Jan 9, 2015
    Posts:
    192
    Hi Mate Thanks , This is a 2D game , what I mean is I have one virtual joystick control (circular one ) , So if I Touch the circular stick and drag it to right upper direction then I want to get the angle between the drag , Suppose I got angle 20 degree . So My question is Can I translate the player 20 degree right up ? Is it possible ?
     
  10. greggtwep16

    greggtwep16

    Joined:
    Aug 17, 2012
    Posts:
    1,511
    Sure this is possible, thanks for the description what you're describing is not really a virtual joystick control but rather more similar to a touchpad on a laptop for the mouse.

    Touchpad works over time not at all from a center point, but rather is a rectangular space carved out on device (or it can be the whole screen up to you). In general for a touchpad you want to each frame subtract this frames touch location from last frames touch location. This will give you the delta and you will then move the character accordingly. That way if you swipe up 20 degrees you will move the character 20 degrees.

    You will want to do this every frame rather than waiting for a start and end touch.
     
    Abhijit-Mukherjee likes this.
  11. Abhijit-Mukherjee

    Abhijit-Mukherjee

    Joined:
    Jan 9, 2015
    Posts:
    192
    Thanks Mate ,
    I am calculating the delta on Touch Moved Phase , But same functionality has to build on virtual joy stick . I can not move my stick beyond the radius .. that is the problem ... I was thinking joystick support this or not ?
     
  12. minionnz

    minionnz

    Joined:
    Jan 29, 2013
    Posts:
    391
    It should work for any direction - not just 8? I'm slightly confused here, if it's limited to 8 directions then I guess the joystick code is deliberately restricting to the 8 directions (ie: X can only be -1, 0 or 1 and Y can only be -1, 0, or 1) - but that seems unlikely based on the description you gave?

    If you want the distance as well, don't normalize it.
     
  13. greggtwep16

    greggtwep16

    Joined:
    Aug 17, 2012
    Posts:
    1,511
    Post your code, because it definitely will work for any degree movement.
     
    Abhijit-Mukherjee likes this.
  14. Abhijit-Mukherjee

    Abhijit-Mukherjee

    Joined:
    Jan 9, 2015
    Posts:
    192
    Here is the whole Code Below .
    Code (CSharp):
    1.  //touch controls
    2. using UnityEngine;
    3. using System.Collections;
    4. using UnityEngine.UI;
    5.  
    6.  
    7. public class JoyStickController : MonoBehaviour {
    8.  
    9.     // Use this for initialization
    10.     public Image stick ;
    11.     public RectTransform stickPosition;
    12.     public Vector2 StickStartingPosition;
    13.     //public Vector3 deltaPositionOfTouch;
    14.     public Vector2 deltaPositionOfTouch;
    15.     public Vector3 stickChangePosition;
    16.     public float joyStickMaxBoundary ;
    17.     public GameObject player ;
    18.     public Image PadImage ;
    19.     public Vector2 velocity;
    20.     public Rigidbody2D rb2D;
    21.     public bool touchedNotEnded ;
    22.     public Text text ;
    23.     public bool isStickDrag;
    24.  
    25.     public static float speed;
    26.     public float increment = 0.4f;
    27.     public static float distance = 0f;
    28.  
    29.  
    30.     void Start () {
    31.         StickStartingPosition = new Vector2 (stickPosition.position.x, stickPosition.position.y);
    32.  
    33.     }
    34.  
    35.     public void DragStick ()
    36.     {
    37.         isStickDrag = true;
    38.     }
    39.  
    40.     public void MovePlayer ( )
    41.     {
    42.         if (touchedNotEnded ) {
    43.             Vector3 moving = new Vector3 (0f,0f,0f);
    44.             moving = new Vector3 ((player.transform.position.x +  (Mathf.Round (deltaPositionOfTouch.x/1.2f)) ), (player.transform.position.y +  Mathf.Round(deltaPositionOfTouch.y/1.2f)), 0f);
    45.             player.transform.position = Vector3.MoveTowards (player.transform.position, moving,  speed * Time.deltaTime);
    46.        
    47.         }
    48.     }
    49.     public void MoveStickToCurrentPosition(Vector3 position, bool isMoved)
    50.     {
    51.         float x = Mathf.Round(position.x);
    52.         float y = Mathf.Round(position.y);
    53.  
    54.         Vector3 moveDistance = new Vector3 (Mathf.Clamp(x,Mathf.Round(StickStartingPosition.x) - joyStickMaxBoundary, Mathf.Round(StickStartingPosition.x) + joyStickMaxBoundary ),Mathf.Clamp(y,Mathf.Round(StickStartingPosition.y) - joyStickMaxBoundary, Mathf.Round(StickStartingPosition.y) + joyStickMaxBoundary ), 0f);
    55.         Vector2 startPoint = new Vector2 (Mathf.Round(StickStartingPosition.x),Mathf.Round(StickStartingPosition.y));
    56.         Vector2 endPoint = new Vector2 (Mathf.Round(moveDistance.x),Mathf.Round(moveDistance.y));
    57.         // Clamp the stick with radius of pad ----------------
    58.         stickPosition.position= Vector3.Lerp(stickPosition.position, moveDistance,  Time.deltaTime*500 );
    59.    
    60.         // get the distance
    61.         distance = Vector2.Distance (startPoint,endPoint);
    62.    
    63.         // get Delta position ---------------
    64.         deltaPositionOfTouch = new Vector2 (x - Mathf.Round(StickStartingPosition.x), y - Mathf.Round(StickStartingPosition.y)).normalized;
    65.         //set speed base on how far he dragged ---------------
    66.         if (distance >= 100f) {
    67.             speed = 20;
    68.         } else if (distance >= 30f && distance <100) {
    69.             speed = 15;
    70.  
    71.         } else {
    72.             speed = 2;
    73.        
    74.         }
    75.    
    76.  
    77.  
    78.  
    79.     }
    80.  
    81.  
    82.     public void MoveStickToDefaultPosition(Vector3 position, bool isEnded)
    83.     {
    84.         stickPosition.position = new Vector3 (position.x, position.y, 0f);
    85.     }
    86.  
    87.     // Update is called once per frame
    88.     void Update () {
    89.  
    90.         if ( Input.touchCount == 1)
    91.         {
    92.             Touch touch = Input.touches[0];
    93.             Vector3 touchPosition ;
    94.        
    95.             switch (touch.phase)
    96.             {
    97.             case TouchPhase.Began :
    98.                // Store the current position of the stick
    99.                 touchPosition = new Vector3(touch.position.x,  touch.position.y,0);
    100.                 touchedNotEnded = true;
    101.                 break;
    102.            
    103.             case TouchPhase.Moved :
    104.                 // Get the end touch
    105.                 deltaPositionOfTouch = new Vector3 (touch.position.x, touch.position.y,0);
    106.                 MoveStickToCurrentPosition(deltaPositionOfTouch,true);
    107.  
    108.            
    109.                 break;
    110.        
    111.            
    112.             case TouchPhase.Stationary :
    113.                 break;
    114.            
    115.             case TouchPhase.Canceled :
    116.                 MoveStickToDefaultPosition(StickStartingPosition,true);
    117.                 touchedNotEnded = false;
    118.                 isStickDrag = false;
    119.                 deltaPositionOfTouch = new Vector2 (0f,0f);
    120.                 touchPosition = new Vector3 (0f,0f,0f);
    121.                 break;
    122.  
    123.             case TouchPhase.Ended :
    124.                 MoveStickToDefaultPosition(StickStartingPosition,true);
    125.                 touchedNotEnded = false;
    126.                 isStickDrag = false;
    127.                 deltaPositionOfTouch = new Vector2 (0f,0f);
    128.                 touchPosition = new Vector3 (0f,0f,0f);
    129.                 break;
    130.             }
    131.  
    132.             if(Input.GetTouch(0).phase != TouchPhase.Ended && touchedNotEnded)
    133.             {
    134.                 MovePlayer ();
    135.             }
    136.         }
    137.  
    138.  
    139.  
    140.  
    141.  
    142.     }
    143. }
    144.  
    Here is the out put
     
    Last edited: Aug 6, 2015
    appslabs likes this.
  15. greggtwep16

    greggtwep16

    Joined:
    Aug 17, 2012
    Posts:
    1,511
    When posting code please use code blocks to make it readable. In your code there are numerous things that aren't necessary and it's a bit hard to follow (you repurpose and reassgn a couple of variables like the delta at different times). Also, you are hardcoding it to be the first touch position which isn't always the case and a couple of other things. In general though you would want to have your logic flow be more like (this is just pseudo code):
    Code (CSharp):
    1.  //touch controls
    2.             touchCount = Input.touchCount;
    3.  
    4.             if (touchCount > 0)
    5.             {
    6.                 for (int i = 0; i < touchCount; i++)
    7.                 {
    8.                     Touch touch = Input.GetTouch(i);
    9.  
    10.                     //touch somewhere on control (in between the sprites boundaries
    11.                     if (touch.position.x >= screenPixelsRect.x &&
    12.                             touch.position.x <= (screenPixelsRect.x + screenPixelsRect.width) &&
    13.                             touch.position.y >= screenPixelsRect.y &&
    14.                             touch.position.y <= (screenPixelsRect.y + screenPixelsRect.height))
    15.                     {
    16.                         //moving the nub (the graphic portion of the UI)
    17.                         nubMovement.x = touch.position.x - screenPixelsRect.center.x;
    18.                         nubMovement.y = touch.position.y - screenPixelsRect.center.y;
    19.                         nubMovement.z = 0;
    20.                         break;
    21.                     }
    22.                 }
    23.             }
    24.  
    25.             //if both are zero don't bother we're already correct
    26.             if (!(nubMovement.x == 0f && nubMovement.y == 0f))
    27.             {
    28.  
    29.                 //normalize by the dimensions of the sprite and then multiply by our sensitivity
    30.                 horizontal = (nubMovement.x / normalizeFactorX) * sensitivity;
    31.                 vertical = (nubMovement.y / normalizeFactorY) * sensitivity;
    32.  
    33.  
    34.             }
    35.  
    36.             joystickImageForeground.rectTransform.position = defaultNubPosition + nubMovement;
    37.  
    38.             transform.position += new Vector3(horizontal, vertical, 0f);
    39.  
    40.  
    41.  
     
  16. Abhijit-Mukherjee

    Abhijit-Mukherjee

    Joined:
    Jan 9, 2015
    Posts:
    192
    Thanks you for the review ... what is the normalizeFactorX ?
     
    Last edited: Aug 6, 2015
  17. Abhijit-Mukherjee

    Abhijit-Mukherjee

    Joined:
    Jan 9, 2015
    Posts:
    192
    Dose it handle the diagonal too ?
    1. //normalize by the dimensions of the sprite and then multiply by our sensitivity
    2. horizontal = (nubMovement.x / normalizeFactorX) * sensitivity;
    3. vertical = (nubMovement.y / normalizeFactorY) * sensitivity;
    transform.position+=newVector3(horizontal, vertical, 0f);
     
  18. supamigit

    supamigit

    Joined:
    Dec 2, 2012
    Posts:
    22
    Gonna say isnt there something to smooth out his points the circle controls have a feel in game of a SQUARE..

    All same love that its in Android nice one m8.. keep the updates posted so we can Resource that badboy for future users, that was if you were giving back.. =).... beauty....
     
    Abhijit-Mukherjee likes this.
  19. greggtwep16

    greggtwep16

    Joined:
    Aug 17, 2012
    Posts:
    1,511
    Yeah, it would handle diagonal, 20 degree, 73 degrees, or anything else. From a center point 0 degrees is 1 horizontal, 0 vertical. 45 degrees would be 1 horizontal, 1 vertical. 30 degrees would be sqrt(3) horizontal, 1 vertical, 90 degrees is 0 horizontal, 1 vertical. 180 is -1 horizontal 0 vertical. You normalize so that you can have reliable movement regardless of what device you play on (pixel density). When you make the joystick a fixed % of the screen the joystick sprite will probably be something like 100 x 100 on a low end device (800 x 480 resolution), but will be more than 300 x 300 pixels on a QHD phone (2560 x 1440 pixels). If you don't normalize you would actually see your character move faster on better phones, because that subtraction would be a larger number (up to 300/2 (150) from the center instead of up to 50 on a low res phone).

    What @supamigit is getting at is the sprite itself is square, but in general circles more natural to a joystick. My sample code is just pseudo code for a rough example there are many other general best practices (like the square vs. circle brought up) if you want a very polished joystick. For the square vs. circle you will want to check the distance from the center and only allow a max distance so that it is circle shaped. In addition you probably want to introduce a dead area around the center, and a max area around the edges so that slight movements of the stick don't move the character and so that the player doesn't have to be exaclty on the edge to do full speed movement. There are other best practices but the code sample is just the basics and is just psuedo code.
     
    Last edited: Aug 6, 2015
  20. Abhijit-Mukherjee

    Abhijit-Mukherjee

    Joined:
    Jan 9, 2015
    Posts:
    192
    Thank you , But I am not clear how tho get the "normalizeFactorX" , Please let me know how I need to calculate that
     
  21. greggtwep16

    greggtwep16

    Joined:
    Aug 17, 2012
    Posts:
    1,511
    the width of your sprite divided by two. Lets say your sprite is 100 pixels wide (meaning all the way left in pixels is -50 and way right is 50). Your normalizeFactorX is 50 and is what you divide by so everything stays in the -1 to 1 range.

    NormalizeFactorY is the same thing but with the height of your sprite.
     
    Abhijit-Mukherjee likes this.
  22. Abhijit-Mukherjee

    Abhijit-Mukherjee

    Joined:
    Jan 9, 2015
    Posts:
    192
    Thank You !! So actually the calculation will be like
    1. horizontal = ( 10f / -1 ) * 10
    2. Result say : -20 f ?
    so it will go to left direction ?
     
  23. greggtwep16

    greggtwep16

    Joined:
    Aug 17, 2012
    Posts:
    1,511
    No the normalize factor is never going to be negative it's the width of your sprite (the art) that you made for the background of the joystick. Saying your sprite is a negative width doesn't make sense.

    horizontal
    = (nubMovement.x / normalizeFactorX) * sensitivity;

    • horizontal = how much you are going to move your player horizontally this frame
    • nubMovement.x = where you are currently touching minus the center of your sprite (your art). Another way of saying this is it is where you are touching relative to the center of your background sprite. Why call it nubMovement? Because you generally have a separate foreground sprite that is the shape of a joystick nub. That is moving over the top of the background sprite to kind of give it the look and feel of a real joystick.
    • NormalizeFactorX = half of the width of your background sprite (in pixels)
    • sensitivity = just a constant multiplier that makes sense for the game in particular. Some characters you want to move fast, some slow. Can be any value that makes sense for your game or even a different constant per character.
    Example, lets say your art sprite is 100 pixels wide and you want to make your character super fast 20x normal. You are currently touching a half of the way left (which is 25 pixels left from the center of your sprite)

    horizontal = (-25 / 50) * 20;
    horizontal = - 10 (you are moving to the left 10 units this frame)
     
    Abhijit-Mukherjee likes this.
  24. Abhijit-Mukherjee

    Abhijit-Mukherjee

    Joined:
    Jan 9, 2015
    Posts:
    192
    Thank You ! I will give a try ... And post the result here .. My Goal is to make the movement smooth all angles ..
    screenPixelsRect : Is the screen or it i the back Ground sprite ?
     
  25. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    2,640
    Look at Mathf.Atan2.
     
  26. greggtwep16

    greggtwep16

    Joined:
    Aug 17, 2012
    Posts:
    1,511
    Background sprite, I agree that one should have been named better.
     
    Abhijit-Mukherjee likes this.
  27. Abhijit-Mukherjee

    Abhijit-Mukherjee

    Joined:
    Jan 9, 2015
    Posts:
    192
    Thank You ! I dont want to rotate the player .. What I need a smooths perfect circular movement of player while I move my circular joystick in a circular path .. Please refer my video where I was doing the same action , But the problem is it not moving proper circular away , it moving like square path ... I really don't know . whether my exception is correct or not .
     
  28. minionnz

    minionnz

    Joined:
    Jan 29, 2013
    Posts:
    391
    Have you tried the code greggtwep16 posted yet?

    If you still can't get it, try removing all "Mathf.Round()" calls in your existing code. So, for example:
    Code (csharp):
    1.  
    2. moving = new Vector3 ((player.transform.position.x +  (Mathf.Round (deltaPositionOfTouch.x/1.2f)) ), (player.transform.position.y +  Mathf.Round(deltaPositionOfTouch.y/1.2f)), 0f);
    3.  
    becomes
    Code (csharp):
    1.  
    2. moving = new Vector3 ((player.transform.position.x +  (deltaPositionOfTouch.x/1.2f) ), (player.transform.position.y +  deltaPositionOfTouch.y/1.2f), 0f);
    3.  
    The rounding is what is causing your square-like movement.
     
    Abhijit-Mukherjee likes this.
  29. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    2,640

    That is what Atan2 is for.. describing a circle's angle in degrees based on xy coordinates. I ain't writing your code for you but it is a no brainer to me for what you are trying to do as I understand your explanation.
     
    Abhijit-Mukherjee likes this.
  30. Abhijit-Mukherjee

    Abhijit-Mukherjee

    Joined:
    Jan 9, 2015
    Posts:
    192
    Thank you Very Much ! I will do that ... And post the result here for sure ... It will take couple of days .. please be with me .
     
  31. Abhijit-Mukherjee

    Abhijit-Mukherjee

    Joined:
    Jan 9, 2015
    Posts:
    192
    Thank you Very Much ! If I need more inputs on this , please be with me .. I will take couple of days to close this hopefully . Thank You very much for spending your time .
     
  32. Abhijit-Mukherjee

    Abhijit-Mukherjee

    Joined:
    Jan 9, 2015
    Posts:
    192
    Hello my friend . I follow the same , and it working fine as expected . Thanks bro !!
     
  33. Abhijit-Mukherjee

    Abhijit-Mukherjee

    Joined:
    Jan 9, 2015
    Posts:
    192
    I am closing this discussion . Thanks you all for your support and valuable time spend on this post to hep me out .. I really appropriate .

    Problem is solved by following below code .

    moving =newVector3((player.transform.position.x+(deltaPositionOfTouch.x/1.2f)), (player.transform.position.y+ deltaPositionOfTouch.y/1.2f), 0f);
     
  34. Abhijit-Mukherjee

    Abhijit-Mukherjee

    Joined:
    Jan 9, 2015
    Posts:
    192


    This is very useful .