I'm creating a game for webgl, the goal is to create an orbital camera for a phone, I managed to do it for computers, but I can't do it for a phone. I've been trying to do this for a few days now, and I'm still not getting it. I need your help. At the moment I have written a script, and there is 1 error in it that does not allow me to use it. Where I have the error: step 1. I press my finger on any element of the user interface and keep my finger pressed on it. Step 2. I press the other finger in the free zone and swipe my finger across the screen while still holding it. Step 3. I raise the first finger that was above the user interface and still hold the finger that was in the free zone. Stage 4. The camera jerks sharply 1 time. How to avoid this camera jump?
my script
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
public class OrbitCamera : MonoBehaviour
{
public Transform target;
public float distance = 30;
public float sensitivityX = 4.0f;
public float sensitivityY = 1.0f;
public float minYAngle = -80.0f;
public float maxYAngle = 80.0f;
private float rotationX = 0.0f;
private float rotationY = 0.0f;
public bool CanRotateCamera;
public float smoothSpeed = 5f;
private Dictionary<int, bool> fingerIdToFirstTouchOverUI = new Dictionary<int, bool>();
private Touch _touchcurrent;
private void Start()
{
CanRotateCamera = true;
if (Application.isMobilePlatform)
{
Input.multiTouchEnabled = true;
sensitivityY = 7f;
sensitivityX = 7f;
}
else
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
}
private void LateUpdate()
{
if (Application.isMobilePlatform)
{
HandleMobileInput();
}
else
{
HandlePCInput();
}
}
private void HandleMobileInput()
{
if (CanRotateCamera)
{
bool isAnyTouchMoving = false;
for (int i = 0; i < Input.touchCount; i++)
{
Touch touch = Input.GetTouch(i);
if (touch.phase == TouchPhase.Began)
{
fingerIdToFirstTouchOverUI[touch.fingerId] = IsTouchOverUI(touch.position);
if (fingerIdToFirstTouchOverUI[touch.fingerId])
{
continue;
}
}
if (touch.phase == TouchPhase.Moved && !fingerIdToFirstTouchOverUI[touch.fingerId])
{
rotationY -= touch.deltaPosition.x * sensitivityX * Time.deltaTime;
rotationX += touch.deltaPosition.y * sensitivityY * Time.deltaTime;
rotationX = Mathf.Clamp(rotationX, minYAngle, maxYAngle);
isAnyTouchMoving = true;
}
}
if (isAnyTouchMoving)
{
transform.rotation = Quaternion.Euler(rotationX, rotationY, 0);
}
Vector3 newPosition = target.position - transform.forward * distance;
newPosition.y += 7.0f;
transform.position = newPosition;
}
}
private void HandlePCInput()
{
if (CanRotateCamera)
{
float mouseX = Input.GetAxis("Mouse X");
float mouseY = Input.GetAxis("Mouse Y");
rotationY += mouseX * sensitivityX;
rotationY = Mathf.Repeat(rotationY, 360);
rotationX -= mouseY * sensitivityY;
rotationX = Mathf.Clamp(rotationX, minYAngle, maxYAngle);
distance -= Input.GetAxis("Mouse ScrollWheel");
distance = Mathf.Clamp(distance, 8.0f, 30.0f);
transform.rotation = Quaternion.Euler(rotationX, rotationY, 0);
Vector3 newPosition = target.position - transform.forward * distance;
newPosition.y += 7.0f;
transform.position = newPosition;
}
}
private bool IsTouchOverUI(Vector2 touchPosition)
{
PointerEventData eventData = new PointerEventData(EventSystem.current);
eventData.position = touchPosition;
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(eventData, results);
return results.Any(result => result.gameObject.layer == LayerMask.NameToLayer("UI"));
}
}
I have tried a large number of different options, but for many days in a row I have not been able to do anything, I am disappointed and go around in circles, I really need the help of people who understand how to implement it. I just want an orbital camera that will not interfere with the UI and it will all work in webgl from the phone.
I suspect that when you lift your first finger, the second finger then gets assigned as touchId 1 and you end up with a very large deltaPosition. Can you try just checking for and rejecting that touch?
if (touch.phase == TouchPhase.Moved && !fingerIdToFirstTouchOverUI[touch.fingerId])
{
// check for large delta and skip this time
// experiment with the value so that it doesn't miss certain fast swipes
if (touch.deltaPosition.magnitude > 100)
{
continue; // skip to next for loop
}
// delta looks good, handle normally
rotationY -= touch.deltaPosition.x * sensitivityX * Time.deltaTime;
rotationX += touch.deltaPosition.y * sensitivityY * Time.deltaTime;
rotationX = Mathf.Clamp(rotationX, minYAngle, maxYAngle);
isAnyTouchMoving = true;
}