如何在cocos2d的模态层下停止所有CCTouch?

时间:2012-09-17 10:59:44

标签: event-handling cocos2d-iphone modal-dialog ccmenuitem

在我的cocos2d游戏中,我有一个“设置”按钮,它启动一个模态层,用于锁定其下的所有内容。为此,我使用菜单状态方法的组合锁定所有CCMenuItems并使用覆盖层;两者都在代码中。

问题是这两种解决方案似乎都不适用于CCScrollLayers。当我单击按钮(启动模态)时,CCScrollLayer仍然可以滚动,这不是我想要的。

我想:

  1. 按下禁用的按钮ALL触摸并禁用所有元素,包括CCScrollLayers
  2. 启动模态(仅允许触摸模态)
  3. 我试过了:

    1. 使用触摸可以使用CCTargetedTouchDelegate
    2. 吞噬所有触摸

      [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];

      1. 我试过
      2. 启动模态

        的图层上的

        self.isTouchEnabled = NO

        1. 我尝试调整MenuStatus方法,以便它适用于CCScrollLayers,但它似乎不起作用。
        2. 我不确定我做错了什么。我的代码现在如下。

          // My main layer which launches the Settings Modal Layer
          
          #pragma mark - Lock/Unlock layers
          
          -(void) doSettings
          {    
              [self lockLayers];
              SettingsModalLayer *sml = [[[SettingsModalLayer alloc] init] autorelease];
              [sml showSettingsOnLayer:self closeBlock:^{[self unlockLayers];}];
          }
          
          -(void) lockLayers
          {
              [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
              [self MenuStatus:NO Node:self];   
          }
          
          -(void) unlockLayers
          {
              [self MenuStatus:YES Node:self];
          }
          
          
          // Disabled/Enable layers
          -(void) MenuStatus:(BOOL)_enable Node:(id)_node
          {
              for (id result in ((CCNode *)_node).children) {        
          
          
                  if ([result isKindOfClass:[CCMenu class]]) {
                      for (id result1 in ((CCMenu *)result).children) {
                          if ([result1 isKindOfClass:[CCMenuItem class]]) {
                              ((CCMenuItem *)result1).isEnabled = _enable;
                          }
                      } // next
                  } 
          
              } // next
          
          }
          
          
          -(void) registerWithTouchDispatcher {
              [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:INT_MIN+1 swallowsTouches:YES];
          }
          
          - (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
          {
              NSLog(@"Event: %@", event);
              for( UITouch *touch in touches )
              {
                  CGPoint location = [touch locationInView: [touch view]];
          
                  location = [[CCDirector sharedDirector] convertToGL: location];        
                  CCLayer *gl = (CCLayer *)[self getChildByTag:4];
                  [gl setIsTouchEnabled:NO];
          
              }
          }
          -(void) ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event
          {
          
          }
          
          
          -(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
          {
              [self removeFromParentAndCleanup:YES];    
          }
          
          -(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
          {
          
              return YES;
          }
          
          
          
          // Settings Modal Layer
          
          -(void) showSettingsOnLayer:(CCLayer *)layer closeBlock:(void (^)())noBlock 
          {
              CoverLayer *coverLayer = [[CoverLayer alloc] init];
              [layer addChild:coverLayer z:1000];
              [coverLayer runAction:[CCFadeTo actionWithDuration:kAnimationTime opacity:155]]; // smooth fade-in to dim with semi-transparency
          
          ... // Other stuff goes here
          
          }
          
          
              // CoverLayer
              // This is meant to stop all touches, but it doesn't really work on CCScrollLayer
          
          #define kDialogTag 1234
          #import "CoverLayer.h"
          
          
          
          // class that implements a black colored layer that will cover the whole screen 
          // and eats all touches except within the dialog box child
          
          @implementation CoverLayer
          - (id)init {
              self = [super init];
              if (self) {
                  [self initWithColor:ccc4(0,0,0,0) 
                                width:[CCDirector sharedDirector].winSize.width 
                               height:[CCDirector sharedDirector].winSize.height];
                  self.isTouchEnabled = YES;
              }
              return self;
          }
          
          - (void)dealloc {
              [[CCTouchDispatcher sharedDispatcher] removeDelegate:self];
              [super dealloc];
          }
          
          
          - (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event 
          {
              CGPoint touchLocation = [self convertTouchToNodeSpace: touch];
              CCNode *dialogBox = [self getChildByTag: kDialogTag];
          
              // eat all touches outside of dialog box
              return !CGRectContainsPoint(dialogBox.boundingBox, touchLocation);
          }
          

3 个答案:

答案 0 :(得分:4)

您只需了解优先级如何与CCTouchDispatcher配合使用。 具有最小优先级值的层将首先接收触摸事件。现在你只需要相应地调整优先级。

创建一个阻塞图层类,并在使用CCTouchDispatcher注册时将其优先级设置为最小值,并覆盖ccTouchBegan并在其中返回YES。

如果您查看CCMenu类,您会发现默认优先级是kCCMenuTouchPriority = -128,这就是菜单项具有更高触摸优先级的原因。

答案 1 :(得分:2)

吞下所有触摸事件的图层需要以比任何基础控件更高的优先级进行注册。通常这些是菜单项,默认优先级为kCCMenuHandlerPriority = -128(最先处理最低值)。

吞咽层然后只是处理它接收的任何触摸,什么也不做。

然后需要在吞咽层之前对弹出窗口上的任何控件进行优先排序,因此如果您使用菜单,则需要设置新的优先级。然后,这些触摸将首先由项目处理(而不是吞咽层)。

相关功能显示注册优先级为-1024的吞咽层,处理(忽略)所有触摸,并添加优先于吞咽层的菜单项:

// Ensure dialog background, which swallows all touches, is prioritised before normal menus (-128)
// Menus displayed on the dialog, then need to be prioritised before that.
#define kDialogSwallowTouchPriority -1024
#define kDialogMenuPriority -1032

- (void) registerWithTouchDispatcher {
    [[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self
        priority:kDialogSwallowTouchPriority swallowsTouches:YES];
}

- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
    // Swallow all touches
    return YES;
}

...

- (void)addCloseMenu
{
    CCSprite *close = [CCSprite spriteWithSpriteFrameName:@"closebutton.png"];
    CCMenuItem *closeMenuItem = [CCMenuItemSprite itemWithNormalSprite:close  
        selectedSprite:nil target:self selector:@selector(closeTapped:)];
    closeMenuItem.anchorPoint = ccp( 1, 1 );
    closeMenuItem.position = ccp( self.dialog.contentSize.width - 10, 
        self.dialog.contentSize.height - 10 );
    self.closeMenu = [CCMenu menuWithItems:closeMenuItem, nil];
    self.closeMenu.anchorPoint = ccp( 1, 1 );
    self.closeMenu.position = CGPointZero;
    // Set the priority above the swallowing layer
    self.closeMenu.touchPriority = kDialogMenuPriority;
    [self.dialog addChild:self.closeMenu];
}

答案 2 :(得分:0)

穷人的做法:添加一个ccmenuitemsprite和ccmenu,ccsprite opacity设置为0,覆盖你不想点击的任何内容。当我不想让触摸调度员弄乱时,对我有用。