SpriteKit - 在一段随机时间后运行带有两个参数的方法

时间:2014-08-06 14:05:06

标签: objective-c methods sprite-kit skspritenode skaction

在尝试为iOS创建游戏时我遇到了一个问题:我找不到一种方法来调用一个方法来创建一个SpriteKit节点来自另一个类"调用本身"或者以一种简单的方式在一段随机的时间后重复。

这个想法是这样的:我有一个创建场景的类。但后来我有了另一个类(SKSPriteNode的子类),它创建了我需要的不同SKSpriteNode。我有一个名为createObjectWithName的方法:名称位置:带有两个参数(名称和位置)的位置。我需要从我的场景调用这个方法(好到这里),但我还需要在随机的时间段内不断重复这个方法。因此,一旦它被调用一次,它会在一段时间后自行调用,创建更多的SKSPriteNodes。

我尝试过使用performSelector和dispatch_after,但到目前为止我还没有运气。

提前谢谢你。

3 个答案:

答案 0 :(得分:1)

您可以在场景类中存储时间戳属性(让我们将其称为timeElapsedFromLastSpawn并使用0初始化它)。然后,您可以在更新方法中使用此属性:

timeElapsedFromLast += timeElapsedFromLastUpdate;
if (timeElapsedFromLast > 5.0) {
    [self spawnSpriteNode];
    timeElapsedFromLast = 0;
}

这将每5秒产生一个新的精灵。 (你可以轻松随机化)

我还建议产卵方法不在SKSpriteNode实例中但在外部(例如在育儿场景/节点类中),因为SKSpriteNode角色是表示精灵而不是精灵的工厂(除非它创造儿童精灵直接控制)

编辑:

要计算timeElapsedFromLastUpdate,您可以使用以下代码(取自Ray Wenderlich的网站,该网站对此内容有很好的tutorials

- (void)update:(NSTimeInterval)currentTime {
    // Handle time delta.
    // If we drop below 60fps, we still want everything to move the same distance.
    CFTimeInterval timeSinceLast = currentTime - self.lastUpdateTimeInterval;
    self.lastUpdateTimeInterval = currentTime;
    if (timeSinceLast > 1) { // more than a second since last update
        timeSinceLast = 1.0 / 60.0;
        self.lastUpdateTimeInterval = currentTime;
    }

    [self updateWithTimeSinceLastUpdate:timeSinceLast];

}

您应该在场景类中实现updateWithTimeSinceLastUpdate方法,或直接在上面的update方法中使用计算

答案 1 :(得分:1)

除非我遗漏了某些内容,否则我认为您希望使用SKAction来解决此问题。

你可以有一个方法来启动这样的spawner:

-(void)startSpawner:(float)duration range:(float)range
{

    SKAction *delay = [SKAction waitForduration:duration withRange:range];
    SKAction *spawnBlock = [SKAction runBlock:^(void)
                            {

                                NSString *spawnName = @"name";
                                CGPoint *spawnPosition = CGPointMake(someX, someY);
                                SpriteNodeSubclass *node = [SpriteNodeSubclass createObjectWithName:spawnName andPosition:spawnPosition];
                                // do something with that node if you need to.
                            }];

    SKAction *sequence = [SKAction sequence:@[delay, spawnBlock]];
    SKAction *repeat = [SKAction repeatActionForever:sequence];
    [self runAction:repeat];
}

我认为使用SKAction而不是dispatch_after是理想的,因为如果您暂停SpriteKit,SKAction也会暂停。

答案 2 :(得分:0)

如果这是你从场景中调用方法的方式:

[otherClass createObjectWithName:name position:position];

然后,您可以使用GCD在以后的随机时间内安排该呼叫:

dispatch_after(dispatch_time(
    DISPATCH_TIME_NOW, 
    (int64_t)(arc4random_uniform((u_int32_t)(MAX_SECONDS * NSEC_PER_SEC)))), 
    dispatch_get_main_queue(), 
^{
    [otherClass createObjectWithName:name position:position];
});

(假设MAX_SECONDS * NSEC_PER_SEC小到足以用32位数量表示;否则看看用合适的模数运算打桩两个arc4random_uniform调用)

通过__weak安全措施以防止任意延长对象的生命周期,以一种重复的方式使用尾部调用:

- (void)scheduleNextObject
{
    __weak YourClass *weakSelf = self;
    dispatch_after(dispatch_time(
        DISPATCH_TIME_NOW, 
        (int64_t)(arc4random_uniform((u_int32_t)(MAX_SECONDS * NSEC_PER_SEC)))), 
        dispatch_get_main_queue(), 
    ^{
        // weakSelf prevents self itself from being captured, so that self
        // can be deallocated even with this loop ongoing. We'll explicitly 
        // check whether what was self still exists to stick with the idiom,
        // though it's strictly unnecessary
        YourClass *strongSelf = weakSelf;
        if(!strongSelf) return;

        [otherClass createObjectWithName:name position:position];
        [strongSelf scheduleNextObject];
    });
}