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.
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.
P.S. 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)