1

我在我的游戏中实现了一个“暂停菜单”。当用户点击屏幕左上角的暂停按钮时,我运行以下代码:

- (void) pauseGame
{
    // Blur the game's contents:
    [_effectNode setShouldEnableEffects:YES];

    // Apply cover:
    [_pauseLayer addChild:_pauseCover]; // (_pauseLayer sits just above _effectNode)

    // Start from fully transparent...
    [_pauseCover setAlpha:0.0f]; // Start from fully transparent...

    // ...and animate to near-opaque:
    [_pauseCover runAction:[SKAction fadeAlphaTo:0.85f duration:0.125f]];
}

要取消暂停,我这样做:

- (void) unpauseGame
{
    // Un-blur game contents
    [_effectNode setShouldEnableEffects:NO];

    // Fade cover out
    [_pauseLayer runAction:[SKAction fadeAlphaTo:0.0f
                                        duration:0.125f]
                completion:^(void){
                    // The following lines are executed, but still 
                    // the button below doesn't receive any more touches

                    [_pauseLayer removeAllChildren];// Neither
                    [_pauseCover removeFromParent]  // of these
                    [_pauseLayer setHidden:YES];    // makes a difference

                }];
}

取消暂停后,节点层次结构与之前完全相同(我记录了它)。但是,暂停按钮一旦被_pauseLayer(类型SKNode)及其子_pauseCover项(类型)覆盖,SKSpriteNode就不再接收触摸输入(游戏场景本身会)。

如果我没有移除淡入淡出动作完成块上的封面,而是立即执行,或者使用-performSelector:withObject:afterDelay:,如下所示:

- (void) unpauseGame
{
    // Un-blur game contents:
    [_effectNode setShouldEnableEffects:NO];

    // Fade cover out to fully transparent:
    [_pauseLayer runAction:[SKAction fadeAlphaTo:0.0f
                                        duration:0.125f]];

    [_pauseLayer performSelector:@selector(removeAllChildren) 
                      withObject:nil
                      afterDelay:0.25]; // a bit longer than fade, just in case
}

...然后,恢复后,按钮就像以前一样工作...我知道 SKSpriteNode 实例阻止触摸事件(即使使用setUserInteractionEnabled:NO),但精灵不再存在!令人费解!

注意我必须强调完成块确实被执行(断点停在那里),并在此之后记录删除的子项给出正确的计数(0)。但是,暂停按钮(实现-touches*: withEvent: 方法的精灵子类)不再接收触摸。


解决方案: 我从来没有完全完成我想要的:让一堆“占位符”节点充当层(级别),以固定深度持续存在,然后根据需要向它们添加/删除子节点(在这种情况下,封面精灵/对话框)。我想以这种方式实现它,因为 SKNode 没有-insertChild:aboveChild:orinsertChild:belowChild:方法,并且获取目标索引并插入那里有点容易出错/令人困惑(现有节点在哪个方向被“推送”?)。

尽管如此,我还是妥协了,决定按需添加/删除父层,只是跟踪顺序(先进后出,以保留预期的层顺序)。

说得够多了,我确定的代码是:

#define GameSceneDefaultSingleFadeDuration 0.125f

- (void) pause:(id) sender
{
    [_effectNode setShouldEnableEffects:YES];

    [self addChild:_pauseLayer];
    [_pauseLayer addChild:_pauseCover];
    [_pauseCover setAlpha:0.0f];

    [_pauseCover runAction:[SKAction fadeAlphaTo:0.85
                                        duration:GameSceneDefaultSingleFadeDuration]
                completion:^(void){
                }];

    [self addChild:_dialogLayer];
    [_dialogLayer addChild:_pauseDialog];


    for (Button* button in [_pauseDialog children]) {
        [button setAlpha:0.0f];
        [button runAction:[SKAction fadeAlphaTo:1.0f
                                       duration:GameSceneDefaultSingleFadeDuration]];
    }
}

- (void) resume:(id) sender
{
    // Unblur, fade white cover out and remove

    [_effectNode setShouldEnableEffects:NO];

    [_dialogLayer runAction:[SKAction fadeAlphaTo:0.0f
                                         duration:GameSceneDefaultSingleFadeDuration]
                 completion:^(void){

                     [_dialogLayer removeAllChildren];
                     [_dialogLayer setAlpha:1.0f];
                     [_dialogLayer removeFromParent];
                 }];

    [_pauseCover runAction:[SKAction fadeAlphaTo:0.0f
                                        duration:GameSceneDefaultSingleFadeDuration]
                completion:^(void){

                    [_pauseCover removeFromParent];
                    [_pauseLayer removeFromParent];
                }];
}

_pauseLayer在模糊的游戏内容之上,_dialogLayer仍然在此之上,托管不同的对话框:“暂停”、“确认退出”、“确认重启”)。

4

0 回答 0