简体   繁体   中英

Joystick and touchpoint are misaligned

I'm having a problem with custom joystick I made by following this tutorial and making a couple of changes later to convert it to fixed joystick instead of floating one.

The joystick works as expected on 2640x1200 display (that's resolution I use for canvas scaler), but when testing on other screens with bigger or smaller resolution, joystick knob/mushroom and touchpoint are misaligned.

Expected result.

Example of misalignment.

Code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using ETouch = UnityEngine.InputSystem.EnhancedTouch;

public class UI_Game_Controls : MonoBehaviour
{
    [SerializeField] private GameObject Joystick_Walk_Area;
    [SerializeField] private GameObject Joystick_Walk_Mushroom;
    private ETouch.Finger Walking_Finger;

    Vector2 Walk_Area_Center;

    float Walk_Area_Width;
    float Walk_Area_Anchor_X;
    float Walk_Area_Height;
    float Walk_Area_Anchor_Y;

    float Scale_Factor;


    private void OnEnable()
    {
        //Debug.Log(Joystick_Walk_Mushroom.GetComponent<RectTransform>().anchoredPosition);
        //Walk_Area_Center = Joystick_Walk_Area.GetComponent<RectTransform>().anchoredPosition + new Vector2(250, 250);
        //Debug.Log(Walk_Area_Center);
        
        /*Gets 4 points used for checking if touchpoint is inside joystick area.*/
        Walk_Area_Width = Joystick_Walk_Area.GetComponent<RectTransform>().anchoredPosition.x + Joystick_Walk_Area.GetComponent<RectTransform>().rect.width;
        Walk_Area_Anchor_X = Joystick_Walk_Area.GetComponent<RectTransform>().anchoredPosition.x;
        Walk_Area_Height = Joystick_Walk_Area.GetComponent<RectTransform>().anchoredPosition.y + Joystick_Walk_Area.GetComponent<RectTransform>().rect.height;
        Walk_Area_Anchor_Y = Joystick_Walk_Area.GetComponent<RectTransform>().anchoredPosition.y;
        

        ETouch.EnhancedTouchSupport.Enable();
        ETouch.Touch.onFingerDown += HandleFingerDown;
        ETouch.Touch.onFingerMove += HandleFingerMove;
        ETouch.Touch.onFingerUp += Touch_onFingerUp;
    }

    private void OnDisable()
    {
        ETouch.Touch.onFingerDown -= HandleFingerDown;
        ETouch.Touch.onFingerMove -= HandleFingerMove;
        ETouch.Touch.onFingerUp -= Touch_onFingerUp;
        ETouch.EnhancedTouchSupport.Disable();
    }

    private void HandleFingerDown(ETouch.Finger FingerTouchDown)
    {
        // Checks if user has touched joystick.
        if (Walking_Finger == null &&
            FingerTouchDown.screenPosition.x >= Walk_Area_Anchor_X && FingerTouchDown.screenPosition.x <= Walk_Area_Width &&
            FingerTouchDown.screenPosition.y >= Walk_Area_Anchor_Y && FingerTouchDown.screenPosition.y <= Walk_Area_Height)
        {
            Walking_Finger = FingerTouchDown;
        }
    }

    private void HandleFingerMove(ETouch.Finger FingerTouchMove)
    {
        if(FingerTouchMove == Walking_Finger)
        {
            Vector2 Walk_Mushroom_Position;
            // Find size of joystick area in which knob should move.
            float Max_Movement = Joystick_Walk_Area.GetComponent<RectTransform>().sizeDelta.y / 2; // 250;

            /*if (Vector2.Distance(FingerTouchMove.currentTouch.screenPosition,Walk_Area_Center)
                > Max_Movement)*/
            if (false) // Disabled on purpose.
            {
                Walk_Mushroom_Position = (FingerTouchMove.currentTouch.screenPosition -
                    Walk_Area_Center).normalized * Max_Movement;
            }
            else
            {
                Walk_Mushroom_Position = FingerTouchMove.currentTouch.screenPosition - Walk_Area_Center;
            }
            Joystick_Walk_Mushroom.GetComponent<RectTransform>().anchoredPosition = Walk_Mushroom_Position;
        }
    }

    private void Touch_onFingerUp(ETouch.Finger obj)
    {
        Walking_Finger = null;
        Joystick_Walk_Mushroom.GetComponent<RectTransform>().anchoredPosition = Vector2.zero;
    }

    private void Start()
    {
        // Get scale factor of canvas.
        Scale_Factor = this.GetComponent<Canvas>().scaleFactor;
        // Calculate center of joystick area after scaling canvas.
        Walk_Area_Center = (Joystick_Walk_Area.GetComponent<RectTransform>().anchoredPosition + new Vector2(250, 250)) * Scale_Factor;

        // // Calculate 4 points after scaling canvas.
        Walk_Area_Width = Walk_Area_Width * Scale_Factor;
        Walk_Area_Anchor_X = Walk_Area_Anchor_X * Scale_Factor;
        Walk_Area_Height = Walk_Area_Height * Scale_Factor;
        Walk_Area_Anchor_Y = Walk_Area_Anchor_Y * Scale_Factor;
    }

    private void Update()
    {
        //Debug.Log(Joystick_Walk_Mushroom.GetComponent<RectTransform>().anchoredPosition.normalized);
        //Debug.Log("Vector.normalized" + (new Vector2(600,600) - new Vector2(300,300)).normalized);

        if (Walking_Finger != null)
        {
            Debug.Log("Finger" + Walking_Finger.currentTouch.screenPosition);
            Debug.Log("Joystick" + Joystick_Walk_Mushroom.GetComponent<RectTransform>().anchoredPosition);
        }
    }
}

I'm super inexperienced with both c# and unity so please excuse me if I'm making some obvious mistake.

PS Sorry for awful and barely commented code.

Got it, I added RectTransformUtility.ScreenPointToLocalPointInRectangle inside HandleFingerMove method.

Old:

    private void HandleFingerMove(ETouch.Finger FingerTouchMove)
        {
            if(FingerTouchMove == Walking_Finger)
            {
                Vector2 Walk_Mushroom_Position;
                // Find size of joystick area in which knob should move.
                float Max_Movement = Joystick_Walk_Area.GetComponent<RectTransform>().sizeDelta.y / 2; // 250;
     
                /*if (Vector2.Distance(FingerTouchMove.currentTouch.screenPosition,Walk_Area_Center)
                    > Max_Movement)*/
                if (false) // Disabled on purpose.
                {
                    Walk_Mushroom_Position = (FingerTouchMove.currentTouch.screenPosition -
                        Walk_Area_Center).normalized * Max_Movement;
                }
                else
                {
                    Walk_Mushroom_Position = FingerTouchMove.currentTouch.screenPosition - Walk_Area_Center;
                }
                Joystick_Walk_Mushroom.GetComponent<RectTransform>().anchoredPosition = Walk_Mushroom_Position;
            }
        }

New:

    private void HandleFingerMove(ETouch.Finger FingerTouchMove)
        {
            if(FingerTouchMove == Walking_Finger)
            {
                Vector2 Walk_Mushroom_Position;
              // Find size of joystick area in which knob should move.
                float Max_Movement = Joystick_Walk_Area.GetComponent<RectTransform>().sizeDelta.y / 2; // 250;
     
                if (Vector2.Distance(FingerTouchMove.currentTouch.screenPosition,Walk_Area_Center)
                    > Max_Movement)
                //if (false)
                {
                    //TO DO
                    Debug.Log("Finger out");
                    Walk_Mushroom_Position = (FingerTouchMove.currentTouch.screenPosition -
                        Walk_Area_Center).normalized * Max_Movement;
                }
                else
                {
                    RectTransformUtility.ScreenPointToLocalPointInRectangle(
                        Joystick_Walk_Area.GetComponent<RectTransform>(),
                        FingerTouchMove.currentTouch.screenPosition,
                        this.GetComponent<Canvas>().worldCamera,
                        out Walk_Mushroom_Position);
     
                    Debug.Log(Screen.currentResolution);
     
                    Walk_Mushroom_Position.x -= Max_Movement;
                    Walk_Mushroom_Position.y -= Max_Movement;
                }
                Joystick_Walk_Mushroom.GetComponent<RectTransform>().anchoredPosition = Walk_Mushroom_Position;
            }
        }

Edit:

I will try to explain what (I think) I did and why I did things this way.

My scene is organised like this:

Scene

|

> Canvas_UI

  |

  > Joystick_Walk_Area

    |

    > Joystick_Walk_Mushroom

Class which contains HandleFingerMove method is part of Canvas_UI . Canvas_UI is referenced as this inside class.

Joystick_Walk_Area is child of Canvas_UI . Joystick_Walk_Area is anchored in bottom left corner of canvas (75px from left edge and 50px above bottom edge of canvas) and has dimensions of 500px x 500px.

Joystick_Walk_Mushroom is child of Joystick_Walk_Area and its anchor is in center of Joystick_Walk_Area .

I used RectTransformUtility.ScreenPointToLocalPointInRectangle to convert FingerTouchMove.currentTouch.screenPosition (user touch input) into local point of Joystick_Walk_Area which made Joystick_Walk_Mushroom appear +250px in X & Y directions away from FingerTouchMove.currentTouch.screenPosition , I fixed this by subtracting touch coordinates (lines 28 and 29)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM