Search code examples
c#unity-game-enginecontrolstouchcinemachine

Screen Touch control to move Cinemachine Camera in Unity


I'm making third person shooter game in unity for android and this is my first time working on touch controls so with the help of youtube videos I was able to make virtual joystick and button with On_Screen Stick and On_Screen Button button with new unity input system that handles movement and all other stuff.

So what I want is screen touch to control the camera movement specifically cinemachine camera movement to look around so for that I tried searching another youtube video to create a specific touchfield area where I can use touch controls to feed value to vertical and horizontal axis of cinemachine camera but i couldn't find any thing like that. How can I make Specific area where touch can make my cinemachine camera look around and if I touch the joystick the touch field for camera movement is not affected?

NOTE: My cinemachine camera is virtual camera with aim POV component to look around and I already have coded to rotate my player in the direction of camera so all i need is to move my camera around with touch on touchfield and also as I said previously I am using new Input System but I am also using old one too so both are working but I have mostly new input system controls and would prefer to use them, I don't need another joystick move my camera around and I used empty image component to make touch field.

PS: Will appreciate if you someone can fix any errors or advice u can give since I am new to android game development and unity in general.

I did try asking chat GPT to make me a script which did work but it had few problem like when I was touching my movement joystick it was moving my camera also and I could not move joystick and camera at same time and also there was some snapping in touch like suddenly camera moves when I presses other button like fire button even though they aren't on touch field.

here is the code that I got from chat GPT


using UnityEngine;
using UnityEngine.EventSystems;

public class TouchField : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
    [HideInInspector]
    public Vector2 TouchDist;
    [HideInInspector]
    public bool Pressed;

    private RectTransform rectTransform; // Reference to the RectTransform component

    private Vector2 previousTouchPos; // Store the previous touch position

    // Use this for initialization
    void Start()
    {
        // Get the RectTransform component of the image field
        rectTransform = GetComponent<RectTransform>();
    }

    // Update is called once per frame
    void Update()
    {
        // Check if there is only one active touch
        if (Input.touchCount == 1)
        {
            Touch touch = Input.GetTouch(0);

            // Check if the touch is within the bounds of the RectTransform
            if (RectTransformUtility.RectangleContainsScreenPoint(rectTransform, touch.position))
            {
                if (touch.phase == TouchPhase.Moved || touch.phase == TouchPhase.Stationary)
                {
                    if (Pressed)
                    {
                        // Calculate the distance from the previous touch position
                        TouchDist = touch.position - previousTouchPos;
                        previousTouchPos = touch.position;
                    }
                    else
                    {
                        // Initialize the previous touch position
                        previousTouchPos = touch.position;
                        Pressed = true;
                    }
                }
                else
                {
                    // Reset when touch is not moving or released
                    Pressed = false;
                    TouchDist = Vector2.zero;
                }
            }
            else
            {
                // Reset when touch is outside the bounds
                Pressed = false;
                TouchDist = Vector2.zero;
            }
        }
        else
        {
            // Reset when there are no active touches
            Pressed = false;
            TouchDist = Vector2.zero;
        }
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        // Handle pointer down event if needed
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        // Handle pointer up event if needed
    }
}

I'm setting value of cinemachine like this

povComponent.m_HorizontalAxis.Value += touchField.TouchDist.x * SensitivityX * Time.deltaTime;
povComponent.m_VerticalAxis.Value -= touchField.TouchDist.y * SensitivityY * Time.deltaTime;

Solution

  • So yeah I was able to figure it out myself here is the code if anyone wants to know how I did it, this is using completely new input system and is not using touch field or any sort of that thing, meaning that touch is happening on all the screen but it will avoid all the UI buttons using event system. You need to add Event system and new input system name space for this to work and aimPov1 and aimPov2 here are cinemachine virtual camera aim POV component reference which you can get it in start method and reason there are two is because I am using two Cinemachine cam if you want for one then you can remove IF and Else statement where I am checking if cam 1 is active, you can also remove check because it is what I wanted in my scenario and You can also use other Cinemachine camera and also multiply by Time.deltaTime to make movement more smooth.

     if (Touchscreen.current.touches.Count == 0)
            return;
    
        if (EventSystem.current.IsPointerOverGameObject(Touchscreen.current.touches[0].touchId.ReadValue()))
        {
            if (Touchscreen.current.touches.Count > 1 && Touchscreen.current.touches[1].isInProgress)
            {
                if (EventSystem.current.IsPointerOverGameObject(Touchscreen.current.touches[1].touchId.ReadValue()))
                    return;
    
                Vector2 touchDeltaPosition = Touchscreen.current.touches[1].delta.ReadValue();
                if (_cam1.gameObject.activeSelf == true)
                {
                    aimPOV1.m_VerticalAxis.Value -= touchDeltaPosition.y * _touchSensitivityY;
                    aimPOV1.m_HorizontalAxis.Value += touchDeltaPosition.x * _touchSensitivityX;
                }
                else
                {
                    aimPOV2.m_VerticalAxis.Value -= touchDeltaPosition.y * _touchSensitivityY;
                    aimPOV2.m_HorizontalAxis.Value += touchDeltaPosition.x * _touchSensitivityX;
                }
    
            }
        }
        else
        {
            if (Touchscreen.current.touches.Count > 0 && Touchscreen.current.touches[0].isInProgress)
            {
                if (EventSystem.current.IsPointerOverGameObject(Touchscreen.current.touches[0].touchId.ReadValue()))
                    return;
    
                Vector2 touchDeltaPosition = Touchscreen.current.touches[0].delta.ReadValue();
                if (_cam1.gameObject.activeSelf == true)
                {
                    aimPOV1.m_VerticalAxis.Value -= touchDeltaPosition.y * _touchSensitivityY;
                    aimPOV1.m_HorizontalAxis.Value += touchDeltaPosition.x * _touchSensitivityX;
                }
                else
                {
                    aimPOV2.m_VerticalAxis.Value -= touchDeltaPosition.y * _touchSensitivityY;
                    aimPOV2.m_HorizontalAxis.Value += touchDeltaPosition.x * _touchSensitivityX;
                }
            }
        }