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];
}
}
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])))
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])))
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])))
}
Voici le code complet pour construire une minuterie pour SpriteKit avec Xcode 9.3 et Swift 4.1
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!
Tout d'abord, nous avons besoin d'une étiquette
class GameScene: SKScene {
private let label = SKLabelNode(text: "Score: 0")
}
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.
Veuillez noter qu'à ce stade, l'étiquette n'est pas mise à jour!
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
}
}
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)
}
}