Reputation: 285
I'm making a scene in which the lyrics to a song which is played in the background of a scene are displayed line by line at the bottom of a spriteKit scene. I've tried a number of different solutions, but for some reason with each of them some of the lyrics are not being displayed or are out of sync. Im attempting to use an SKLabelNode and using SKActions change the text of it at specific times. There must be an easier way of doing this!?
here's the function I came up with:
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)
}
Upvotes: 1
Views: 303
Reputation: 13665
Yikes! Not the way to go... Imagine what would happen if there is much more lines? You should avoid repeated code as much as possible.
Here is how you can predefine text, delay and refresh label's text based on those data (just copy and paste the code to see how it works):
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")
}
}
Upvotes: 2