为什么waitForDuration:方法只能在sprite kit的update方法中运行一次?

时间:2016-02-22 17:17:53

标签: ios objective-c sprite-kit

这里在我的代码中我试图更新标签(SKSpriteNode),而时间倒计时使用精灵工具包,但我不想使用NSTimer,所以我找到了这个解决方案,但问题是waitForDuration方法只工作第一次更新方法运行。我想使用精灵工具包每秒运行一段代码(更新标签和变量)。任何帮助表示赞赏。

priority

2 个答案:

答案 0 :(得分:2)

我使用类似的技术来扼杀火灾率之类的东西,它适用于支持帧更新的任何游戏引擎,您可以在其中获得增量时间(即此帧与最后一帧之间的时间) )。这几乎是我见过的所有游戏引擎除了 SpriteKit,它给你当前时间(我认为这是游戏开始以来的时间,但没关系),所以你需要计算delta时间自己。

你需要使用一个实例变量来保存当前的计时器值,并从那个时间开始递减 delta time ,当它是<= 0.0时,就可以开始它了。如果你想重复它,那么重置倒计时。

例如:

#define TIMER_VALUE 1.0

@interface MyClass()
{
    CFTimeInterval _lastFrameTime;
    CFTimeInterval _timer;
}
@end

@implementation MyClass()

- (instancetype)init
{
    self = [super init];
    if (self) {
        _lastFrameTime = 0.0;
        _timer = TIMER_VALUE;
    }
    return self;
}

-(void)update:(CFTimeInterval)currentTime
{
    if (_lastFrameTime == 0.0)           // Might need < DBL_EPSILON here?
        _lastFrameTime = currentTime;    // First frame
    CFTimeInterval deltaTime = currentTime - _lastFrameTime;

    _timer -= deltaTime;
    if (_timer <= 0.0) {
        [self doThing];
        _timer = TIMER_VALUE;
    }

    _lastFrameTime = currentTime;
}
@end

答案 1 :(得分:1)

使用SKActions可以做到这一点:

#import "GameScene.h"

@interface GameScene ()

@property (nonatomic, strong) SKLabelNode *label;
@property (nonatomic, assign) NSUInteger timeLeft;
@end

@implementation GameScene

-(instancetype)initWithCoder:(NSCoder *)aDecoder{

    if (self = [super initWithCoder:aDecoder]) {

        _timeLeft = 90;
        _label = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
    }

    return self;
}

//Override timeLeft's setter in order to update label's text property after each assignment to property is made.
-(void)setTimeLeft:(NSUInteger)timeLeft {

    _timeLeft = timeLeft;
    _label.text = [NSString stringWithFormat:@"Current score %lu", (unsigned long)_timeLeft];

}


-(void)didMoveToView:(SKView *)view {

    //How much to wait
    SKAction *wait = [SKAction waitForDuration:1];

    __weak typeof(self) weakSelf =  self;

    //What to do
    SKAction *block = [SKAction runBlock:^{
        weakSelf.timeLeft -= 1;
    }];

    //Sequence to repeat - look at this like it represents one step (wait and update what needed)
    SKAction *sequence = [SKAction sequence:@[wait, block]];

    self.label.text = [NSString stringWithFormat:@"Current score %lu", (unsigned long)self.timeLeft];
    self.label.fontSize = 45;
    self.label.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
    [self addChild:self.label];

    //Repeat the step above forever
    [self runAction:[SKAction repeatActionForever:sequence] withKey:@"countdown"];


}

@end

代码非常直接(并且已经评论很多),但让我再次解释它是如何工作的:

  • 一次创建一个动作序列,并多次重复使用。
  • 在块的内部,它是该序列的一部分,您更新timeLeft变量。这会自动(通过重写的setter)更新标签的文本。
  • 序列永远重复。

要停止此操作,您可以通过密钥访问它,然后将其删除,如下所示:

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

    if ([self actionForKey:@"countdown"]){
        [self removeActionForKey:@"countdown"];
    }

}