燕子接触,除非触摸我当前图层的孩子

时间:2012-03-27 23:34:02

标签: iphone objective-c ios cocos2d-iphone

我正在使用CCLayer编写暂停菜单。我需要图层吞下触摸,这样你就不能按下面的图层,但是我还需要能够使用暂停图层本身的按钮。

我可以让图层吞下触摸,但菜单也不起作用。

这是我的代码:

pauseLayer.m

#import "PauseLayer.h"

@implementation PauseLayer

@synthesize delegate;

+ (id) layerWithColor:(ccColor4B)color delegate:(id)_delegate
{
    return [[[self alloc] initWithColor:color delegate:_delegate] autorelease];
}

- (id) initWithColor:(ccColor4B)c delegate:(id)_delegate {
    self = [super initWithColor:c];
    if (self != nil) {

        NSLog(@"Init");
        self.isTouchEnabled = YES;
        CGSize wins = [[CCDirector sharedDirector] winSize];

         delegate = _delegate;
         [self pauseDelegate];

        CCSprite * background = [CCSprite spriteWithFile:@"pause_background.png"];

        [self addChild:background];

        CCMenuItemImage *resume = [CCMenuItemImage itemFromNormalImage:@"back_normal.png"
                                                         selectedImage:@"back_clicked.png"
                                                                target:self
                                                              selector:@selector(doResume:)];
        resume.tag = 10;
        CCMenu * menu = [CCMenu menuWithItems:resume,nil];

        [menu setPosition:ccp(0,0)];

        [resume setPosition:ccp([background boundingBox].size.width/2,[background boundingBox].size.height/2)];

        [background addChild:menu];

        [background setPosition:ccp(wins.width/2,wins.height/2)];

    }
    return self;
}

-(void)pauseDelegate
{
    NSLog(@"pause delegate");
    if([delegate respondsToSelector:@selector(pauseLayerDidPause)])
        [delegate pauseLayerDidPause];
}

-(void)doResume: (id)sender
{
    if([delegate respondsToSelector:@selector(pauseLayerDidUnpause)])
        [delegate pauseLayerDidUnpause];
    [self.parent removeChild:self cleanup:YES];
}

- (void)onEnter {
    [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:INT_MIN+1 swallowsTouches:YES];
    [super onEnter];
}

- (void)onExit {
    [[CCTouchDispatcher sharedDispatcher] removeDelegate:self];
    [super onExit];
}
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
    return YES;
}

-(void)dealloc
{
    [super dealloc];
}

@end

3 个答案:

答案 0 :(得分:3)

为什么不禁用游戏层上的触摸? 就像在onEnter方法中一样,禁用游戏层上的触摸......并且onExit重新启用它们

类似

-onEnter{
gameLayer.isTouchEnabled=NO;
....
}
-onExit{
gameLater.isTouchEnabled=YES;
...
}

你也不需要CCTouchDispatcher

答案 1 :(得分:1)

根据你的代码,问题是模态层即使是为自己的孩子吞咽事件也是如此。

要解决此问题,您必须将子项的触摸优先级设置为甚至高于模式层本身。 换句话说,将菜单的触摸优先级值设置为模态图层的下方。

有两种解决方案。

  1. 只需覆盖“CCMenu :: registerWithTouchDispatcher()”方法,并从头开始设置更高的优先级。
  2. 使用touchDispatcher的“setPriority”方法或菜单本身的“setHandlerPriority”更改菜单的触控优先级。
  3. 要实现第二种解决方案,您必须注意时间。 “CCMenu :: registerWithTouchDispatcher()”在“onEnter”和“onEnterTransitionDidFinish”之后的某个地方被调用。

    所以,使用“scheduleOnce”或类似的东西。

    示例代码。

    - (id) initWithColor:(ccColor4B)c delegate:(id)_delegate {
       self = [super initWithColor:c];
       if (self != nil) {
             //your codes......   put CCMenu in instance
    
             [self scheduleOnce:@selector(setMenuPriority:) delay:0];
       }
       return self;
    }
    
    - (void) setMenuPriority (ccTime)dt {
       [[[CCDirector sharedDirector] touchDispatcher] setPriority:INT_MIN forDelegate:menu];
       //priority "INT_MIN" because you set the layer's priority to "INT_MIN+1".
    }
    
    PS:我的英语不太好,所以如果句子松散,校正会非常高兴:)

答案 2 :(得分:1)

问题是,在传播触摸时,层/节点层次结构。 触摸从最小priority值的触摸处理程序传递到最高值。

一旦响应者吞下了触摸,触摸就不再转发了。

您可以使用类似于CCMenu的方法。 CCMenu处理所有触摸,并根据这些项目的位置检测已选择的CCMenuItem

如果您以相同的方式实现此功能,则让PauseLayer处理并吞下所有触摸并使用单独的机制来确定您PauseLayer中的哪个子元素已被选中。

示例实现:CCMenu子类

我在此存储库中实现了一个解决方案: https://github.com/Ben-G/MGWU-Widgets/tree/master/Projectfiles/Components/CCMenuBlocking

该组件是CCMenu子类,它吞下所有触摸并且不转发它们。

示例实现:CCNode

这是一个更为一般的CCNode解决方案,它吞下了触摸并只将它们转发给自己的孩子:

https://github.com/Ben-G/MGWU-Widgets/blob/master/Projectfiles/Components/Popup/PopUp.m