MonoGame for reading touch gestures

I am currently writing a game using the fantastic monogame structure. I am having trouble setting input touch properly. When a user drags horizontally or vertically, I want to perform one action in one click. The problem is that the gesture is issued several times for each resistance. Here is my code:

var gesture = default(GestureSample); while (TouchPanel.IsGestureAvailable) gesture = TouchPanel.ReadGesture(); if (gesture.GestureType == GestureType.VerticalDrag) { if (gesture.Delta.Y < 0) return new RotateLeftCommand(_gameController); if (gesture.Delta.Y > 0) return new RotateRightCommand(_gameController); } if (gesture.GestureType == GestureType.HorizontalDrag) { if (gesture.Delta.X < 0) return new RotateLeftCommand(_gameController); if (gesture.Delta.X > 0) return new RotateRightCommand(_gameController); } 

I moved all of this code into one block for the purposes of this example. The returned RotateRightCommand or RotateLeftCommand is then executed by a call code that rotates the object on the screen. All this block of code is launched in the update cycle in the monogame. I think I am missing something in terms of resetting touch input and why am I getting 3 or 4 RotateCommands that were returned for a single drag. What am I doing wrong?

+4
source share
2 answers

Edit: You are not using gestures here. A drag gesture is generated each time a finger moves across the screen. If you move your finger from one side of the screen to the other (very fast), you will get many small gestures. This is how XNA and MonoGame work.

This is the logic you are looking for:

 var touchCol = TouchPanel.GetState(); foreach (var touch in touchCol) { // You're looking for when they finish a drag, so only check // released touches. if (touch.State != TouchState.Released) continue; TouchLocation prevLoc; // Sometimes TryGetPreviousLocation can fail. Bail out early if this happened // or if the last state didn't move if (!touch.TryGetPreviousLocation(out prevLoc) || prevLoc.State != TouchState.Moved) continue; // get your delta var delta = touch.Position - prevLoc.Position ; // Usually you don't want to do something if the user drags 1 pixel. if (delta.LengthSquared() < YOUR_DRAG_TOLERANCE) continue; if (delta.X < 0 || delta.Y < 0) return new RotateLeftCommand(_gameController); if (delta.X > 0 || delta.Y > 0) return new RotateRightCommand(_gameController); } 

If you prefer to make gestures, you can simply do this:

 var gesture = default(GestureSample); while (TouchPanel.IsGestureAvailable) { gesture = TouchPanel.ReadGesture(); if (gesture.GestureType == GestureType.DragComplete) { if (gesture.Delta.Y < 0 || gesture.Delta.X < 0) return new RotateLeftCommand(_gameController); if (gesture.Delta.Y > 0 || gesture.Delta.X > 0) return new RotateRightCommand(_gameController); } } 

In any case, you get what you are looking for. You still need to put the logic inside the loop, as I said in the original post, because you can have multiple gestures in the queue, and you don't want to assume that the last one on the stack is a drag and drop. (Thanks to multi-touch, you can have drag and drop, taps, drag and drop, etc.).

I am not 100% sure if this is your problem ... but your logic here is wrong. The lead CodeFormatting beats me here, but it should be something like this:

 var gesture = default(GestureSample); while (TouchPanel.IsGestureAvailable) { gesture = TouchPanel.ReadGesture(); if (gesture.GestureType == GestureType.VerticalDrag) { if (gesture.Delta.Y < 0) return new RotateLeftCommand(_gameController); if (gesture.Delta.Y > 0) return new RotateRightCommand(_gameController); } if (gesture.GestureType == GestureType.HorizontalDrag) { if (gesture.Delta.X < 0) return new RotateLeftCommand(_gameController); if (gesture.Delta.X > 0) return new RotateRightCommand(_gameController); } } 

Without putting TouchPanel.ReadGesure () inside the loop, you only read one argument per frame. Available gestures are queued and deleted only when ReadGesture () is called. Therefore, if your frame rate hiccups, or if you cannot read the gesture as fast as you can read it (which is very possible), you will work with the old information. You can see that here . For this application, I propose to take each gesture and combine it into one or two, and then decide what you should do based on this.

+13
source

I think it depends on what you consider one of them. MonoGame and XNA consider detecting changes in touch input from one update to the next. Therefore, if you think that you will receive one Gesture from the moment you touch your finger on the screen until you delete it, this would be incorrect in terms of XNA and MonoGame. The gesture that returns is Delta from T-1 to T, where T is now and T-1 is the previous call to Update.

+2
source

All Articles