【问题标题】:multitouch results in methods firing twice多点触控导致方法触发两次
【发布时间】:2012-04-26 10:58:06
【问题描述】:

我正在开发一款将 ipad 屏幕分为下半部分和上半部分的小游戏。每个玩家都有自己的部分可以玩(一个手指游戏)。我必须在视图上启用多点触控,因为当两个玩家同时点击屏幕时,只有一个玩家的方法会被执行或根本不执行。

但是,当 2 个玩家执行完全相同的操作时,这会导致方法触发两次的奇怪行为。这就是它现在的工作方式: 它检查玩家是否触摸了视图中的对象。如果有,就会触发一个方法。如果玩家没有触摸对象而是视图本身,则会触发另一个方法。它检查视图是在上半部分还是下半部分被触摸,以区分玩家一或玩家二的触摸。

我一直在考虑一个解决方案,但我不确定什么是解决这个问题的好方法。也许我应该为每个玩家分开视图(透明),以便我可以更轻松地区分触摸?这是我的 touchesBegan 方法。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{

    NSMutableSet *touchedCirclesPlayerOne = [NSMutableSet set];
    NSMutableSet *touchedCirclesPlayerTwo = [NSMutableSet set];

    for (UITouch *touch in touches) {
        CGPoint touchLocation = [touch locationInView:self.view];
        for (Circle *circle in playerOneCircles) {
            if ([circle.layer.presentationLayer hitTest:touchLocation]) {
                [touchedCirclesPlayerOne addObject:circle];

            } 
        }

    for (UITouch *touch in touches) {
        CGPoint touchLocation = [touch locationInView:self.view];
        for (Circle *circle in playerTwoCircles) {
            if ([circle.layer.presentationLayer hitTest:touchLocation]) {
                [touchedCirclesPlayerTwo addObject:circle];

                } 
            }
    }

    if (touchedCirclesPlayerOne.count) {

        NSLog(@"test");

        for (Circle *circle in touchedCirclesPlayerOne) {

            [circle playerTap:nil];

        }

    } else if (touchedCirclesPlayerTwo.count) {

        NSLog(@"test2");

        for (Circle *circle in touchedCirclesPlayerTwo) {

            [circle SecondPlayerTap:nil];

        }


    } else {

        for (UITouch *touch in touches) {
            CGPoint touchLocation = [touch locationInView:self.view];

            if (CGRectContainsPoint(CGRectMake(0, self.view.frame.size.height/2, self.view.frame.size.width, self.view.frame.size.height/2), touchLocation)) {

            NSLog(@"wrong player 1");
            [[NSNotificationCenter defaultCenter] postNotificationName:@"wrong player 1" object:self];

            }  else {

                NSLog(@"wrong player 2");
                [[NSNotificationCenter defaultCenter] postNotificationName:@"wrong player 2" object:self];
            }

        }


    }

}

}

这里有一个小示意图。这一切都有效,除非两个玩家做同样的事情。它会为每个玩家触发两次相同的动作。

【问题讨论】:

    标签: objective-c ios multi-touch touchesbegan


    【解决方案1】:

    该代码看起来很熟悉:-)。然而,你所拥有的东西做了很多额外的工作。此外,如果有两次点击,它将始终是玩家 1 的点击,而不是玩家 2 的点击。

    您真的想强制每个玩家区域点击一次吗? 请注意,此代码不会阻止这种情况。您可以在前一次触球后开始另一次触球,这不会在集合中。但是,您可以通过查看对象来查看所有当前触摸,而不管它们的状态如何。查询 allTouches,它将为您提供屏幕上的所有当前触摸。

    考虑以下更改...

    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        // Since this rect object is always needed, you probably want to
        // make it once, and keep it as private variables.  If your area is
        // not really divided completely in half, you will want two separate
        // rects, each defining the area for each player.
        CGRect player1Area = CGRectMake(0, self.view.frame.size.height/2, self.view.frame.size.width, self.view.frame.size.height/2);
    
        // For performance sake, we will loop through the touches a single time
        // and process each tap in that loop.  Use these flags to later determine
        // what to do if the player tapped some place other than on a circle.
        BOOL player1Tapped = NO;
        BOOL player2Tapped = NO;
        BOOL player1TappedCircle = NO;
        BOOL player2TappedCircle = NO;
    
        for (UITouch *touch in touches) {
            CGPoint touchLocation = [touch locationInView:self.view];
            if (CGRectContainsPoint(player1Area, touchLocation)) {
                // This touch is in player 1's area
                // Small additional code to restrict player to a single tap.
                player1Tapped = YES;
                for (Circle *circle in playerOneCircles) {
                    // I guess you are using a CAShapeLayer, and looking at the
                    // position during animation?
                    if ([circle.layer.presentationLayer hitTest:touchLocation]) {
                        player1TappedCircle = YES;
                        [circle playerTap:nil];
                    }
                }
            } else {
                // This touch is not for player 1, so must be for player 2...
                player2Tapped = YES;
                for (Circle *circle in playerTwoCircles) {
                    if ([circle.layer.presentationLayer hitTest:touchLocation]) {
                        player2TappedCircle = YES;
                        [circle secondPlayerTap:nil];
                    }
                }
            }
        }
    
        // All touches have now been handled.  We can do stuff based on whether any player
        // has tapped any area, or circles, or whatever.
        if (player1Tapped && !player1TappedCircle) {
            // Player 1 tapped, but did not tap on a circle.
        }
        if (player2Tapped && !player2TappedCircle) {
            // Player 2 tapped, but did not tap on a circle.
        }    
    }
    

    【讨论】:

    • 再次嗨 :) 。您已经获得了如此好的和合乎逻辑的解决方案。当我这样看时,它似乎是如此清晰和明显。我只写了几个月的代码,所以我仍然过于复杂。我必须再次感谢你。
    【解决方案2】:

    我会把它分成两个视图。然后,我会为每个视图附加一个手势识别器。

    UITapGestureRecognizer *tapRecog1 = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap1:)] autorelease]; 
    
    [self.view1 addGestureRecognizer:self.tapRecog1]; 
    
    UITapGestureRecognizer *tapRecog2 = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap2:)] autorelease]; 
    
    [self.view2 addGestureRecognizer:self.tapRecog2];
    

    然后,我将实现动作方法。

    - (void)handleTap1:(UITapGestureRecognizer *)tap;
    {
        CGPoint point = [tap locationInView:self.view1];
    
        // do stuff
    }
    
    - (void)handleTap2:(UITapGestureRecognizer *)tap;
    {
        CGPoint point = [tap locationInView:self.view2];
    
        // do stuff
    }
    

    【讨论】:

    • 这确实是一个解决方案。唯一的问题是在 UIView 动画时这不起作用。
    猜你喜欢
    • 2023-01-27
    • 1970-01-01
    • 2013-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多