Ios 在我恢复一个场景之前,我如何倒计时?

Ios 在我恢复一个场景之前,我如何倒计时?,ios,sprite-kit,Ios,Sprite Kit,我有一个暂停的SKScene。当用户要求这样做时,我希望恢复场景。但是,我想在游戏开始前给用户几秒钟的准备时间。为此,当用户要求恢复游戏时,我希望先从3开始倒计时,然后恢复场景 我目前有一个SKLabel来指示计数。当用户单击resume时,我使用一个NSTimer从3开始倒计时,每秒更新标签的内容,并在计数结束时继续游戏 但是,由于游戏暂停,SKLabel不会每秒更新;它只在游戏恢复后的最后更新一次。我正在寻找解决这个问题的方法。在游戏场景中使用一个通用变量,指示游戏是否暂停,例如isGame

我有一个暂停的
SKScene
。当用户要求这样做时,我希望恢复场景。但是,我想在游戏开始前给用户几秒钟的准备时间。为此,当用户要求恢复游戏时,我希望先从3开始倒计时,然后恢复场景

我目前有一个
SKLabel
来指示计数。当用户单击resume时,我使用一个
NSTimer
从3开始倒计时,每秒更新标签的内容,并在计数结束时继续游戏


但是,由于游戏暂停,
SKLabel
不会每秒更新;它只在游戏恢复后的最后更新一次。我正在寻找解决这个问题的方法。

游戏场景中使用一个通用变量,指示游戏是否暂停,例如
isGamePaused
。在
更新:
方法中,您将拥有:

if(!isGamePaused){
    //Do all game logic
}
您可以使用
isGamePaused
暂停和取消暂停游戏。现在,让我们倒计时。我将创建一个子类
SKNode
,在那里添加
SKLabel
,并设置一个委托,以便我们知道
倒计时何时完成。例如,在
倒计时.h
中:

@protocol SKCountDownDelegate <NSObject>

-(void)countDown:(id)countDown didFinishCounting:(BOOL) didFinishCounting;

@end

@interface SKCountDown : SKNode

@property (assign, atomic) id<SKCountDownDelegate> delegate;

-(instancetype)initCountDownWithSeconds:(int)seconds andColor:(UIColor *) color andFontName:(NSString *)fontName;

@end
因此,无论您想在何处添加此
倒计时
,都可以执行以下操作:

-(void)startCountDown{
    self.countDown = [[SKCountDown alloc] initCountDownWithSeconds:3 andColor:self.countdownFontColor andFontName:self.countdownFontName];
    self.countDown.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
    self.countDown.delegate = self;
    self.countDown.zPosition = 20;
    [self addChild:self.countDown];
}

-(void)countDown:(id)countDown didFinishCounting:(BOOL)didFinishCounting{
    isGamePaused = NO;
}

这是一个这样做的例子。希望有帮助

在游戏过程中暂停整个场景对我来说似乎有点太直截了当了,因为您通常希望更新节点层次结构中的某些内容

一个简单的解决方案是区分游戏节点和UI节点。您只需将两个节点(
game
ui
)添加到场景中,并在场景调用
[self addChild]
时选择要将它们添加到的节点。 稍后,您可以暂停
游戏
节点,仍然可以更新UI

SKScene
   - SKNode "game" // <-- pause this one
       - SKSpriteNode "goodGuy"
       - SKSpriteNode "badGuy"
       - SKSpriteNode "mehGuy"
       - ...
   - SKNode "ui"
       - SKLabelNode "countdownLabel"
       - SKSpriteNode "resumeButton"
       - SKSpriteNode "pauseButton"
       - ...
SKScene

-SKNode“game”/我更喜欢简单地暂停更新方法的各个部分,而不是暂停整个场景。创建布尔属性:

@property (nonatomic) BOOL runUpdateMethod;
构建更新方法以确定哪些部分暂停:

-(void)update {

    if(runUpdateMethod) {

        // code to be paused
    }

    // code not to be paused
}
您可以使用SKAction块运行倒计时并恢复定期更新:

-(void)countdown {

    __block SKLabelNode *labelNode0;

    SKAction *wait0 = [SKAction waitForDuration:1.0];

    SKAction *block0 = [SKAction runBlock:^{

        labelNode0 = [SKLabelNode labelNodeWithFontNamed:@"Arial"];
        labelNode0.text = @"5";
        labelNode0.fontSize = 100;
        labelNode0.fontColor = [SKColor redColor];
        labelNode0.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeCenter;
        labelNode0.verticalAlignmentMode = SKLabelVerticalAlignmentModeCenter;
        labelNode0.position = CGPointMake(self.screenWidth/2, self.screenHeight/2);
        labelNode0.zPosition = 955;
        labelNode0.alpha = 0.4;
        [self addChild:labelNode0];
    }];

    SKAction *block1 = [SKAction runBlock:^{
        labelNode0.text = @"4";
    }];

    SKAction *block2 = [SKAction runBlock:^{
        labelNode0.text = @"3";
    }];

    SKAction *block3 = [SKAction runBlock:^{
        labelNode0.text = @"2";
    }];

    SKAction *block4 = [SKAction runBlock:^{
        labelNode0.text = @"1";
    }];

    SKAction *block5 = [SKAction runBlock:^{
        [labelNode0 removeFromParent];
        self.runUpdateMethod = YES;
    }];

    [self runAction:[SKAction sequence:@[block0, wait0, block1, wait0, block2, wait0, block3, wait0, block4, wait0, block5]]];
}

我没有暂停游戏,而是将
SKScene
speed
属性设置为0,同时将
SKPhysicsWorld
speed
属性设置为0。如果游戏没有暂停,我还必须稍微修改我的
update
功能,只执行代码的某些部分


这产生了与暂停整个游戏相同的效果,同时也允许我更新标签的内容。

关于将NSTimer与SpriteKit@Whirlwind一起使用时可能出现的问题,在这种情况下这不是问题;这就是我使用
NSTimer
而不是
SKAction
的原因。我需要一种方法来忽略游戏的暂停状态。我只是说“可能”,让你意识到随之而来的问题。通常将NSTimer与SpriteKit一起使用是一个坏主意。搜索以便了解原因(NSTimer也与内存泄漏有关)。无论如何,要做到这一点,你可以取消暂停的场景,并延迟游戏开始使用SKAction与完成块(或只是使用序列)。。。在该完成块中,更改某些自定义变量的值(建议使用isGamePaused)并在倒计时结束时启动游戏。此外,正确地使计时器无效将避免潜在的泄漏,但SKActions仍然更安全。
-(void)countdown {

    __block SKLabelNode *labelNode0;

    SKAction *wait0 = [SKAction waitForDuration:1.0];

    SKAction *block0 = [SKAction runBlock:^{

        labelNode0 = [SKLabelNode labelNodeWithFontNamed:@"Arial"];
        labelNode0.text = @"5";
        labelNode0.fontSize = 100;
        labelNode0.fontColor = [SKColor redColor];
        labelNode0.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeCenter;
        labelNode0.verticalAlignmentMode = SKLabelVerticalAlignmentModeCenter;
        labelNode0.position = CGPointMake(self.screenWidth/2, self.screenHeight/2);
        labelNode0.zPosition = 955;
        labelNode0.alpha = 0.4;
        [self addChild:labelNode0];
    }];

    SKAction *block1 = [SKAction runBlock:^{
        labelNode0.text = @"4";
    }];

    SKAction *block2 = [SKAction runBlock:^{
        labelNode0.text = @"3";
    }];

    SKAction *block3 = [SKAction runBlock:^{
        labelNode0.text = @"2";
    }];

    SKAction *block4 = [SKAction runBlock:^{
        labelNode0.text = @"1";
    }];

    SKAction *block5 = [SKAction runBlock:^{
        [labelNode0 removeFromParent];
        self.runUpdateMethod = YES;
    }];

    [self runAction:[SKAction sequence:@[block0, wait0, block1, wait0, block2, wait0, block3, wait0, block4, wait0, block5]]];
}