swift 如果我在Reality Composer中分配了一个声音,我可以在RealityKit中通过编程停止它吗?

e37o9pze  于 2023-01-08  发布在  Swift
关注(0)|答案(1)|浏览(122)

我在Reality Composer中为场景指定声音,如下图所示

我想创建一个UIButton,可以按下它来停止声音。我可以这样做吗?

vc6uscn9

vc6uscn91#

我为盒子场景创建了三个Reality Composer动作:它们是Play SoundSpinNotify。如您所见,***循环播放***已打开。

快速用户界面

我的代码就是这么简单。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秒)。

UI套件

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 action(换句话说,基于场景,而不是基于对象,如Play Sound action),则可以通过以下方式实现您的想法:

arView.scene.anchors[0].children[0].stopAllAudio()
    
completion = { entity in
    entity?.scene?.anchors[0].children[0].stopAllAudio()
}

相关问题