5

私のcocos2dゲームには、モーダルレイヤーを起動し、その下にあるすべてのものをロックするための[設定]ボタンがあります。これを行うには、すべてのCCMenuItemをロックするメニューステータスメソッドとカバーレイヤーを組み合わせて使用​​します。どちらも以下のコードにあります。

問題は、どちらのソリューションもCCScrollLayersでは機能しないように見えることです。ボタン(モーダルを起動する)をクリックしても、CCScrollLayerをスクロールできますが、これは私が望むものではありません。

そうしたいです:

  1. ボタンを押すと、すべてのタッチが無効になり、CCScrollLayersを含むすべての要素が無効になります
  2. モーダルを起動します(モーダルのみのタッチを許可します)

私はもう試した:

  1. タッチを使用して、CCTargetedTouchDelegate

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

  1. 私はもう試した

self.isTouchEnabled = NOモーダルを起動するレイヤー上

  1. CCScrollLayersで機能するようにメソッドを調整しようとしましMenuStatusたが、機能しないようです。

何が間違っているのかわかりません。私のコードは次のとおりです。

// 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 に答える