Need Help ! On Math !

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 .

2236447--149109--upload_2015-8-5_11-52-18.png like this .
I want to move it 0 to 360 degree angle .
2236447--149110--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

Dude, it says this is not a help section right in the discription for “General Discussion”.

Try posting this in the scripting section.

1 Like

Ok dude …

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.

1 Like

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 …

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.

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 .

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”.

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 ?

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.

1 Like

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 ?

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.

Post your code, because it definitely will work for any degree movement.

1 Like

Here is the whole Code Below .

 //touch controls
using UnityEngine;
using System.Collections;
using UnityEngine.UI;


public class JoyStickController : MonoBehaviour {

    // Use this for initialization
    public Image stick ;
    public RectTransform stickPosition;
    public Vector2 StickStartingPosition;
    //public Vector3 deltaPositionOfTouch;
    public Vector2 deltaPositionOfTouch;
    public Vector3 stickChangePosition;
    public float joyStickMaxBoundary ;
    public GameObject player ;
    public Image PadImage ;
    public Vector2 velocity;
    public Rigidbody2D rb2D;
    public bool touchedNotEnded ;
    public Text text ;
    public bool isStickDrag;

    public static float speed;
    public float increment = 0.4f;
    public static float distance = 0f;


    void Start () {
        StickStartingPosition = new Vector2 (stickPosition.position.x, stickPosition.position.y);

    }

    public void DragStick ()
    {
        isStickDrag = true;
    }

    public void MovePlayer ( )
    {
        if (touchedNotEnded ) {
            Vector3 moving = new Vector3 (0f,0f,0f);
            moving = new Vector3 ((player.transform.position.x +  (Mathf.Round (deltaPositionOfTouch.x/1.2f)) ), (player.transform.position.y +  Mathf.Round(deltaPositionOfTouch.y/1.2f)), 0f);
            player.transform.position = Vector3.MoveTowards (player.transform.position, moving,  speed * Time.deltaTime);
        
        }
    }
    public void MoveStickToCurrentPosition(Vector3 position, bool isMoved)
    {
        float x = Mathf.Round(position.x);
        float y = Mathf.Round(position.y);

        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);
        Vector2 startPoint = new Vector2 (Mathf.Round(StickStartingPosition.x),Mathf.Round(StickStartingPosition.y));
        Vector2 endPoint = new Vector2 (Mathf.Round(moveDistance.x),Mathf.Round(moveDistance.y));
        // Clamp the stick with radius of pad ----------------
        stickPosition.position= Vector3.Lerp(stickPosition.position, moveDistance,  Time.deltaTime*500 );
    
        // get the distance
        distance = Vector2.Distance (startPoint,endPoint);
    
        // get Delta position ---------------
        deltaPositionOfTouch = new Vector2 (x - Mathf.Round(StickStartingPosition.x), y - Mathf.Round(StickStartingPosition.y)).normalized;
        //set speed base on how far he dragged ---------------
        if (distance >= 100f) {
            speed = 20;
        } else if (distance >= 30f && distance <100) {
            speed = 15;

        } else {
            speed = 2;
        
        }
    



    }


    public void MoveStickToDefaultPosition(Vector3 position, bool isEnded)
    {
        stickPosition.position = new Vector3 (position.x, position.y, 0f);
    }

    // Update is called once per frame
    void Update () {

        if ( Input.touchCount == 1)
        {
            Touch touch = Input.touches[0];
            Vector3 touchPosition ;
        
            switch (touch.phase)
            {
            case TouchPhase.Began :
               // Store the current position of the stick
                touchPosition = new Vector3(touch.position.x,  touch.position.y,0);
                touchedNotEnded = true;
                break;
            
            case TouchPhase.Moved :
                // Get the end touch
                deltaPositionOfTouch = new Vector3 (touch.position.x, touch.position.y,0);
                MoveStickToCurrentPosition(deltaPositionOfTouch,true);

            
                break;
        
            
            case TouchPhase.Stationary :
                break;
            
            case TouchPhase.Canceled :
                MoveStickToDefaultPosition(StickStartingPosition,true);
                touchedNotEnded = false;
                isStickDrag = false;
                deltaPositionOfTouch = new Vector2 (0f,0f);
                touchPosition = new Vector3 (0f,0f,0f);
                break;

            case TouchPhase.Ended :
                MoveStickToDefaultPosition(StickStartingPosition,true);
                touchedNotEnded = false;
                isStickDrag = false;
                deltaPositionOfTouch = new Vector2 (0f,0f);
                touchPosition = new Vector3 (0f,0f,0f);
                break;
            }

            if(Input.GetTouch(0).phase != TouchPhase.Ended && touchedNotEnded)
            {
                MovePlayer ();
            }
        }





    }
}

Here is the out put

https://www.youtube.com/watch?v=aLoOwBdSms8

1 Like

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):

 //touch controls
            touchCount = Input.touchCount;

            if (touchCount > 0)
            {
                for (int i = 0; i < touchCount; i++)
                {
                    Touch touch = Input.GetTouch(i);

                    //touch somewhere on control (in between the sprites boundaries
                    if (touch.position.x >= screenPixelsRect.x &&
                            touch.position.x <= (screenPixelsRect.x + screenPixelsRect.width) &&
                            touch.position.y >= screenPixelsRect.y &&
                            touch.position.y <= (screenPixelsRect.y + screenPixelsRect.height))
                    {
                        //moving the nub (the graphic portion of the UI)
                        nubMovement.x = touch.position.x - screenPixelsRect.center.x;
                        nubMovement.y = touch.position.y - screenPixelsRect.center.y;
                        nubMovement.z = 0;
                        break;
                    }
                }
            }

            //if both are zero don't bother we're already correct
            if (!(nubMovement.x == 0f && nubMovement.y == 0f))
            {

                //normalize by the dimensions of the sprite and then multiply by our sensitivity
                horizontal = (nubMovement.x / normalizeFactorX) * sensitivity;
                vertical = (nubMovement.y / normalizeFactorY) * sensitivity;


            }

            joystickImageForeground.rectTransform.position = defaultNubPosition + nubMovement;

            transform.position += new Vector3(horizontal, vertical, 0f);

Thanks you for the review … what is the normalizeFactorX ?

Dose it handle the diagonal too ?

  • //normalize by the dimensions of the sprite and then multiply by our sensitivity
  • horizontal = (nubMovement.x / normalizeFactorX) * sensitivity;
  • vertical = (nubMovement.y / normalizeFactorY) * sensitivity;

transform.position+=newVector3(horizontal, vertical, 0f);

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…

1 Like

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.

Thank you , But I am not clear how tho get the “normalizeFactorX” , Please let me know how I need to calculate that