I have SKActions defined in my class, eg:
let CSound = SKAction.playSoundFileNamed("C3.mp3", waitForCompletion: false)
let DSound = SKAction.playSoundFileNamed("D3.mp3", waitForCompletion: false)
I want to be able to call a function to play sounds, and I want to adjust the name dynamically, like this:
func playSound(noteName: String) {
print(noteName) // "C"
var name = noteName "Sound"
print(name) // "CSound"
run(SKAction(named: name)!)
}
This causes a fatal error on the run(SKAction(named: name)!)
line:
Fatal error: Unexpectedly found nil while unwrapping an Optional value
Why is this? How is it nil? The variable name
has the value CSound
, and an SKAction does exist with that name. How can I use a dynamic name like this?
CodePudding user response:
You can store the sounds in a dictionary:
let sounds = [
"C": SKAction.playSoundFileNamed("C3.mp3", waitForCompletion: false),
"D": SKAction.playSoundFileNamed("D3.mp3", waitForCompletion: false),
]
let sounds = Dictionary(uniqueKeysWithValues:
["C", "D"]
.map { ($0, SKAction.playSoundFileNamed("\($0)3.mp3", waitForCompletion: false)) }
)
If there are many sounds and you don't want to repeat playSoundFileNamed
too many times, you can do a map
:
let sounds = Dictionary(uniqueKeysWithValues:
["A", "B", "C", "D", "E", "F", "G"]
.map { ($0, SKAction.playSoundFileNamed("\($0)3.mp3", waitForCompletion: false)) }
)
Then you can access it like this:
func playSound(noteName: String) {
if let action = sounds[noteName] {
run(action)
} else {
// there is no sound with the given name...
}
}
The SKAction(named:)
creates an SKAction
from a .sks file in your app's bundle. You can add such a file in Xcode by doing File -> New -> File... -> SpriteKit Action. You pass in the file name as the parameter, and it creates the action encoded in the file.