我目前正在使用梦幻般的monogame框架编写游戏。我无法正确对触摸输入作出反应。当用户水平或垂直拖动时,我想每次拖动执行一次动作。问题是每次拖动都会多次发出手势。这是我的代码:
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);
}
出于本示例的目的,我已将所有此代码移动到一个块中。然后返回的RotateRightCommand或RotateLeftCommand由调用代码执行,该调用代码在屏幕上旋转对象。整个代码块在monogame的更新循环中运行。我认为我在重置触摸输入方面缺少一些东西,这就是我为一次拖动返回3或4个RotateCommands的原因。我做错了什么?
答案 0 :(得分:15)
编辑:你这里没有正确使用手势。每次手指在屏幕上移动时都会生成拖动手势。如果您将手指从屏幕的一侧移动到另一侧(非常快),您将获得许多小拖动手势。这就是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);
}
}
无论哪种方式都会为您提供您正在寻找的行为。您仍然需要像我在原始帖子中所说的那样将逻辑放在循环内部,因为您可以排队多个手势,并且您不希望假设堆栈中的最后一个是拖动。 (多边触控,你可以使用拖动,点击,拖动完成等)。
我不是百分百确定这是否是你的问题...但你的逻辑在这里是错误的。 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()时才会被删除。因此,如果您的帧率打嗝,或者您无法像操作系统可以读取的那样快速读取手势(这很可能),您将使用旧信息。你可以看到here。对于这个应用程序,我建议采取每个手势,并将其组合成一个或两个,然后根据它决定你应该做什么。
答案 1 :(得分:2)
我想这取决于你认为的拖累。 MonoGame和XNA考虑检测从一次更新到下一次更新的触摸输入的变化。因此,如果您认为从触摸手指到屏幕直到移除它将会收到一个手势,那么在XNA和MonoGame术语中这将是不正确的。返回的手势是从T-1到T的Delta,其中T是Now,T-1是之前的Update调用。