Custom InputHandler is giving different results between Editor and final Build
Good day,
currently I am working on a custom Input Handler that shall recognize Tap, Drag and Pinch and cast an equal event after. Now I have a problem with my drag event, which is giving different results when testing in Unity Editor (via Unity Remote) than in built version (Android).
What is happening?
When I am testing in Editor everything works like intended. The Object moves equal to the amount the finger moved on the touch screen.
When in built version, the object moves less than the amount the finger moved on tablet. The faster the finger moves, the less the object moves pro-rata. The slower the finger moves, the more the object moves pro-rata (nearly the same amount as the finger)
What did I test so far?
I checked the measured deltaPosition that is tracked and that is handled: both the same.
I tracked the amount of event calls, compared to Execute() - both gets the same amount of calls.
FPS is all fine got no lags or spikes.
Checked this behavior with different devices - all built versions have the same problem.
Checked with HTC One m8 and Galaxy Tab S2
I am a little bit confused and would like to ask you to help me. Maybe there are some build settings I need to check? Unfortunately I am not used to configure the unity build. Any advice / tips / help are very welcome!
Many thanks beforehand!
My Code looks as follows:
(InputHandler Execute() gets called by managing MonoBehaviour class within Update() )
InputHandler.cs :
using System.Collections.Generic;
using UnityEngine;
namespace HMB {
public class InputHandler {
private class ExtTouch {
private Vector2 _pressPosition;
private Touch _touch;
public ExtTouch(Touch touch) {
_pressPosition = touch.position;
Debug.Log(_pressPosition.ToString(), DebugType.INPUT);
_touch = touch;
}
public Vector2 PressPosition {
get { return _pressPosition; }
}
public Vector2 Position {
get {return _touch.position; }
}
public Vector2 DeltaPosition {
get { return _touch.deltaPosition; }
}
public float Distance {
get { return Vector2.Distance(Position, PressPosition); }
}
public float DeltaDistance {
get { return DeltaPosition.magnitude; }
}
public int FingerId {
get { return _touch.fingerId; }
}
public TouchPhase Phase {
get { return _touch.phase; }
}
public bool HoverInterface {
get { return UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject(FingerId); }
}
private Touch GetTouch() {
foreach (Touch touch in Input.touches) {
if (touch.fingerId == FingerId) {
return touch;
}
}
// If we can't find our touch in current touches
// we implicy the touch has ended.
_touch.phase = TouchPhase.Canceled;
return _touch;
}
public void Update() {
_touch = GetTouch();
}
}
#region VARIABLES
//===========================================================
private float _dragThreshold = 2f;
private bool _isDragging = false;
private ExtTouch _draggingTouch;
/// <summary>
/// Stores all touches that not began on an Interface Element.
/// </summary>
private List<ExtTouch> validTouches;
//===========================================================
#endregion
#region EVENTS
//===========================================================
public delegate void Tap(Vector2 position);
public static event Tap OnTap;
public delegate void Drag(Vector2 deltaPosition);
public static event Drag OnDrag;
public delegate void Pinch(float magnitude);
public static event Pinch OnPinch;
//===========================================================
#endregion
#region OBJECT_METHODS
//===========================================================
public InputHandler() {
validTouches = new List<ExtTouch>();
}
public void Execute() {
ExecuteMobile();
}
public void ExecuteMobile() {
//Update all current valid touches.
for (int i = validTouches.Count - 1; i >= 0; i--) {
var touch = validTouches[i];
touch.Update();
}
// Add all new touches that are valid to equal list.
foreach (UnityEngine.Touch touch in Input.touches) {
if (touch.phase == TouchPhase.Began && !HoverInterface(touch)) {
var newTouch = new ExtTouch(touch);
validTouches.Add(newTouch);
}
}
//Read all Inputs and call events.
if (validTouches.Count > 0) {
var inputHandled = false;
HMB.Debug.Log("Reading valid touch input.", DebugType.INPUT);
if (validTouches.Count == 1) {
HMB.Debug.Log("Reading valid single touch input.", DebugType.INPUT);
// Read if tapped and return if done so.
if (!inputHandled) inputHandled = Tapped(validTouches[0]);
// Read if dragged and return if done so.
if (!inputHandled) inputHandled = Dragged(validTouches[0]);
}
if (validTouches.Count == 2) {
_isDragging = false;
HMB.Debug.Log("Reading valid multiple touch input.", DebugType.INPUT);
// Read if pinched and return if done so.
if (!inputHandled) inputHandled = Pinched(validTouches[0], validTouches[1]);
}
}
// Remove all touches that ended or got canceled.
// We do this in an extra loop as we want to use
// the Ended and Cancelled State for Input recognition.
for (int i = validTouches.Count - 1; i >= 0; i--) {
var touch = validTouches[i];
if (touch.Phase == TouchPhase.Ended || touch.Phase == TouchPhase.Canceled) {
validTouches.Remove(touch);
}
}
}
private bool HoverInterface(Touch touch) {
return UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject(touch.fingerId);
}
public void ReadMouseInput() {
if (Input.GetMouseButtonDown(0)) {
if (OnTap != null) {
OnTap(Input.mousePosition);
}
}
}
private bool Tapped(ExtTouch touch) {
HMB.Debug.Log("Tap Step 0", DebugType.INPUT);
if (_isDragging) return false;
HMB.Debug.Log("Tap Step 1", DebugType.INPUT);
if (touch.Phase == TouchPhase.Ended && OnTap != null) {
OnTap(touch.Position);
HMB.Debug.Log(
"INPUT: tapping +++ VALID TOUCH COUNT: " + validTouches.Count +
" +++ GLOBAL TOUCH COUNT: " + Input.touches.Length, DebugType.INPUT);
return true;
}
return false;
}
private bool Dragged(ExtTouch touch) {
// If we are dragging but this is not the dragging touch, break.
if (_isDragging && touch != _draggingTouch) return false;
if (touch.Phase == TouchPhase.Ended || touch.Phase == TouchPhase.Canceled){
_isDragging = false;
_draggingTouch = null;
return false;
}
// If we are not dragging and traveled distance is larger
// than the threshold, set this touch as dragging touch and
// start dragging.
if (!_isDragging && touch.Distance > _dragThreshold) {
_isDragging = true;
_draggingTouch = touch;
}
// If we are dragging and event is not null,
// call the event using DeltaPosition.
if (_isDragging && OnDrag != null) {
OnDrag(touch.DeltaPosition);
HMB.Debug.Log(
"INPUT: dragging +++ DELTA POSITION: " + touch.DeltaPosition + "+++ VALID TOUCH COUNT: " + validTouches.Count +
" +++ GLOBAL TOUCH COUNT: " + Input.touches.Length, DebugType.INPUT);
return true;
}
return false;
}
private bool Pinched(ExtTouch touchOne, ExtTouch touchTwo) {
// Find the position in the previous frame of each touch.
Vector2 touchOnePrevPos = touchOne.Position - touchOne.DeltaPosition;
Vector2 touchTwoPrevPos = touchTwo.Position - touchTwo.DeltaPosition;
// Find the magnitude of the vector (the distance) between the touches in each frame.
float prevTouchDeltaMag = (touchOnePrevPos - touchTwoPrevPos).magnitude;
float touchDeltaMag = (touchOne.Position - touchTwo.Position).magnitude;
// Find the difference in the distances between each frame.
float deltaMagnitudeDiff = prevTouchDeltaMag - touchDeltaMag;
// Call Pinch event
if (OnPinch != null) {
OnPinch(deltaMagnitudeDiff);
HMB.Debug.Log(
"INPUT: pinching +++ DISTANCE: " + deltaMagnitudeDiff + "+++ VALID TOUCH COUNT: " + validTouches.Count +
" +++ GLOBAL TOUCH COUNT: " + Input.touches.Length, DebugType.INPUT);
return true;
}
return false;
}
//===========================================================
#endregion
}
}
Draw Object:
using UnityEngine;
using UnityEngine.UI;
namespace HMB {
public class DrawObject : MonoBehaviour, IZoomable, IDraggable {
public void Start() {
Camera.main.orthographicSize = Screen.height/pixelPerUnit/2.0f;
}
public Text text;
int eventCount = 0;
public int pixelPerUnit = 100;
public void Drag(Vector2 deltaPosition) {
var pixelToWorld = ((Camera.main.orthographicSize*2) * deltaPosition / Screen.height);
this.gameObject.transform.Translate(pixelToWorld.x, pixelToWorld.y, 0);
}
public void Zoom(float distance) {
}
}
}
I haven't given it much thought, but I think it might have something to do with varying resolutions and dpi's specifically. I remember I had a similar problem once with legacy GUI when using virtual resolution matrices. So no real answer here, just a direction in which to look.
Your answer
Follow this Question
Related Questions
Unity (builds and editor) Keep firing input on its own after Windows 10 update 0 Answers
Mobile Touch vs PC Touch 0 Answers
Getting Two Input Devices to work Simultaneously... 0 Answers
Why unity not working after launching .exe but works when build and run? 0 Answers
Sending data to custom HID device 1 Answer