Я назначаю звук сцене в Reality Composer, как показано на изображении ниже.

Я хотел бы создать UIButton, который можно нажать, чтобы остановить звук. Могу ли я сделать это?





Я создал три действия Reality Composer для бокс-сцены: Play Sound, Spin и Notify. Как видите, циклическое воспроизведение включено.
Мой код такой же простой. Основные методы stop() предназначены для немедленной остановки звука и анимации. Вторичные методы stop() являются содержимым обработчика завершения для свойства onAction.
import SwiftUI
import RealityKit
struct ContentView : View {
@State var completion: ((Entity?) -> ()) = { _ in }
@State var arView = ARView(frame: .zero)
@State var boxScene = try! Experience.loadBox()
var body: some View {
ZStack {
ARViewContainer(arView: $arView, boxScene: $boxScene)
.ignoresSafeArea()
VStack {
Button("Stop") {
boxScene.steelBox?.stopAllAudio() // 1
boxScene.steelBox?.stopAllAnimations() // 1
print("Actions are stopped.")
completion = {
$0?.stopAllAudio() // 2
$0?.stopAllAnimations() // 2
$0?.scale = [1,15,1]
print("Both actions were completely stopped.")
}
boxScene.actions.occured.onAction = completion
}
Spacer()
}
}
}
}
А вот и обычная привязка.
struct ARViewContainer : UIViewRepresentable {
@Binding var arView: ARView
@Binding var boxScene: Experience.Box
func makeUIView(context: Context) -> ARView {
arView.scene.anchors.append(boxScene)
return arView
}
func updateUIView(_ view: ARView, context: Context) { }
}
Обратите внимание, что действие Notify является последним в последовательности. Через какое время будут применены вторичные методы stop() (я имею в виду содержимое обработчика завершения), зависит от длительности аудиофайла или анимации (продолжительность моего аудио составляет 14 секунд).
Решение UIKit несколько отличается и немного проще.
import UIKit
import RealityKit
class ViewController : UIViewController {
@IBOutlet var arView: ARView!
let boxScene = try! Experience.loadBox()
var completion: ((Entity?) -> Void)? = { _ in }
override func viewDidLoad() {
super.viewDidLoad()
let rect = CGRect(x: 50, y: 50, width: 100, height: 50)
let stopButton = UIButton(frame: rect)
stopButton.setTitle("Stop", for: .normal)
stopButton.addTarget(self,
action: #selector(stopPlayingAudioAndAnime),
for: .touchUpInside)
arView.addSubview(stopButton)
arView.scene.anchors.append(boxScene)
}
@objc private func stopPlayingAudioAndAnime() {
boxScene.steelBox?.stopAllAudio() // 1
boxScene.steelBox?.stopAllAnimations() // 1
completion = { entity in
entity?.stopAllAudio() // 2
entity?.stopAllAnimations() // 2
print("Completely Stopped")
}
boxScene.actions.occured.onAction = completion
}
}
Однако, если вы будете использовать действие Play Music (другими словами, на основе сцены, а не объекта, как Play Sound действие), вы можете реализовать свою идею следующим образом:
arView.scene.anchors[0].children[0].stopAllAudio()
completion = { entity in
entity?.scene?.anchors[0].children[0].stopAllAudio()
}
Хороший! Дополнительно у меня 2 вопроса: 1) Зачем нужно добавлять .children[0] в код? и 2) Могу ли я использовать .playAudio() для возобновления воспроизведения после остановки?
1) Это иерархия. AnchorEntity не имеет необходимых компонентов. 2) разместить еще один вопрос.
Можно ли использовать
arView.scene.anchors[0].stopAllAudio()?