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
}
}
}