5

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

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

我想:

  1. 按下按钮禁用所有触摸并禁用所有元素,包括 CCScrollLayers
  2. 启动模态(仅允许触摸模态)

我试过了:

  1. 使用 Touch 吞下所有触摸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);
}
4

3 回答 3

4

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

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

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

于 2012-09-17T12:16:52.197 回答
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];
}
于 2013-06-10T07:19:52.747 回答
0

穷人的做法:添加一个 ccmenuitemsprite 和 ccmenu,并将 ccsprite 不透明度设置为 0,覆盖您不想点击的任何内容。当我不想弄乱触摸调度程序时,对我有用。

于 2013-05-07T20:16:50.787 回答