質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.86%

Swift ARKit 複数のオブジェクトが異なる音声が再生されるようにしたいです。

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 497

oyshwk46

score 9

前提・実現したいこと

Xcode Swift4にてARKitを用い、AR空間にあるオブジェクトをタップすると音が再生されるというアプリを作っています。
最終的には、オブジェクトを複数配置し、それぞれ別の音が鳴るようにしたいと考えています。

例)オブジェクトAは音声1を再生、オブジェクトBは音声2を再生

発生している問題・エラーメッセージ

オブジェクトを2個配置し、同じ音を再生させることは出来たのですが、オブジェクトごとに違う音声を再生させることができません。

該当のソースコード

import UIKit
import SceneKit
import ARKit
import AVFoundation


class ViewController: UIViewController, ARSCNViewDelegate {

    @IBOutlet var sceneView: ARSCNView!

    let node1 = SCNNode()
    let node2 = SCNNode()
    var audioPlayer1:AVAudioPlayer!
    var audioPlayer2:AVAudioPlayer!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Set the view's delegate
        sceneView.delegate = self
       // sceneView.debugOptions = [.showWorldOrigin, .showFeaturePoints]

        node1.geometry = SCNSphere(radius: 1)
        let marerial1 = SCNMaterial()
        marerial1.diffuse.contents = UIColor(red: 255/255, green: 0/255, blue: 0/255, alpha: 1.0)
        node1.geometry?.materials = [marerial1]

        node2.geometry = SCNSphere(radius: 1)
        let marerial2 = SCNMaterial()
        marerial2.diffuse.contents = UIColor(red: 0/255, green: 255/255, blue: 0/255, alpha: 1.0)
        node2.geometry?.materials = [marerial2]


        let phi1:Double = 252.292
        let PHI1:Double = phi1 * (.pi/180)
        let theta1:Double = 69.663
        let THETA1:Double = theta1 * (.pi/180)

        let phi2:Double = 246
        let PHI2:Double = phi2 * (.pi/180)
        let theta2:Double = 80
        let THETA2:Double = theta2 * (.pi/180)

        let r:Double = 100

        let x1:Double = r * sin(PHI1) * cos(THETA1)
        let y1:Double = r * sin(THETA1) * sin(PHI1)
        let z1:Double = r * cos(THETA1)

        let x2:Double = r * sin(PHI2) * cos(THETA2)
        let y2:Double = r * sin(THETA2) * sin(PHI2)
        let z2:Double = r * cos(THETA2)

        node1.position = SCNVector3(Double(y1), Double(z1), -Double(x1))
        node2.position = SCNVector3(Double(y2), Double(z2), -Double(x2))

        sceneView.scene.rootNode.addChildNode(node1)
        sceneView.scene.rootNode.addChildNode(node2)

        let audioPath1 = Bundle.main.path(forResource: "sheep-cry1", ofType:"mp3")!
        let audioPath2 = Bundle.main.path(forResource: "dog1", ofType:"mp3")!

        let audioUrl1 = URL(fileURLWithPath: audioPath1)
        let audioUrl2 = URL(fileURLWithPath: audioPath2)

        var audioError1:NSError?
        do{
            audioPlayer1 = try AVAudioPlayer(contentsOf: audioUrl1)
        } catch let error as NSError {
            audioError1 = error
            audioPlayer1 = nil
        }
        if let error = audioError1 {
            print("Error \(error.localizedDescription)")
        }

        var audioError2:NSError?
        do{
            audioPlayer2 = try AVAudioPlayer(contentsOf: audioUrl2)
        } catch let error as NSError {
            audioError2 = error
            audioPlayer2 = nil
        }
        if let error = audioError2 {
            print("Error \(error.localizedDescription)")
        }

        audioPlayer1.delegate = self as? AVAudioPlayerDelegate
        audioPlayer1.prepareToPlay()
        audioPlayer2.delegate = self as? AVAudioPlayerDelegate
        audioPlayer2.prepareToPlay()
    }


    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
       guard let touchLocation = touches.first?.location(in: sceneView),
        let hitResults = sceneView.hitTest(touchLocation, options: [:]).first else  { return }

        let node = hitResults.node

        if node.name == "node1" {

            audioPlayer1.play()

        } else if node.name == "node2" {

            audioPlayer2.play()

        }
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        let configuration = ARWorldTrackingConfiguration()

        sceneView.session.run(configuration)

    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        // Pause the view's session
        sceneView.session.pause()
    }
}

試したこと

オブジェクトを1つ配置し、音が再生されるといったコードは以下になります。

import UIKit
import SceneKit
import ARKit
import AVFoundation


class ViewController: UIViewController, ARSCNViewDelegate {

    @IBOutlet var sceneView: ARSCNView!
    let node1 = SCNNode()
    var audioPlayer1:AVAudioPlayer!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Set the view's delegate
        sceneView.delegate = self
       // sceneView.debugOptions = [.showWorldOrigin, .showFeaturePoints]

       // let node1 = SCNNode()
        //node.geometry = SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0)
        node1.geometry = SCNSphere(radius: 1)
        let marerial1 = SCNMaterial()
        marerial1.diffuse.contents = UIColor(red: 255/255, green: 0/255, blue: 0/255, alpha: 1.0)
        node1.geometry?.materials = [marerial1]

        let phi1:Double = 252.292
        let PHI1:Double = phi1 * (.pi/180)
        let theta1:Double = 69.663
        let THETA1:Double = theta1 * (.pi/180)

        let r:Double = 100

        let x1:Double = r * sin(PHI1) * cos(THETA1)
        let y1:Double = r * sin(THETA1) * sin(PHI1)
        let z1:Double = r * cos(THETA1)

        node1.position = SCNVector3(Double(y1), Double(z1), -Double(x1))
        sceneView.scene.rootNode.addChildNode(node1)

        let audioPath1 = Bundle.main.path(forResource: "sheep-cry1", ofType:"mp3")!
        let audioUrl1 = URL(fileURLWithPath: audioPath1)

        var audioError:NSError?
        do{
            audioPlayer1 = try AVAudioPlayer(contentsOf: audioUrl1)
        } catch let error as NSError {
            audioError = error
            audioPlayer1 = nil
        }
        if let error = audioError {
            print("Error \(error.localizedDescription)")
        }

        audioPlayer1.delegate = self as? AVAudioPlayerDelegate
        audioPlayer1.prepareToPlay()
    }

    @IBAction func tap(_ sender: UITapGestureRecognizer) {

        let sceneView = sender.view as!ARSCNView
        let touchLocation = sender.location(in: sceneView)
        let hitResults = sceneView.hitTest(touchLocation, options: [:])

        if !hitResults.isEmpty {
            audioPlayer1.play()
        }
        else {
            audioPlayer1.stop()
        }
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        let configuration = ARWorldTrackingConfiguration()

        sceneView.session.run(configuration)

    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        // Pause the view's session
        sceneView.session.pause()
    }    
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

check解決した方法

0

ノードの名前をつけたら出来ました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.86%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる