web-dev-qa-db-fra.com

SpriteKit - Création d'une minuterie

Comment puis-je créer une minuterie qui se déclenche toutes les deux secondes qui augmentera le score de un sur un HUD que j'ai sur mon écran? Voici le code que j'ai pour le HUD:

    @implementation MyScene
{
    int counter;
    BOOL updateLabel;
    SKLabelNode *counterLabel;
}

-(id)initWithSize:(CGSize)size
{
    if (self = [super initWithSize:size])
    {
        counter = 0;

        updateLabel = false;

        counterLabel = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
        counterLabel.name = @"myCounterLabel";
        counterLabel.text = @"0";
        counterLabel.fontSize = 20;
        counterLabel.fontColor = [SKColor yellowColor];
        counterLabel.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeCenter;
        counterLabel.verticalAlignmentMode = SKLabelVerticalAlignmentModeBottom;
        counterLabel.position = CGPointMake(50,50); // change x,y to location you want
        counterLabel.zPosition = 900;
        [self addChild: counterLabel];
    }
}
29
user3578149

Dans Sprite Kit n'utilisez pas NSTimer, performSelector:afterDelay: ou Grand Central Dispatch (GCD, c'est-à-dire tout dispatch_...) car ces méthodes de temporisation ignorent l'état paused d'un nœud, d'une scène ou de la vue. De plus, vous ne savez pas à quel moment de la boucle de jeu ils sont exécutés, ce qui peut entraîner divers problèmes en fonction de ce que fait réellement votre code.

Les deux seules façons autorisées d'exécuter quelque chose en fonction du temps dans Sprite Kit sont d'utiliser soit le SKScene update: et en utilisant le paramètre currentTime transmis pour garder le temps.

Ou plus généralement, vous utiliseriez simplement une séquence d'actions qui commence par une action d'attente:

id wait = [SKAction waitForDuration:2.5];
id run = [SKAction runBlock:^{
    // your code here ...
}];
[node runAction:[SKAction sequence:@[wait, run]]];

Et pour exécuter le code à plusieurs reprises:

[node runAction:[SKAction repeatActionForever:[SKAction sequence:@[wait, run]]]];

Vous pouvez également utiliser performSelector:onTarget: au lieu de runBlock: ou peut-être utiliser un customActionWithDuration:actionBlock: si vous devez imiter le SKScene update: et je ne sais pas comment la transférer vers le nœud ou où le transfert serait gênant.

Voir référence SKAction pour plus de détails.


MISE À JOUR: Exemples de code utilisant Swift

Swift 5

 run(SKAction.repeatForever(SKAction.sequence([
     SKAction.run( /*code block or a func name to call*/ ),
     SKAction.wait(forDuration: 2.5)
     ])))

Swift 3

let wait = SKAction.wait(forDuration:2.5)
let action = SKAction.run {
    // your code here ...
}
run(SKAction.sequence([wait,action]))

Swift 2

let wait = SKAction.waitForDuration(2.5)
let run = SKAction.runBlock {
    // your code here ...
}
runAction(SKAction.sequence([wait, run]))

Et pour exécuter le code à plusieurs reprises:

runAction(SKAction.repeatActionForever(SKAction.sequence([wait, run])))
60
LearnCocos2D

Dans Swift utilisable:

var timescore = Int()  
var actionwait = SKAction.waitForDuration(0.5)
            var timesecond = Int()
            var actionrun = SKAction.runBlock({
                    timescore++
                    timesecond++
                    if timesecond == 60 {timesecond = 0}
                    scoreLabel.text = "Score Time: \(timescore/60):\(timesecond)"
                })
            scoreLabel.runAction(SKAction.repeatActionForever(SKAction.sequence([actionwait,actionrun])))
5
user1671097

J'ai pris l'exemple Swift ci-dessus et ajouté des zéros au début de l'horloge.

    func updateClock() {
    var leadingZero = ""
    var leadingZeroMin = ""
    var timeMin = Int()
    var actionwait = SKAction.waitForDuration(1.0)
    var timesecond = Int()
    var actionrun = SKAction.runBlock({
        timeMin++
        timesecond++
        if timesecond == 60 {timesecond = 0}
        if timeMin  / 60 <= 9 { leadingZeroMin = "0" } else { leadingZeroMin = "" }
        if timesecond <= 9 { leadingZero = "0" } else { leadingZero = "" }

        self.flyTimeText.text = "Flight Time [ \(leadingZeroMin)\(timeMin/60) : \(leadingZero)\(timesecond) ]"
    })
    self.flyTimeText.runAction(SKAction.repeatActionForever(SKAction.sequence([actionwait,actionrun])))
}
5
Adam

Voici le code complet pour construire une minuterie pour SpriteKit avec Xcode 9.3 et Swift 4.1

enter image description here

Dans notre exemple, l'étiquette de score sera incrémentée de 1 toutes les 2 secondes. Voici le résultat final

Bon, commençons!

1) L'étiquette de score

Tout d'abord, nous avons besoin d'une étiquette

class GameScene: SKScene {
    private let label = SKLabelNode(text: "Score: 0")
}

2) L'étiquette de partition entre en scène

class GameScene: SKScene {

    private let label = SKLabelNode(text: "Score: 0")

    override func didMove(to view: SKView) {
        self.label.fontSize = 60
        self.addChild(label)
    }
}

Maintenant, l'étiquette est au centre de l'écran. Exécutons le projet pour le voir.

enter image description here

Veuillez noter qu'à ce stade, l'étiquette n'est pas mise à jour!

3) Un compteur

Nous voulons également créer une propriété de compteur qui contiendra la valeur actuelle affichée par l'étiquette. Nous voulons également que l'étiquette soit mise à jour dès que la propriété du compteur est modifiée, alors ...

class GameScene: SKScene {

    private let label = SKLabelNode(text: "Score: 0")
    private var counter = 0 {
        didSet {
            self.label.text = "Score: \(self.counter)"
        }
    }

    override func didMove(to view: SKView) {
        self.label.fontSize = 60
        self.addChild(label)

        // let's test it!
        self.counter = 123
    }
}

enter image description here

4) Les actions

Enfin, nous voulons construire une action qui toutes les 2 secondes incrémentera le compteur

class GameScene: SKScene {

    private let label = SKLabelNode(text: "Score: 0")
    private var counter = 0 {
        didSet {
            self.label.text = "Score: \(self.counter)"
        }
    }

    override func didMove(to view: SKView) {
        self.label.fontSize = 60
        self.addChild(label)
        // 1 wait action
        let wait2Seconds = SKAction.wait(forDuration: 2)
        // 2 increment action
        let incrementCounter = SKAction.run { [weak self] in
            self?.counter += 1
        }
        // 3. wait + increment
        let sequence = SKAction.sequence([wait2Seconds, incrementCounter])
        // 4. (wait + increment) forever
        let repeatForever = SKAction.repeatForever(sequence)

        // run it!
        self.run(repeatForever)
    }
}
1
Luca Angeletti