MonoGame阅读触摸手势

我目前正在使用梦幻般的monogame框架编写游戏。 我无法正确对触摸输入作出反应。 当用户水平或垂直拖动时,我想每次拖动执行一次动作。 问题是每次拖动都会多次发出手势。 这是我的代码:

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

为了本示例的目的,我已将所有此代码移动到一个块中。 然后返回的RotateRightCommand或RotateLeftCommand由调用代码执行,该代码在屏幕上旋转对象。 整个代码块在monogame的更新循环中运行。 我认为我在重置触摸输入方面缺少一些东西,这就是我为一次拖动返回3或4个RotateCommands的原因。 我究竟做错了什么?

编辑:你这里没有正确使用手势。 每次手指在屏幕上移动时都会生成拖动手势。 如果您将手指从屏幕的一侧移动到另一侧(非常快),您将获得许多小拖动手势。 这就是XNA和MonoGame的工作方式。

这是你正在寻找的逻辑:

 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); } 

如果你更愿意做手势,你可以这样做:

 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); } } 

无论哪种方式都会给你你正在寻找的行为。 你仍然需要像我在原帖中所说的那样将逻辑放在循环中,因为你可以排队多个手势,而你不想假设堆栈中的最后一个是拖动。 (多边触控,你可以有拖动,点击,拖动完成等)。

我不是100%确定这是否是你的问题…但你的逻辑在这里是错误的。 CodeFormatting老板在这里击败我,但它应该更像是这样:

 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); } } 

如果不将TouchPanel.ReadGesure()放在循环中,那么每帧只能读取一个gesure。 可用的手势被放入队列中,只有在调用ReadGesture()时才会被删除。 因此,如果您的帧率打嗝,或者您无法像操作系统可以读取的那样快速读取手势(这很可能),您将使用旧信息。 你可以在这看到。 对于这个应用程序,我建议采取每个手势,并将其组合成一个或两个,然后根据它决定你应该做什么。

我想这取决于你认为的拖累。 MonoGame和XNA考虑检测从一次更新到下一次更新的触摸输入的变化。 因此,如果您认为从触摸手指到屏幕直到移除它将会收到一个手势,那么在XNA和MonoGame术语中这将是不正确的。 返回的手势是从T-1到T的Delta,其中T是Now,T-1是之前的Update调用。