iPhone touch events slowdown fps?!?

EDIT: Added my swipe class, which detects swipes and stores swipe speed, swipe direction, swipe started/ended etc…it seems that this code slows my FPS down by 5-10fps. I use the stored values of this class from another class, to decide what actions to take.

using UnityEngine;
using System.Collections;

public class Swipe : MonoBehaviour {
	
	// Singleton access
	private static Swipe _instance = null;
	public static Swipe Instance
	{
		get{ 
			if( _instance == null )
			{
				_instance = FindObjectOfType( typeof( Swipe )) as Swipe;
				
				if( !_instance )
					_instance = new GameObject( "Swipe" ).AddComponent<Swipe>();
			}
			return _instance; 
		}
	}

	
	// Enums
	public enum SwipeType
	{
		HORIZONTAL,
		VERTICAL,
		BOTH
	}
	public SwipeType swipeType;
	
	private enum SwipeDirection
	{
		NONE,
		SWIPE_LEFT,
		SWIPE_RIGHT,
		SWIPE_UP,
		SWIPE_DOWN
	}
	private SwipeDirection swipeDirection = SwipeDirection.NONE;
	
	// Public vars accessible in editor
	public bool constantDetection = false;	// Turn on to always detect swipes anywhere, not just on specific UI element
	
	public float swipeSpeed = 1f;
	public float minSwipeDistance = 0.65f;
	public float swipeDeadZone = 0.1f;
	
	public string eventName;
	
	public Camera customUICam;
	
	// Private variables
	private Vector2 _touchStart, _touchEnd, _lastPos,
					_currentTouch, _moveAmount;

	private float _comfortZone;
	private float _swipeVelocity;
	private float _swipeDist;
	private float _minSwipeDist;
	private GameObject _swipeObj;
	
	private bool _couldBeSwipe;
	private bool _swipeSuccess;
	private bool _touchEnded;
	private bool _swipeEnded;
	
	private bool _touchControls, _mouseControls;
	
	
	#region Getter and Setters
	public Vector2 CurrentTouchPos
	{
		get{ return _currentTouch; }
	}
	
	public Vector2 TouchStart
	{
		get{ return _touchStart; }
		set{ _touchStart = value; }
	}
	
	public Vector2 TouchEnd
	{
		get{ return _touchEnd; }
	}
	
	public Vector2 MoveAmount
	{
		get{ return _moveAmount; }
		set{ _moveAmount = value; }
	}
	
	public float SwipeVelocity
	{
		get{ return _swipeVelocity; }
		set{ _swipeVelocity = value; }
	}
	
	public float ComfortZone
	{
		get{ return _comfortZone; }
	}
	
	public float SwipeDist {
		
		get{ return _swipeDist; }
	}	
	
	public float MinSwipeDist
	{
		get{ return _minSwipeDist; }
	}

	public GameObject SwipeObj
	{
		get{ return _swipeObj; }
	}
	
	public bool SwipingLeft		{ get{ return ( swipeDirection == SwipeDirection.SWIPE_LEFT ); }}
	public bool SwipingRight	{ get{ return ( swipeDirection == SwipeDirection.SWIPE_RIGHT ); }}
	public bool SwipingUp		{ get{ return ( swipeDirection == SwipeDirection.SWIPE_UP ); }}
	public bool SwipingDown		{ get{ return ( swipeDirection == SwipeDirection.SWIPE_DOWN ); }}
	
	public bool CouldBeSwipe
	{ 
		get{ return _couldBeSwipe; }
		set{ _couldBeSwipe = value; }
	}
	
	public bool SwipeSuccess
	{ 
		get{ return _swipeSuccess; }
	}
	
	public bool TouchEnded
	{ 
		get{ return _touchEnded; } 
	}
	
	public bool SwipeEnded
	{ 
		get{ return _swipeEnded; } 
	}
	
	#endregion
	
	
	
	void OnEnable()
	{
		_instance = this;
	}
	
	
	// =============================================== AWAKE FUNCTION =============================================== //
	void Awake()
	{
		if( !_instance ) _instance = this;
		
		// Set correct control types depending on platform
		if( Application.platform == RuntimePlatform.IPhonePlayer ||
			Application.platform == RuntimePlatform.Android )
		{
			_touchControls	= true;
			_mouseControls	= false;
		}
		else
		{
			_touchControls	= false;
			_mouseControls	= true;
		}
		
		if( !UICamera.mainCamera )
		{
			if( !customUICam )
			{
				customUICam = FindObjectOfType( typeof( Camera )) as Camera;
				if( !customUICam )
				{
					Debug.Log("There are no cameras in the scene! In this case, the Swipe won't check for ray collision with gameObjects.");
				}
			}
		}
	}
	
	
	// =============================================== START FUNCTION =============================================== //
	void Start()
	{
		// Initialize class members
		_currentTouch	= Vector2.zero;
		_touchStart		= Vector2.zero;
		_touchEnd		= Vector2.zero;
		_lastPos		= Vector2.zero;
		
		_moveAmount		= Vector2.zero;
		_swipeVelocity	= 0f;
		_comfortZone	= Screen.width * swipeDeadZone;
		_minSwipeDist	= Screen.width * minSwipeDistance;
		
		_couldBeSwipe	= false;
		_swipeSuccess	= false;
		_touchEnded		= false;
		_swipeEnded		= false;
	}
	
	
	// =============================================== UPDATE FUNCTION =============================================== //
	void Update ()
	{
		if( constantDetection ) DetectSwipe( _comfortZone, _minSwipeDist, swipeType );
	}
	
	
	// ================================================================================================================================ //
	// ======================================================= CUSTOM FUNCTIONS ======================================================= //
	// ================================================================================================================================ //
	
	// =============================================== SWIPE HORIZONTAL FUNCTION =============================================== //
	private void DetectSwipe( float deadZone, float minSwipeDist, SwipeType sType )
	{
		// ********* TOUCH INPUTS ********* //
		if( _touchControls )
		{
			// Stop if no touches are happening
			if( Input.touches == null ) return;
			
			// Iterate through all touches
			foreach( Touch touch in Input.touches )
			{
				// Store the swipe distance
				_swipeDist		= ( touch.position - _touchStart ).magnitude;
				
				switch( touch.phase )
				{
					case TouchPhase.Began:
						ResetSwipeStates( true );
						_touchStart = touch.position;
						_lastPos	= touch.position;
						break;
						
					case TouchPhase.Moved:
						if( Mathf.Abs( _swipeDist ) > deadZone )
						{
							_swipeObj		= GetSwipedObject( touch.position );
							_swipeVelocity	= touch.deltaPosition.magnitude * touch.deltaTime * 10;
							
							_couldBeSwipe	= true;
							_swipeEnded		= false;
							_touchEnd		= touch.position;
							
							// Track touch position to see how much we move
							_moveAmount += touch.deltaPosition * swipeSpeed;
							_moveAmount.x *= (( Screen.width - _swipeDist ) / Screen.width ) * Time.deltaTime;
							
							// Are we swipping left or right?
							swipeDirection = GetSwipeDirection( sType, touch.deltaPosition );
//							print("USING TOUCH FOR SWIPE");
						}
						
					    //print("Swipe Distance: " + _swipeDist );
						//print("Move Amount: " + _moveAmount );
						//print("Touch Range: " + Mathf.Abs( touch.position.x - _touchStart.x) );
						break;
						
					case TouchPhase.Stationary:
						_moveAmount = Vector2.zero;
						_swipeEnded	= true;
						break;
						
					case TouchPhase.Ended:
						
						// Check how long the swipe was, and check the swipe direction
						if( _couldBeSwipe )
						{
							_moveAmount = Vector2.zero;
							_swipeEnded	= true;
							
							// When swipe ends, get the swipe direction again, but this time use
							// the start position of the touch to calculate the swipe direction.
							// This is required for events that take place AFTER the swipe ended,
							// like the Level Select Screen which changes screen depending on the
							// swipe direction.
							swipeDirection = GetSwipeDirection( sType, touch.position, _touchStart );
							
							// Check how long the swipe was, and check the swipe direction
//							Debug.Log("_swipeDist: " + Mathf.Abs( _swipeDist ) + "  | minsSwipeDist: " + minSwipeDist);
							if( _swipeDist > minSwipeDist )
							{
								_swipeSuccess = true;
							}
							else
							{
								print("SWIPE NOT LONG ENOUGH");
								_swipeSuccess = false;
							}
							
						}
						ResetSwipeStates( false );
						break;
				}
			}
			
			return;		// End of touch controls
		}
		
		// ********* MOUSE INPUTS ********* //
		if( _mouseControls )
		{
			Vector2 mPos	= new Vector2( Input.mousePosition.x, Input.mousePosition.y );
			Vector2 mAxis	= new Vector2( Input.GetAxis( "MouseX" ), Input.GetAxis( "MouseY" ));
			
			if( Input.GetMouseButtonDown( 0 ))
			{
				ResetSwipeStates( true );
				_touchStart = mPos;
				_lastPos	= mPos;
			}
			
			if( Input.GetMouseButton( 0 ) )
			{
//				var delta = mPos - _lastPos;
				
				// Store the swipe distance
				_swipeDist		= ( mPos - _touchStart ).magnitude;
				
				if( Mathf.Abs( _swipeDist ) > deadZone )
				{
					_swipeObj		= GetSwipedObject( mPos );
					_swipeVelocity	= mAxis.magnitude * Time.deltaTime * 10;
					
					_couldBeSwipe 	= true;
					_swipeEnded		= false;
					_touchEnd		= mPos;
					
					// Track touch position to see how much we move
					_moveAmount = mAxis * swipeSpeed * Time.deltaTime;
//					Debug.Log("Move Amount: " + _moveAmount);
					
					// While swiping, are we swipping left or right?
					swipeDirection = GetSwipeDirection( sType, mAxis );
					
					print("USING MOUSE FOR SWIPE");
				}
				
				_lastPos	= mPos;
				
				// Stationary
				if( mAxis.magnitude == 0f )
				{
					_swipeEnded = true;
				}
			}
			else
			{
				// _couldBeSwipe gets turned off after changing screens, in 'UI_LevelSelection'
				if( _couldBeSwipe && !_touchEnded )
				{
					_moveAmount = Vector2.zero;
					
					// When swipe ends, get the swipe direction again, but this time use
					// the start position of the touch to calculate the swipe direction.
					// This is required for events that take place AFTER the swipe ended,
					// like the Level Select Screen which changes screen depending on the
					// swipe direction.
					swipeDirection = GetSwipeDirection( sType, mPos, _touchStart );
					
					// Check how long the swipe was, and check the swipe direction
//					Debug.Log("_swipeDist: " + Mathf.Abs( _swipeDist ) + "  | minsSwipeDist: " + minSwipeDist);
					if( Mathf.Abs( _swipeDist ) > minSwipeDist )
					{
						_swipeSuccess	= true;
					}
					else
					{
						print("SWIPE NOT LONG ENOUGH");
						_swipeSuccess	= false;
					}
				}
				ResetSwipeStates( false );
			}
			
			return;		// End of mouse controls
		}
	    
	}
	
	
	
	// =============================================== RESET SWIPE STATES FUNCTION =============================================== //
	
	/// <summary>
	/// Resets the swipe states, at the begining or end of swipe.
	/// </summary>
	/// <param name='touchBegan'>
	/// Boolean: is this being called on TouchPhase.Began/Input.GetMouseButtonDown (different values get reset at begining of new touch/input)?
	/// </param>
	public void ResetSwipeStates( bool touchBegan )
	{
		// Make sure to reset boolean flags
		
		_moveAmount		= Vector2.zero;
		
		if( touchBegan )
		{
			_touchEnded		= false;
			_couldBeSwipe	= false;
			_swipeSuccess	= false;
		}
		else
		{
			_touchEnded		= true;
		}
	}
	
	
	// =============================================== SWIPE DIRECTION FUNCTIONS =============================================== //
	
	/// <summary>
	/// Gets the direction of the current swipe.
	/// </summary>
	/// <returns>
	/// Enum Value: The swipe direction (LEFT/RIGHT/UP/DOWN).
	/// </returns>
	/// <param name='sType'>
	/// SwipeType: The type of swipe (HORIZONTAL/VERTICAL/BOTH).
	/// </param>
	/// <param name='tDeltaPos'>
	/// Vector2: The delta position of the current touch (same as touch.position - lastPos).
	/// </param>
	private SwipeDirection GetSwipeDirection( SwipeType sType, Vector2 tDeltaPos )
	{
		// Here we're using the deltaPosition of the current touch/mous position.
		// The delta position is equivalent to touch.position - lastPos.
		switch( sType )
		{
			case SwipeType.HORIZONTAL:
				if( tDeltaPos.x < 0 )
				{
//					Debug.Log("SWIPING LEFT!");
					return SwipeDirection.SWIPE_LEFT;
				}
				else if( tDeltaPos.x > 0 )
				{
//					Debug.Log("SWIPING RIGHT!");
					return SwipeDirection.SWIPE_RIGHT;
				}
				break;
				
			case SwipeType.VERTICAL:
				if( tDeltaPos.y < 0 )
				{
//					Debug.Log("SWIPING DOWN!");
					return SwipeDirection.SWIPE_DOWN;
				}
				else if( tDeltaPos.y > 0 )
				{
//					Debug.Log("SWIPING UP!");
					return SwipeDirection.SWIPE_UP;
				}
				break;
		}
		
		// Return NONE if none of the above are true
//		Debug.Log("SWIPING NONE!");
		return SwipeDirection.NONE;
	}
	

	/// <summary>
	/// Get the gameObject being swiped on.
	/// </summary>
	/// <returns>
	/// GameObject: The swiped gameObject.
	/// </returns>
	/// <param name='touchPosition'>
	/// Vector2: Current position of touch/input.
	/// </param>
	private GameObject GetSwipedObject( Vector2 touchPosition )
	{
		Camera cam = UICamera.mainCamera ? UICamera.mainCamera : customUICam;
		if( !cam ) return gameObject;
		else
		{
			Ray ray = cam.ScreenPointToRay( touchPosition );
			RaycastHit hit;
			if( Physics.Raycast( ray, out hit ))
			{
//				Debug.LogWarning("Swipping ON: " + hit.transform.gameObject.name );
//				Debug.Log("Raycasting Camera: " + cam.name);
				
				return hit.transform.gameObject;
			}
			
			// If the ray doesn't hit any object, then return the game object this script is attached to
			return gameObject;
		}
	}
	
	
	public void OnApplicationQuit()
	{
		_instance = null;
	}
	
}

And from my GUI_Controls class, I access values stored in Swipe() to decide which actions to take:

using UnityEngine;
using System.Collections;

public class GUI_Controls : MonoBehaviour {
	
	public Swipe swipe;
	
	public bool forceControlsOn = false;	// Used to bypass game state check
	
	public float preloadMinDist = 200f;
	
	public bool iphoneControls = true;
	public bool mouseControls = false;

	public GameObject preloadBtn;

        public bool preloadOn = false;
	

	
	// =============================== AWAKE FUNCTION =============================== //
    void Awake ()
    {
		if( !this.enabled ) return;
    }
	
	
	// =============================== STAR FUNCTION =============================== //
    void Start ()
    {
		if( !forceControlsOn )
		{
			if( !GameStates.initDone )
			{
				Debug.LogWarning("Disabling gui controls. ~ " + this);
				this.enabled = false;
				return;
			}
		}
		
		if( Application.platform != RuntimePlatform.IPhonePlayer )
			iphoneControls = false;
		else
			iphoneControls = true;
		
		// Get the Swipe class
		swipe = Swipe.Instance;
	}
	
	
	// =============================== UPDATE FUNCTION =============================== //
	void Update() {
		
		if( !forceControlsOn )
		{
			// ................
		}
		else
		{
			// Check for preload conditions
			if( swipe.SwipeObj == preloadBtn && swipe.SwipingUp )
			{
				CheckForPreload( swipe.SwipeDist );
			}
		}
	}

	
	// ================================================= SWIPE CONTROLS (preload/scrub) ================================================= //
	// Keeping simple functions like 'CheckForPreload', which itself calls a more advanced function,
	// lets us add simple event listeners with only 1-2 parameters, if needed
	public void CheckForPreload( float swipeDistance )
	{
		CheckForSwipeControlState( swipeDistance, preloadMinDist, "PRELOAD", ref preloadOn );
	}
	
	public void CheckForSwipeControlState( float swipeDistance, float minSwipeDist, string controlName, ref bool controlOn )
	{
		if( this.enabled )
		{
			if( !forceControlsOn )
			{
				// ..............
			}
			else
			{
				if( !swipe.TouchEnded )
				{
					if( swipeDistance > minSwipeDist )
					{
						controlOn = true;
					}
				}
				
				if( swipe.TouchEnded || swipe.SwipeEnded ) controlOn = false;
			}
			
		}
		
		Debug.LogWarning("swipeDistance: " + swipeDistance, this);
		
	}
   
}

There it is…hopefully someone can see something I’m not seeing and help me figure out why swiping 1 finger on the screen slows my frame-rate down. Also, if I’m doing anything BAD in my classes above, please don’t be afraid to let me know :stuck_out_tongue: I take criticism very well :slight_smile:

Thanks!

===================================================================================

OLD: I realize that they are not free, but I have seen my FPS drop by 10fps when swiping on the screen! That was never an issue before so I wonder if the latest Unity update has anything to do with it.

Also, is it faster to use:

int count = Input.touchCount;
for( t = 0; t < count; t++ )
{
    Touch touch = Input.GetTouch(t);
    // Process touch phases/events
}

// Or use:

foreach( Touch touch in Input.touches )
{
    // process touch phases/events
}

Should I really be expecting my FPS to drop by 10 when swiping on the screen? Just touching the screen is fine, it’s only when I start swiping that it takes a hit.

Thanks…

Maybe the bottleneck is somewhere else? I had a similar problem some time ago, but in the end the real culprit was my method of applying the input. From your description, I don’t know if you’ve isolated your swipe class for testing - if not, check out what happens in other classes. You wrote that you’re doing suspension stuff, which sounds kinda expensive :slight_smile:

Having said that: In my game, I can still see a certain slowdown when I’m touching the screen, but not as drastic as what you’re experiencing.

Here is a tool that might help you with your further analysis: Unity3D: Tweaked version of @robotduck's CodeProfiler script. · GitHub - this is a profiling tool. You can use that to check if it’s your input or something else that causes the slowdown. Hope you find what’s troubling you!

Sooooo…

After doing some more testing and researching online, it seams I might have pinned down my slowdown problems with my Swipe() class:

// What I had to start with
foreach( Touch touch in Input.touches )
{
    // do a bunch of stuff with touch
}

// What I have now, which seems a bunch faster
int touchCount = Input.touchCount;
for( int i = 0; i < touchCount; i++ )
{
    Touch touch = Input.GetTouch(i);
    // do a bunch of stuff with touch
}

Here’s an explanation of why Input.GetTouch() might be the faster way: http://answers.unity3d.com/questions/167750/how-does-multi-touch-work.html