Verzögerung zwischen SKAction und SKAudioNode, wenn SKScene angehalten und fortgesetzt wirdIOS

Programmierung für iOS
Guest
 Verzögerung zwischen SKAction und SKAudioNode, wenn SKScene angehalten und fortgesetzt wird

Post by Guest »

Übersicht
In meiner SKScene habe ich einen SKAudioNode, der eine Audiodatei abspielt, die wie folgt deklariert ist:

Code: Select all

   var backgroundMusic: SKAudioNode?
und wie folgt initialisiert:

Code: Select all

    guard let musicURL = Bundle.main.url(forResource: "MY_AUDIO_FILENAME", withExtension: "mp3") else { fatalError() }
backgroundMusic = SKAudioNode(url: musicURL)
backgroundMusic?.isPositional = false
Stellen Sie sich der Einfachheit halber den abgespielten Ton als eine Stimme vor, die laut von 1 bis 1000 zählt:

"eins , break, two, break, three, break, -- [cut]"

Jetzt ist es mein Ziel, < stark> Lassen Sie das Audio abspielen und führen Sie Dinge in meinem Code aus, wenn das Audio einen bestimmten Wert erreicht Teil,, z.B. wenn die Stimme die Zahl 45 zählt.
Um das zu erreichen, habe ich mit SKAction einen Timer wie folgt eingerichtet:

Code: Select all

    let wait = SKAction.wait(forDuration: 48)
let playAlarmSound = SKAction.run {
// perform stuff
}
let timer = SKAction.sequence([wait, playAlarmSound])
Ich füge beide gleichzeitig zur Szene hinzu, sodass theoretisch der Timer ausgelöst wird, wenn der Ton diesen bestimmten Punkt erreicht.

Code: Select all

    run(timer, withKey: "Timer")
addChild(backgroundMusic!)
Probleme
  • Jedes Mal, wenn die SKScene angehalten und dann fortgesetzt wird, wird der SKAudioNode wird einen kleinen Teil des Audios überspringen, im Beispielfall so, als ob eine einzelne Zahl etwa übersprungen würde.
  • Nach jeder Pause und Wiederaufnahme wird der Timer etwas später ausgelöst. Dies wird in dem Beispielprojekt, das ich unten bereitstelle, deutlich: Wenn Sie etwa zehnmal pausieren und fortfahren, wird der Timer bei etwa 50 statt bei 45 ausgelöst.
Lösungsversuche
  • Der SKAudioNode jedes Mal separat angehalten wird, wenn der SKScene angehalten wird, indem gesagt wird backgroundMusic?.run(SKAction.pause()).
    Obwohl dadurch Problem 1. behoben und die Verzögerung von Problem 2. erheblich reduziert wurde, ist es immer noch keine optimale Lösung, da der Timer weiterhin funktioniert nicht mit dem Audio synchronisiert werden.
    Diesmal wird es jedoch nur etwa eine Sekunde früher als vorgesehen ausgelöst, statt mehrere Sekunden später.
  • Verwenden des Timers< /code>. Dies ist KEINE praktikable Lösung, und zwar aus zwei Gründen: 1) Es ignoriert den pausierten-Status eines Knotens, einer Szene oder der Ansicht, wie in mehreren Antworten hier angegeben [Quellen: 1. 2] 2 ) Ich habe es ausprobiert und es führt zu Verzögerungen in meinem Spiel. Aus Erfahrung ist es meiner Meinung nach bei der Verwendung von SpriteKit besser, keine Hybridlösungen auszuprobieren.
Ich habe keine Ahnung, warum diese Verzögerung auftritt. Wenn also jemand etwas Licht ins Dunkel bringen kann, wäre ich dankbar.
Außerdem Ich suche einen konsistente und optimale Lösung für die beschriebenen Probleme. Ich möchte in der Lage sein, Dinge im Code genau zu einer bestimmten Laufzeit des Audios auszuführen (die nicht bei der Fertigstellung liegt).
< h2>Beispielprojekt
Dies ist ein minimalistisches Beispielprojekt, das das hervorhebt Probleme, auf die ich hingewiesen habe. Es sind keine .sks-Dateien erforderlich, einfach kopieren, einfügen und erstellen und ausführen.
Das Projekt startet die Audiodatei und den Timer automatisch, sobald GameScene präsentiert wird. Von dort aus können Sie die Szene anhalten/fortsetzen, indem Sie irgendwo auf den roten Bildschirm tippen, um die Probleme zu reproduzieren. Mit meinen Einstellungen und dem von mir bereitgestellten Audio sollte der Timer ausgelöst werden, wenn der Zähler die Zahl 45 erreicht.
Immer wenn Sie die Szene anhalten/fortsetzen und wenn der Timer ausgelöst wird, druckt die App weiter Konsole.
Beachten Sie, dass ich diese Lösung aus einer anderen Frage verwendet habe, um den pausierten Status konsistent zu halten, wenn die App in den Hintergrund wechselt.
Für dieses Beispiel empfehle ich, diese Audiodatei herunterzuladen und zu verwenden (Dropbox-Link) eines Mannes, der Zahlen zählt, da es die Probleme deutlich macht.

Code: Select all

final class GameViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

let skView = SKView(frame: view.frame)
view = skView
skView.ignoresSiblingOrder = true

let gameScene = GameScene()
skView.presentScene(gameScene)
}
}

import SpriteKit

final class GameScene: SKScene {

var backgroundMusic: SKAudioNode?

var isGamePaused: Bool = false {
didSet {
self.isPaused = isGamePaused

// Uncomment the following lines to test my solution, which is not optimal. After multiple pause/resume, the timer will still not be synchronized with the audio and will fire just around a second earlier than when it is supposed to.

//if isGamePaused {
//   self.backgroundMusic?.run(SKAction.pause())
//} else {
//   self.backgroundMusic?.run(SKAction.play())
//}
}
}
override var isPaused: Bool {
didSet {
if (self.isPaused == false && self.isGamePaused == true) {
self.isPaused = true

// Uncomment the following line to test my solution, which is not optimal. After multiple pause/resume, the timer will still not be synchronized with the audio and will fire just around a second earlier than when it is supposed to.

//self.backgroundMusic?.run(SKAction.pause())
}
}
}

override func didMove(to view: SKView) {
super.didMove(to: view)
view.isMultipleTouchEnabled = false
backgroundColor = .red

startAudioAndTimer()
}

func startAudioAndTimer() {

// ISSUE: On pause&resume, especially after multiple times, the timer gets unsynchronized with the audio and will fire many seconds later than when it is supposed to.

guard let musicURL = Bundle.main.url(forResource: "Test_Song", withExtension: "mp3") else {
fatalError("Error: add a mp3 audio file to the project")
}
backgroundMusic = SKAudioNode(url: musicURL)
backgroundMusic?.isPositional = false

let wait = SKAction.wait(forDuration: 48) // With this value for duration, if you're using the audio file I provided, the alarm should ring at the end of '45' in the song
let playAlarmSound = SKAction.run {
print("\n--- The alarm rings ---\n")
}
let timer = SKAction.sequence([wait, playAlarmSound])

run(timer, withKey: "Timer")
addChild(backgroundMusic!)
}

override func touchesBegan(_ touches: Set, with event: UIEvent?) {
isGamePaused = !isGamePaused
let statusString = isGamePaused ? "paused" : "resumed"
print("\nScene \(statusString)\n")
}

override func touchesMoved(_ touches: Set, with event: UIEvent?) { }

override func touchesEnded(_ touches: Set, with event: UIEvent?) { }

override func touchesCancelled(_ touches: Set, with event: UIEvent?) { }
}

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post