ARKitを利用したポケモンカードARお遊び

#今回作成したもの
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">ポケカARその2<a href="https://twitter.com/hashtag/%E3%83%9D%E3%82%B1%E3%82%AB?src=hash&amp;ref_src=twsrc%5Etfw">#ポケカ</a> <a href="https://t.co/3HDzKpw2cj">pic.twitter.com/3HDzKpw2cj</a></p>&mdash; ツナ@CL千葉 (@poke_tuna) <a href="https://twitter.com/poke_tuna/status/1095996615184257024?ref_src=twsrc%5Etfw">2019年2月14日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


#はじめに
今回の記事を書くにあたりこちらの記事を参考にさせていただきました．
https://qiita.com/shunp/items/4289660b912d90536ece

SwiftやARKitに関しては全くの初心者ですが読んでいて思わず自分も実装してみたいと思い，こちらの記事を参考にしつつ自分が今はまっているポケモンカードを対象として追加要素を実装したのでまとめておきます．
初学者でも簡単に実装でき，いい時代だなぁと感じました．
至らない点もあると思いますがよろしくお願いします．

#概要
ARKitを利用したポケモンカードARの実装．

追加要素として
- 複数のオブジェクトの認識
- 対象認識時の音声の出力
の2点を実装しましたのでこの2点について記述します．

#複数オブジェクトの認識
##まず認識対象の画像を複数用意
複数の対象を認識するためにその対象分の画像がいるのでそれらを用意するところから始めます．
インターネット上から探してくるなどして対象画像を用意します．
今回は，こんな感じでリザードンとカメックスを用意しました．
このようにAR Resourcesの中に複数の対象を用意します．
<img width="690" alt="スクリーンショット 2019-02-14 1.13.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/183525/48ffe075-edb0-73f9-d179-bab5bf0ee812.png">

##画像に対応する複数のモデルの配置方法
3Dオブジェクトを表示させるコードです．

```ViewController.swift
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
         
        let node1 = SCNNode()
        
        if let imageAnchor = anchor as? ARImageAnchor {
            let plane = SCNPlane(width: imageAnchor.referenceImage.physicalSize.width, height: imageAnchor.referenceImage.physicalSize.height)
            plane.firstMaterial?.diffuse.contents = UIColor(red: 0, green: 0, blue: 1.0, alpha: 0.5)
            let planeNode = SCNNode(geometry: plane)
            planeNode.eulerAngles.x = -.pi / 2
            node1.addChildNode(planeNode)
            
            switch imageAnchor.referenceImage.name {
            case "Charizard":
                
                if let charizardScene = SCNScene(named: "art.scnassets/Charizard.scn") {
                    
                    if let charizardNode = charizardScene.rootNode.childNodes.first {
                        charizardNode.eulerAngles.x = .pi/2
                        charizardNode.eulerAngles.z = .pi
                        planeNode.addChildNode(charizardNode)
                    }
                }
                
            case "Blastoise":
                
                if let BlastoiseScene = SCNScene(named: "art.scnassets/Blastoise.scn") {
                    
                    if let BlastoiseNode = BlastoiseScene.rootNode.childNodes.first {
                        BlastoiseNode.eulerAngles.x = .pi/2
                        BlastoiseNode.eulerAngles.z = .pi
                        planeNode.addChildNode(BlastoiseNode)
                    }
                }
                
            default:
                return nil
            }
        }
        return node1
        
    }
```
複数対象のためのポイントとしては，至ってシンプルです．

```ViewController.swift
switch imageAnchor.referenceImage.name {
case "Charizard":                               
```
このようにswitch構文を利用して，対象としてAR Resourcesに置いた画像ごとにレンダリングの処理を記述します．
すると次の画像のように画像ごとに対応するモデルが表示されます．
<img width="505" alt="スクリーンショット 2019-02-14 1.56.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/183525/83d2d4a5-a465-032c-9bf5-f97b00e399d2.png">

複数対象の認識の準備が整ったので，次に認識と同時に音声が出力される処理を実装します．

#音声再生処理の準備
こちらのコードを「func viewDidload()」内に追加します．
各ポケモンの音声ファイルは，こちらからダウンロードしました．
http://games255.512.jp/pokewav_DL/index.html

```ViewController.swift
        //音声のファイルのパスの取得
        let audioPath1 = Bundle.main.path(forResource:"006", ofType:"wav")!
        let audioUrl1 = URL(fileURLWithPath: audioPath1)
        let audioPath2 = Bundle.main.path(forResource:"009", ofType:"wav")!
        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)")
        }
        
        audioPlayer1?.delegate = self as? AVAudioPlayerDelegate
        audioPlayer1?.prepareToPlay()
        
        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)")
        }
        
        audioPlayer2?.delegate = self as? AVAudioPlayerDelegate
        audioPlayer2?.prepareToPlay()
```

#音声の再生
このコマンドで設定した音声が再生されます．

```
audioPlayer.play()
```
今回は，モデル配置時に1回のみ音声プレイヤーが実行されるよう設定しました．
そのコードがこちらになります．

```ViewController.swift
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
         
        let node1 = SCNNode()

        
        if let imageAnchor = anchor as? ARImageAnchor {
            let plane = SCNPlane(width: imageAnchor.referenceImage.physicalSize.width, height: imageAnchor.referenceImage.physicalSize.height)
            plane.firstMaterial?.diffuse.contents = UIColor(red: 0, green: 0, blue: 1.0, alpha: 0.5)
            let planeNode = SCNNode(geometry: plane)
            planeNode.eulerAngles.x = -.pi / 2
            node1.addChildNode(planeNode)
            
            switch imageAnchor.referenceImage.name {
            case "Charizard":
                audioPlayer1.play()
                if let charizardScene = SCNScene(named: "art.scnassets/Charizard.scn") {
                    
                    if let charizardNode = charizardScene.rootNode.childNodes.first {
                        charizardNode.eulerAngles.x = .pi/2
                        charizardNode.eulerAngles.z = .pi
                        planeNode.addChildNode(charizardNode)
                    }
                }
                //return node
            case "Blastoise":
                audioPlayer2.play()
                if let BlastoiseScene = SCNScene(named: "art.scnassets/Blastoise.scn") {
                    
                    if let BlastoiseNode = BlastoiseScene.rootNode.childNodes.first {
                        BlastoiseNode.eulerAngles.x = .pi/2
                        BlastoiseNode.eulerAngles.z = .pi
                        planeNode.addChildNode(BlastoiseNode)
                    }
                }
                //return node
            default:
                return nil
            }
        }
        return node1
        
    }
```

これでビルドした後，アプリを実行することで冒頭のようなものを再現することができます．

#まとめ
ARKitを使って遊んでみましたが，シンプルなコードでここまでできることに感動しました．
まだまだ触れられていない機能も多々あるので勉強します．