如何停止下在cocos2d一个模式层所有CCTouch?(How to stop all CCTou

2019-09-22 12:07发布

在我的cocos2d游戏我有一个“设置”按钮,启动一个模态层,其目的是根据它来锁定一切。 要做到这一点,我使用的锁定所有CCMenuItems菜单状态相结合的方法,我用一个覆盖层; 这两者都是在下面的代码。

问题是,无论是解决方案似乎对CCScrollLayers工作。 当我点击按钮(启动模式)的CCScrollLayer仍然可以滚动这不是我想要的。

我想:

  1. 按禁用所有触摸一个按钮,并禁止包括CCScrollLayers所有元素
  2. 启动模式(允许模式只接触)

我试过了:

  1. 使用触摸使用吞下所有触摸CCTargetedTouchDelegate

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

  1. 我试过了

self.isTouchEnabled = NO启动模态在该层上

  1. 我试着适应MenuStatus方法,使其适用于CCScrollLayers但它似乎并没有工作。

我不知道我在做什么错。 现在我的代码如下。

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

Answer 1:

你只需要了解的优先级如何与CCTouchDispatcher。 其中有最低优先级值层将首先接收触摸事件。 现在你只需要相应地调整优先级。

创建一个阻挡层类,并与CCTouchDispatcher注册时,其优先级设置为最低,并覆盖ccTouchBegan,只是在它返回YES。

如果你看看在CCMenu类,你会发现默认的优先级是kCCMenuTouchPriority = -128,这是菜单项具有较高的优先级接触的原因。



Answer 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];
}


Answer 3:

这样做的差芒方式:添加ccmenuitemsprite和ccmenu与ccsprite不透明度设置为0覆盖任何你不想点击。 对我的作品时,我只是不想让凌乱与触摸调度。



文章来源: How to stop all CCTouch under a modal layer in cocos2d?