I was having issues with the Gesture classes, so I’ve switched over to using TouchLocation objects. It’s working fine so far, but I can’t seem to get a Swipe gesture working.
In the Game1.cs’ Update method, I have the following code:
// Get the collection of TouchLocation objects
TouchCollection touchCollection = TouchPanel.GetState();
for (int i = 0; i < touchCollection.Count; i++)
{
if (IsScreenSwiped(touchCollection[i]) == true)
{
Debug.OutputValue("Was swiped!");
}
}
The purpose of this code is, of course, to check if the screen was swiped. Here’s my IsScreenSwiped method:
public bool IsScreenSwiped(TouchLocation? touchLoc)
{
// Return false if the touch location is null
if (touchLoc == null) return false;
// Convert the specified location to a non-nullable TouchLocation to access its properties
TouchLocation fullTouchLoc = (TouchLocation)touchLoc;
// Return false if the touch is not in the released state
if (fullTouchLoc.State != TouchLocationState.Released) return false;
// Stores the previous touch location of the gesture
TouchLocation prevLoc;
// Try to get the previous location
// Return false if the previous location could not be found or the previous location's state is not Moved
if (fullTouchLoc.TryGetPreviousLocation(out prevLoc) == false || prevLoc.State != TouchLocationState.Moved)
return false;
// Get the difference between the two positions
Vector2 delta = (fullTouchLoc.Position - prevLoc.Position);
float DragTolerance = 20;
return (Math.Abs(delta.X) >= DragTolerance);
}
My code was heavily based on the Stack Overflow answer found here.
The issue is that the delta is always 0. The previous touch location’s Position is equal to the current touch location’s Position, and so the method never returns true to indicate that a swipe has occurred.
I’ve been working with this for a few hours now and can’t seem to wrap my head around it. I would prefer to use TouchLocations, as Gestures have caused freezing and other weird issues in my game. Since switching to TouchLocations, I haven’t had a problem.
Does anyone have any insight on how I can get swipe gestures working? Thanks in advance for any help!
I’ve figured it out! Below is how I did it. All code is in Game1.cs:
I defined two class variables.
// The minimum amount required to move your finger after holding it down to be considered a swipe input
private const float DragTolerance = 30f;
// Stores the previous touch location. Used for swiping
private Vector2 PrevTouchLoc;
Then, I created a method for capturing the current touch location.
public TouchLocation? GetTouchLocation()
{
// Get the collection of TouchLocation objects
TouchCollection touchCollection = TouchPanel.GetState();
// Check if no touches can be found
if (touchCollection.Count < 1)
{
// Reset the previous touch location
ResetPrevTouchLoc();
// Return null
return null;
}
// Check if a previous touch location doesn't exist
if (PrevTouchLoc == -Vector2.One)
{
// Set the previous touch location to the first touch location
PrevTouchLoc = touchCollection[0].Position;
}
// Return the first TouchLocation object
return (touchCollection[0]);
}
Then, I created the ResetPrevTouchLoc method.
This method sets the PrevTouchLocation to coordinates of (-1, -1). It is not possible for a player to tap on a negative coordinate, so -Vector2.One is basically the default value that indicates that a previous touch location has not yet been set.
After, I made sure to reset the previous touch location when the game starts so that it will be set to its default value. Do this in the Initialize method in Game1.cs.
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
ResetPrevTouchLoc();
...
}
I created two methods: one for checking if the screen was swiped, and one for getting the delta between the current and previous touch points.
public bool IsScreenSwiped(float delta)
{
// Get the positive value of the delta
delta = Math.Abs(delta);
// Return whether or not a swipe was performed
return (delta >= DragTolerance);
}
public float GetSwipeDelta(TouchLocation? touchLoc)
{
// Return false if the touch location is null
if (touchLoc == null) return 0f;
// Convert the specified location to a non-nullable TouchLocation to access its properties
TouchLocation fullTouchLoc = (TouchLocation)touchLoc;
// Return false if the touch is not in the released state
if (fullTouchLoc.State != TouchLocationState.Released) return 0f;
// Get the difference between the two positions
Vector2 delta = (fullTouchLoc.Position - PrevTouchLoc);
// Reset the previous touch location
ResetPrevTouchLoc();
// Return the X difference between the current and previous touch points
return delta.X;
}
Finally, I implemented the code in the Update method.
protected override void Update(GameTime gameTime)
{
// Get the last touch gesture (if any)
TouchLocation? touchLoc = GetTouchLocation();
// Get the delta of a potential swipe gesture
float delta = GetSwipeDelta(touchLoc);
// Check if the screen was swiped
if (IsScreenSwiped(delta) == true)
{
// Put swipe logic here
}
...
}
That’s about it! The code is well-commented, so that should do a good job of explaining what everything is, and why it’s done. However, if you have any questions, please feel free to ask!
Just one final note: the code is not perfect. It doesn’t allow for multiple touches per frame, but this can probably be overcome by just looping through the code in the Update method (step #6). You can get the number of items in the TouchCollection and create a FOR loop using that count.
Also, a player can technically tap on a point on the screen, hold it for as long as he/she wants, and let go somewhere else on the screen, and it could constitute a swipe. While this is an issue, for my purposes it is fine. I’m sure the code can be modified a little bit to include a timer of some sort to prevent excessive holds and drags from being considered a swipe. One idea is to store the game time when the previous touch location was registered and compare that time to the time that the point was released.