我在我的游戏中实现了一个“暂停菜单”。当用户点击屏幕左上角的暂停按钮时,我运行以下代码:
- (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
仍然在此之上,托管不同的对话框:“暂停”、“确认退出”、“确认重启”)。