Camera and Player control on mobiles

**NOTE: This script has been incorporated into the "UI template: Mobile joystick" package on AC's Downloads page.**

This script improves the Direct and First Person on mobile devices by separating player and camera movement on different sides of the screen - with drags on the left moving the Player, and drags on the right moving the Camera.

To use it for **Direct** movement:

* In the Settings Manager, set **Movement method** to **Direct**, **Input method** to **Touch Screen**, and **Direct movement** to **Custom Input**.
* Assign a GameCamera Third-person Camera type, uncheck **Is drag-controlled?**, and set the **Spin** and **Pitch** input axes to **CameraSpin** and **CameraPitch** respectively (these need not be added to Unity's Input Manager)
* Copy/paste the script below into a C# file named DragCameraAndPlayer.cs, add to the scene, and assign your camera in its **GameCamera Third Person** Inspector field.
* To tweak the drag distance that causes the Player to run, adjust the **Player Run Threshold** field in the Drag Camera And Player component's Inspector.
* To tweak the camera speed, adjust the **Input influence** fields in the GameCamera Third-person component's Inspector.

To use it for **First Person** movement:

* In the Settings Manager, set **Movement method** to **First Person**, **Input method** to **Touch Screen**, and **First-person movement** to **Custom Script**.
* Add a First-person Camera to your Player as normal, following the steps in this tutorial.
* Copy/paste the script below into a C# file named DragCameraAndPlayer.cs, and add to the scene.
* To tweak the drag distance that causes the Player to run, adjust the **Player Run Threshold** field in the Drag Camera And Player component's Inspector.
* To tweak the camera speed, adjust the **Freelook sensitivity** values in the First Person Camera component's Inspector.

DragCameraAndPlayer.cs:

```
using UnityEngine;
using AC;

public class DragCameraAndPlayer : MonoBehaviour
{

 private readonly TouchData cameraTouch = new TouchData (true, false, 1f);
 private readonly TouchData playerTouch = new TouchData (false, true, 1f);

 [SerializeField] private float playerRunThreshold = 0.2f;
 private const string playerHorizontalAxis = "Horizontal";
 private const string playerVerticalAxis = "Vertical";
 private const string runAxis = "Run";

 [SerializeField] private GameCameraThirdPerson gameCameraThirdPerson = null;

 private int cursorFingerID = -1;
 private Vector2 lastCursorPosition;

 private void Start ()
 {
 KickStarter.playerInput.InputGetAxisDelegate = InputGetAxis;
 KickStarter.playerInput.InputGetButtonDelegate = InputGetButton;
 KickStarter.playerInput.InputMousePositionDelegate = InputMousePosition;
 KickStarter.playerInput.InputGetFreeAimDelegate = InputGetFreeAimDelegate;
 }

 private void Update ()
 {
 cameraTouch.Update ();
 playerTouch.Update ();

 UpdateCursor ();
 }

 private void UpdateCursor ()
 {
 if (cursorFingerID < 0)
 {
 for (int i = 0; i < Input.touchCount; i++)
 {
 Touch touch = Input.GetTouch (i);
 if (touch.phase == TouchPhase.Began)
 {
 lastCursorPosition = touch.position;
 cursorFingerID = touch.fingerId;
 return;
 }
 }
 return;
 }

 for (int i = 0; i < Input.touchCount; i++)
 {
 if (Input.GetTouch (i).fingerId == cursorFingerID && Input.GetTouch (i).phase != TouchPhase.Ended)
 {
 return;
 }
 }
 cursorFingerID = -1;
 }

 private Vector2 InputMousePosition (bool isLocked)
 {
 if (isLocked)
 {
 return KickStarter.playerInput.LockedCursorPosition;
 }

 if (cursorFingerID >= 0)
 {
 for (int i = 0; i < Input.touchCount; i++)
 {
 if (Input.GetTouch (i).fingerId == cursorFingerID)
 {
 lastCursorPosition = Input.GetTouch (i).position;
 }
 }
 return lastCursorPosition;
 }
 return Input.mousePosition;
 }

 private bool InputGetButton (string axis)
 {
 if (!InvInstance.IsValid (KickStarter.runtimeInventory.SelectedInstance) && axis == runAxis)
 {
 return (playerTouch.GetDragVector ().magnitude / ACScreen.LongestDimension) > playerRunThreshold;
 }

 try { return Input.GetButton (axis); }
 catch { return false; }
 }

 private float InputGetAxis (string axis)
 {
 if (!InvInstance.IsValid (KickStarter.runtimeInventory.SelectedInstance))
 {
 if (gameCameraThirdPerson && axis == gameCameraThirdPerson.spinAxis)
 {
 return cameraTouch.GetDragVector ().x;
 }
 else if (gameCameraThirdPerson && axis == gameCameraThirdPerson.pitchAxis)
 {
 return cameraTouch.GetDragVector ().y;
 }
 else if (axis == playerHorizontalAxis)
 {
 return playerTouch.GetDragVector ().x;
 }
 else if (axis == playerVerticalAxis)
 {
 return playerTouch.GetDragVector ().y;
 }
 }

 try { return Input.GetAxis (axis); }
 catch { return 0f; }
 }

 private Vector2 InputGetFreeAimDelegate (bool cursorIsLocked)
 {
 return cameraTouch.GetDragVector () \* 0.0005f;
 }

 private class TouchData
 {

 public int fingerID = -1;
 public Vector2 startPosition;
 private readonly bool OnRightSide;
 private readonly bool DragIsRelative;
 private readonly float DragScaler;

 public TouchData (bool onRightSide, bool dragIsRelative, float dragScaler)
 {
 OnRightSide = onRightSide;
 DragIsRelative = dragIsRelative;
 DragScaler = dragScaler;
 }

 public void Update ()
 {
 if (fingerID == -1)
 {
 fingerID = GetBeginningTouchIndex ();
 if (fingerID >= 0)
 {
 startPosition = GetTouchPosition ();
 }
 }
 else
 {
 if (!IsStillTouching ())
 {
 fingerID = -1;
 }
 }
 }

 public Vector2 GetDragVector ()
 {
 if (DragIsRelative)
 {
 return fingerID >= 0 ? (GetTouchPosition () - startPosition) \* DragScaler : Vector2.zero;
 }
 return fingerID >= 0 ? GetTouchDrag () \* DragScaler : Vector2.zero;
 }

 private int GetBeginningTouchIndex ()
 {
#if !UNITY\_EDITOR
 for (int i = 0; i < Mathf.Min (2, Input.touchCount); i++)
 {
 Touch touch = Input.GetTouch (i);
 if (touch.phase == TouchPhase.Began && (OnRightSide == touch.position.x > ACScreen.width / 2f))
 {
 return touch.fingerId;
 }
 }
#else
 if (Input.GetMouseButtonDown (0) && (OnRightSide == Input.mousePosition.x > ACScreen.width / 2f))
 {
 return 0;
 }
#endif
 return -1;
 }

 private bool IsStillTouching ()
 {
#if !UNITY\_EDITOR
 for (int i = 0; i < Input.touchCount; i++)
 {
 Touch touch = Input.GetTouch (i);
 if (touch.fingerId == fingerID && touch.phase != TouchPhase.Ended)
 {
 return true;
 }
 }
 return false;
#else
 return Input.GetMouseButton (0);
#endif
 }

 private Vector2 GetTouchPosition ()
 {
#if !UNITY\_EDITOR
 for (int i = 0; i < Input.touchCount; i++)
 {
 Touch touch = Input.GetTouch (i);
 if (touch.fingerId == fingerID)
 {
 return touch.position;
 }
 }
 return startPosition;
#else
 return (Vector2) Input.mousePosition;
#endif
 }

 private Vector2 GetTouchDrag ()
 {
#if !UNITY\_EDITOR
 for (int i = 0; i < Input.touchCount; i++)
 {
 Touch touch = Input.GetTouch (i);
 if (touch.fingerId == fingerID)
 {
 return touch.deltaPosition;
 }
 }
 return Vector2.zero;
#else
 return GetTouchPosition () - startPosition;
#endif
 }

 }

}

```