MonoGame 阅读触摸手势 [英] MonoGame reading touch gestures

查看:23
本文介绍了MonoGame 阅读触摸手势的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am currently writing a game using the fantastic monogame framework. I am having trouble reacting to touch input correctly. When a user drags horizontally or vertically I want to perform an action once per drag. The problem is the gesture is getting issued multiple times for each drag. 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);
}

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

I have moved all of this code into one block for the purposes of this example. The RotateRightCommand or RotateLeftCommand that is returned is then executed by the calling code which rotates the object on the screen. This whole block of code is being run in the update loop in monogame. I think I am missing something in terms of resetting the touch input and that's why I'm getting 3 or 4 RotateCommands returned for one drag. What am I doing wrong?

推荐答案

您在此处未正确使用手势.每次手指在屏幕上移动时都会生成一个拖动手势.如果您将手指从屏幕的一侧移动到另一侧(非常快),您会得到很多小的拖动手势.这就是 XNA 和 MonoGame 的工作原理.

You're not using gestures correctly here. A drag gesture is generated every time a finger moves across the screen. If you move your finger from one side of the screen to the other (Very quickly), you'll get a lot of small drag gestures. This is how XNA and MonoGame work.

这是您正在寻找的逻辑:

This is the logic you're 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'd rather do gestures, you can just 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);
    }
}

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

Either way will give you the behavior you're looking for. You still need to put the logic inside of the loop as I said in the original post, because you can have multiple gestures queued up, and you don't want to assume that the last one in the stack is the drag. (Thanks to multitouch you can have drags, taps, drag complete, etc).

我不能 100% 确定这是否是您的问题……但您的逻辑在这里是错误的.CodeFormatting老大在这里打我,但应该更像这样:

I'm not 100% sure if this is your problem... but your logic is wrong here. The CodeFormatting boss is beating me here, but it should be more 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);
    }
}

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

By not putting the TouchPanel.ReadGesure() inside of a loop, you're only reading one gesure per frame. The available gestures are put into a queue, and only removed when ReadGesture() is called. Therefore if your framerate hiccups, or if you can't read a gesture as fast as you the OS can read it (Which is very possible), you'll be working with old information. You can see that here. For this application, I suggest taking each gesture, and combining it into one or two, then deciding what you should do based on that.

这篇关于MonoGame 阅读触摸手势的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆