Reputation: 6278
When an AVSpeechUtterance
is speaking, I want to wait until it's finished before doing something else.
There is a property of AVSpeechSynthesizer
that's seemingly indicative of when speech is occuring:
As stupid and simple as this question might sound, I'm wondering how do I use/check this property to wait until speech has concluded before going on?
ALTERNATIVELY:
There's a delegate, that I'm also clueless as to how to use, which has an ability to do something when an utterance has finished:
There's an answer, here, that says to use this. But that doesn't help me because I don't know how to use a Delegate.
This is how I setup my speaking class:
import AVFoundation
class CanSpeak: NSObject, AVSpeechSynthesizerDelegate {
let voices = AVSpeechSynthesisVoice.speechVoices()
let voiceSynth = AVSpeechSynthesizer()
var voiceToUse: AVSpeechSynthesisVoice?
override init(){
voiceToUse = AVSpeechSynthesisVoice.speechVoices().filter({ $0.name == "Karen" }).first
}
func sayThis(_ phrase: String){
let utterance = AVSpeechUtterance(string: phrase)
utterance.voice = voiceToUse
utterance.rate = 0.5
voiceSynth.speak(utterance)
}
}
using the above mentioned isSpeaking
property, in the gameScene:
voice.sayThis(targetsToSay)
let initialPause = SKAction.wait(forDuration: 1.0)
let holdWhileSpeaking = SKAction.run {
while self.voice.voiceSynth.isSpeaking {print("STILL SPEAKING!")}
}
let pauseAfterSpeaking = SKAction.wait(forDuration: 0.5)
let doneSpeaking = SKAction.run {print("TIME TO GET ON WITH IT!!!")}
run(SKAction.sequence(
[ initialPause,
holdWhileSpeaking,
pauseAfterSpeaking,
doneSpeaking
]))
Upvotes: 0
Views: 3938
Reputation: 1413
Delegate pattern is one of the most common used design pattern in object-oriented programming, it's not as hard as it seems. For your case, you can simply let your class (a game scene) to be a delegate of the CanSpeak class.
protocol CanSpeakDelegate {
func speechDidFinish()
}
Next set AVSpeechSynthesizerDelegate to your CanSpeak class, declare CanSpeakDelegate and then use AVSpeechSynthesizerDelegate delegate function.
class CanSpeak: NSObject, AVSpeechSynthesizerDelegate {
let voices = AVSpeechSynthesisVoice.speechVoices()
let voiceSynth = AVSpeechSynthesizer()
var voiceToUse: AVSpeechSynthesisVoice?
var delegate: CanSpeakDelegate!
override init(){
voiceToUse = AVSpeechSynthesisVoice.speechVoices().filter({ $0.name == "Karen" }).first
self.voiceSynth.delegate = self
}
func sayThis(_ phrase: String){
let utterance = AVSpeechUtterance(string: phrase)
utterance.voice = voiceToUse
utterance.rate = 0.5
voiceSynth.speak(utterance)
}
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
self.delegate.speechDidFinish()
}
}
Lastly in your game scene class, simply conform to CanSpeakDelegate and set it as the delegate of your CanSpeak class.
class GameScene: NSObject, CanSpeakDelegate {
let canSpeak = CanSpeak()
override init() {
self.canSpeak.delegate = self
}
// This function will be called every time a speech finishes
func speechDidFinish() {
// Do something
}
}
Upvotes: 8
Reputation: 669
Sets up delegate to your AVSpeechSynthesizer instance.
voiceSynth.delegate = self
Then, implements didFinish
method as below:
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer,
didFinish utterance: AVSpeechUtterance) {
// Implements here.
}
Upvotes: 3
Reputation: 1658
Try AVSpeechSynthesizerDelegate
with method:
- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didFinishSpeechUtterance:(AVSpeechUtterance *)utterance;
Upvotes: 0