- Home /
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 :P I take criticism very well :)
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...
I have Unity 3.5.6f4, not 4.0 yet :)
Thx for the link, reading it right now...
Fattie, I read through the whole page in that link you gave me, and although there is tons of great info on touches there, there wasn't anything related to slowdowns/expensive ways to process touches etc.
One thing I am wondering is, I used to use floats to store my touch positions, and now use Vector2, and then access x/y by myTouchPos.x, myTouchPos.y...could using Vectors ins$$anonymous$$d of floats be a performance hit?
Fattie, I will post my Swipe class when I get home, maybe you'll see something I'm not seeing! Another thing I just thought about, is that I recently got the NGUI extension, which also does swipe detection in its core UICamera class. The UICamera class is automatically attached to their Camera, so it's very possible that it's running both their swipe detection and my swipe detection at the same time...
I tried completely deleting any NGUI elements from my scene and running again, and it seemed like the FPS was better, but still dropping by 4-5FPS.
$$anonymous$$an I should really compile and run on the iPhone everytime I work on my game, ins$$anonymous$$d of testing it on the phone every 2-3 weeks...would make it much easier to find new bottlenecks!
Is the degredation in performance relative to the number of fingers that are on the screen?
whydoidoit, no, I'm swiping with only 1 finger, although I need to test with multiple fingers and observe the results...
Fattie, you're right I need to strip everything out and do more testing that way. I will do that and let you know my findings.
As for the FPS numbers involved, it's around 57-60 when not swiping on the screen, and goes down to 48-49 when swiping, with 1 finger.
Answer by ronronmx · Oct 15, 2012 at 06:24 PM
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
Answer by refardeon · Oct 10, 2012 at 07:12 PM
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 :)
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: https://gist.github.com/2033967 - 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!
Thanks for the link to CodeProfiler, I'm gonna run some tests and see what's going on.
The suspension stuff I'm doing is pretty simple:
if( swipingIsTrue ) rigidbody.AddRelativeForce( globalUp * preloadStrenght, Force$$anonymous$$ode.Impulse );
Not much going on here. I'll use CodeProfiler to try and pinpoint where my slowdown is co$$anonymous$$g from.
Your answer
Follow this Question
Related Questions
Working with Touch screens... 1 Answer
How do I invert the Y axis in Penelope tutorial? 3 Answers
Iphone touch not working 0 Answers
Delay before first touch position changes on iPhone 1 Answer
simple TOUCH of a 3D object in iOS 2 Answers