SKLabelNode 在指定时间显示文本

SKLabelNode display text at specified time

我正在制作一个场景,其中在 spriteKit 场景的底部逐行显示在场景背景中播放的歌曲的歌词。我尝试了多种不同的解决方案,但出于某种原因,每种解决方案中的一些歌词都没有显示或不同步。我试图使用 SKLabelNode 并使用 SKActions 在特定时间更改它的文本。必须有更简单的方法来做到这一点!?

这是我想出的函数:

import SpriteKit

let lyrics = SKLabelNode(fontNamed: "avenirnext")

func lyricSectionCreate(lnOneTxt: String, lnOneTime: Double, lnTwoTxt: String, lnTwoTime: Double, lnThreeTxt: String, lnThreeTime: Double, lnFourTxt: String, lnFourTime: Double, lnFiveTxt: String, lnFiveTime: Double, lnSixTxt: String, lnSixTime: Double, lnSevenTxt: String, lnSevenTime: Double, lnEightTxt: String, lnEightTime: Double, lnNineTxt: String, lnNineTime: Double, lnTenTxt: String, lnTenTime: Double){

lyrics.position = CGPoint(x:250, y: 25)
lyrics.zPosition = 5

//line one
let lnOne = SKAction.runBlock { () -> Void in
    lyrics.text = lnOneTxt
}

runAfterDelay(lnOneTime){
    lyrics.runAction(lnOne)
}

//line two
let lnTwo = SKAction.runBlock { () -> Void in
    lyrics.text = lnTwoTxt
}

runAfterDelay(lnTwoTime){
    lyrics.runAction(lnTwo)
}

//line three
let lnThree = SKAction.runBlock { () -> Void in
    lyrics.text = lnThreeTxt
}

runAfterDelay(lnThreeTime){
    lyrics.runAction(lnThree)
}

//line four
let lnFour = SKAction.runBlock { () -> Void in
    lyrics.text = lnFourTxt
}

runAfterDelay(lnFourTime){
    lyrics.runAction(lnFour)
}

//line five
let lnFive = SKAction.runBlock { () -> Void in
    lyrics.text = lnFiveTxt
}

runAfterDelay(lnFiveTime){
    lyrics.runAction(lnFive)
}

//line six
let lnSix = SKAction.runBlock { () -> Void in
    lyrics.text = lnSixTxt
}

runAfterDelay(lnSixTime){
    lyrics.runAction(lnSix)
}

//line seven
let lnSeven = SKAction.runBlock { () -> Void in
    lyrics.text = lnSevenTxt
}

runAfterDelay(lnSevenTime){
    lyrics.runAction(lnSeven)
}

//line eight
let lnEight = SKAction.runBlock { () -> Void in
    lyrics.text = lnEightTxt
}

runAfterDelay(lnEightTime){
    lyrics.runAction(lnEight)
}

//line nine
let lnNine = SKAction.runBlock { () -> Void in
    lyrics.text = lnNineTxt
}

runAfterDelay(lnNineTime){
    lyrics.runAction(lnNine)
}

//line ten
let lnTen = SKAction.runBlock { () -> Void in
    lyrics.text = lnTenTxt
}

runAfterDelay(lnTenTime){
    lyrics.runAction(lnTen)
}

}

func runAfterDelay(delay: NSTimeInterval, block: dispatch_block_t) {
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay *   Double(NSEC_PER_SEC)))
dispatch_after(time, dispatch_get_main_queue(), block)
}

哎呀!不是要走的路......想象一下如果有更多的行会发生什么?尽量避免重复代码。

以下是您可以根据这些数据预定义文本、延迟和刷新标签文本的方法(只需复制并粘贴代码以查看其工作原理):

import SpriteKit

class GameScene: SKScene {

let lyricsLabel = SKLabelNode(fontNamed: "ArialMT")

/*
    Create an array of tuples (text,delay). You could go with struct as well.
*/

let lines:[(text:String, delay:NSTimeInterval)] = [

    ("Line 1" ,3.05),
    ("Line 2" ,1.05),
    ("Line 3" ,1.42),
    ("Line 4" ,0.87),
    ("Line 5" ,1.21),
    ("Line 6" ,0.12),
    ("Line 7" ,1.23),
    ("Line 8" ,1.23),
    ("Line 9" ,0.52),
    ("Line 10",2.12)
]

var currentLine = 0

override func didMoveToView(view: SKView) {

    lyricsLabel.position = CGPoint(x:CGRectGetMidX(frame), y:CGRectGetMinY(frame) + 100)
    addChild(lyricsLabel)

    recursive()
}

/*
What is happening here is:

1. method recursive() is called
2. execution continues if there is more lines
3. label's text is updated (and currentLine is updated as well)
4. now we wait for a predefined duration, and recursive() is called again within itself, which means we jump to step 1 again, then go to step 2 etc...
*/

func recursive(){

    guard currentLine < lines.count
    else {

        if actionForKey("aKey") != nil {
            removeActionForKey("aKey")   
        }
        return
    }

    lyricsLabel.text = lines[currentLine].text

    let wait            = SKAction.waitForDuration(lines[currentLine].delay)
    let block           = SKAction.runBlock({[unowned self] in

        self.currentLine++
        self.recursive()
    })
    let sequence        = SKAction.sequence([wait, block])
    let action          = SKAction.repeatActionForever(sequence)

    self.runAction(action, withKey: "aKey")
    }

}