Android Studio + kotlin + SQLiteで音符フラッシュカードアプリを作る　⑧回答ボタン押下（効果音再生（MediaPlayer、正誤判定、次の問題出題）


#１．今回のテーマ

前回は、トップ画面で選択したレベルに応じた問題を出題（問題番号カウントアップ、問題画像表示、正解文字列セット）するところまで実装しました。
今回は回答ボタンを押したときの処理を実装していきます。


#２．処理概要
① 各回答ボタンにlistenerを設定
② 押された回答ボタンからタグを取得
③ ②で取得したタグと、問題表示の際に設定した正解文字列セットを比較
④-1 正解の場合：正解数をカウントアップして正解音を鳴らす
④-2 不正解の場合：不正解音を鳴らす
⑤ 問題数が10だったら次の画面に遷移、10未満のときは次の問題を出題
です。

### ①各回答ボタンにlistenerを設定
第5回の記事で解説しましたが、ボタンが押されたことを検知するために、各ボタンオブジェクトに対して、**listener**を設定します。
https://qiita.com/tomohiro-yamashita-5664/items/ae86d6273cfc8c13b482

listenerは、ゲーム画面が起動された際に設定する必要があるので、onCreateメソッド内に記述していきます。

```kotlin:GameActivity.kt
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_game)

        //回答ボタンを取得
        val btAnswerButton_c = findViewById<ImageButton>(R.id.bt_c)
        val btAnswerButton_d = findViewById<ImageButton>(R.id.bt_d)
        val btAnswerButton_e = findViewById<ImageButton>(R.id.bt_e)
        val btAnswerButton_f = findViewById<ImageButton>(R.id.bt_f)
        val btAnswerButton_g = findViewById<ImageButton>(R.id.bt_g)
        val btAnswerButton_a = findViewById<ImageButton>(R.id.bt_a)
        val btAnswerButton_b = findViewById<ImageButton>(R.id.bt_b)

        //回答ボタンリスナー
        val listener2 = AnswerButtonClickListener()

        btAnswerButton_c.setOnClickListener(listener2)
        btAnswerButton_d.setOnClickListener(listener2)
        btAnswerButton_e.setOnClickListener(listener2)
        btAnswerButton_f.setOnClickListener(listener2)
        btAnswerButton_g.setOnClickListener(listener2)
        btAnswerButton_a.setOnClickListener(listener2)
        btAnswerButton_b.setOnClickListener(listener2)

    }
```

詳細は割愛しますが、処理の内容としては以下の通りです。
・findViewById()で各ボタンオブジェクトを取得
・listenerを定義（今回は**AnswerButtonClickListener()**という名前で定義しました）
・各ボタンに対して、listenerをセット
AnswerButtonClickListenerには押されたボタンオブジェクトを渡せるので、中身の処理はボタンごとの違いはありません。


### ②押された回答ボタンからタグを取得
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619303/813e1a88-20a6-1b7a-c2cd-c187c78887f4.png)
次にどのボタンが押されたかを判定します。
①で定義したAnswerButtonClickListenerクラス内で実装していきます。

画面編で解説しましたが、各ボタンにはtagとして、ド～シの文字列をセットしています。

```xml:activity_game.xml
        <ImageButton
            android:id="@+id/bt_c"
            android:src="@drawable/button_c"
            android:tag="ド"
            android:layout_marginLeft="22dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
```

ソースコードは以下の通りです。

```kotlin:GameActivity.kt
    private inner class AnswerButtonClickListener : View.OnClickListener {
        override fun onClick(view: View) {

            //押された回答ボタンからタグを取得
            val answer = view.tag.toString()
        }

```

**answer**という変数に、引数として渡されたview（押されたボタンです）のtagを取得して、文字列型に変換しています。


###③ ②で取得したタグと、問題表示の際に設定した正解文字列セットを比較
タグ取得の処理の後に続けて書いていきます。

```kotlin
if(answer == correctAnswer){}
```

if文で
タグ：answer
正解文字列：correctAnswer
を比較します。

correctAnswerを設定するコードは以下（[前回の記事参照）](https://qiita.com/tomohiro-yamashita-5664/items/a67eeb3fe9cc63eb1c65)

```kotlin
        //番号に応じて画像と答えを設定
        when(questionId) {
            1 -> {
                //画像に右手ドをセット
                ivNote.setImageResource(R.drawable.right_c);
                correctAnswer = "ド"
            }
```

###④-1 正解の場合：正解数をカウントアップして正解音を鳴らす
次に正解の場合の処理です
if文の条件式がtrueだった場合の処理として実装します。

```kotlin
            if(answer == correctAnswer) {
                correctCount += 1
                _player = MediaPlayer.create(this@GameActivity, R.raw.correct)
                _player?.start()
```

correctCountは、Activityのクラス変数としてonCreateメソッド外で初期値0で宣言します。

```kotlin
class GameActivity : AppCompatActivity() {

    //正解数カウンタ
    var correctCount = 0
```

正解の場合の処理なので、このcorrectCountをカウントアップします。
その処理が
```correctCount += 1```
の部分です。

correctCountは、この後結果画面に渡します。

次に正解音を鳴らす処理です。

androidで音を鳴らすための実装方法は何種類かあるようなのですが、今回は最も簡単な方法を選択しました。

まずは、再生する音声ファイルをプロジェクトに読み込ませます。
プロジェクトエクスプローラーを表示させ、res配下に**raw**ディレクトリを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619303/4a073d58-b32d-91e2-843a-499e75400b33.png)
「res」で右クリック　⇒　「新規」　⇒　「Androidリソース・ディレクトリー」を選択
リソースタイプ：rawを選択してOKボタンを押下。

次に作成したrawフォルダに、音声ファイルをコピーします。
画像をdrawableフォルダにコピーするのと同じ要領です。
今回は**correct.mp3**、**incorrect.mp3**という名前でそれぞれ、正解音・不正解音を保存しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619303/48e8edb9-47d0-62a9-6616-367084602d39.png)

次にクラス変数として、MediaPlayer型の変数***_player***を宣言します。

```kotlin
class GameActivity : AppCompatActivity() {
    //効果音再生用変数
    private var _player: MediaPlayer? = null
```

そして、AnswerButtonClickListenerの中で、MediaPlayerオブジェクトを生成し音声ファイルをセットします。

```kotlin
　_player = MediaPlayer.create(this@GameActivity, R.raw.correct)
```

最後にstart()でファイルを再生します。

```kotlin
　_player?.start()
```


###④-2 不正解の場合：不正解音を鳴らす
続いて不正解の場合です。
正解数カウントアップはなしで、不正解音を鳴らすだけです。
if文の条件式がfalseだった場合の処理として記載します。

③④をまとめると、以下の通りです。

```kotlin:GameActivity.kt
            if(answer == correctAnswer) {
                correctCount += 1
                _player = MediaPlayer.create(this@GameActivity, R.raw.correct)
                _player?.start()
            }else {
                _player = MediaPlayer.create(this@GameActivity, R.raw.incorrect)
                _player?.start()
            }
```

解説は長くなりましたがコードにすると簡単ですね。



###⑤ 問題数が10だったら次の画面に遷移、10未満の時は次の問題を出題
続いて、次の問題を出題していきます。
まずは10問出題し終わっているかどうかの判定です。
10問出し終わっている場合は、結果画面に遷移します。
結果画面に渡すデータは、正解数とレベル、そしてプレイ時間です。
プレイ時間については、次回の記事で解説します。

```kotlin:GameActivity.kt
            //インテントからレベルを取得
            val level = intent.getStringExtra("level")
            //問題数が10だったら結果画面に遷移
            if(questionCount == 10) {
                val intent2Result = Intent(this@GameActivity, ResultActivity::class.java)

                //タイム（テキスト）
                val timeText = findViewById<TextView>(R.id.tv_time).text
                intent2Result.putExtra("finishTime", timeText)
                //タイム（数値）
                intent2Result.putExtra("timeValue", timeValue)
                //正解数
                intent2Result.putExtra("correctCount", correctCount)
                //レベル
                val level = intent.getStringExtra("level")
                intent2Result.putExtra("level", level)

                //結果画面表示
                startActivity(intent2Result)
            }
            else if (level != null) {
                setQuestion(level)
            }
```

正誤判定の後、questionCountが10だったら、結果画面へのintentを生成して

```kotlin
val intent2Result = Intent(this@GameActivity, ResultActivity::class.java)
```

結果画面に渡すデータをputExtraで設定していきます。

```kotlin
                //タイム（テキスト）
                val timeText = findViewById<TextView>(R.id.tv_time).text
                intent2Result.putExtra("finishTime", timeText)
                //タイム（数値）
                intent2Result.putExtra("timeValue", timeValue)
                //正解数
                intent2Result.putExtra("correctCount", correctCount)
                //レベル
                val level = intent.getStringExtra("level")
                intent2Result.putExtra("level", level)
```

そして次の結果画面を表示します。

```kotlin
                //結果画面表示
                startActivity(intent2Result)
```


questionCountが10ではないときは、次の問題を出題します。
問題を出題するには、前回定義したsetQuestionメソッドにレベルを渡してあげるだけです。

```kotlin
            else if (level != null) {
                setQuestion(level)
```

setQuestion()メソッドの内容は以下の通りです。（詳細は前回の記事で解説しています。）

```kotlin
    private fun setQuestion(level: String) {

        //問題番号を1プラス
        questionCount = questionCount + 1


        //問題番号欄の表示を更新
        var tv_questionCount = findViewById<TextView>(R.id.tv_questionCount)
        tv_questionCount.setText("第${questionCount}問")


        //画像をセットするViewを取得
        var ivNote = findViewById<ImageView>(R.id.iv_note)


        //どの問題を表示するか選ぶ
        var questionId = 0
        val level = intent.getStringExtra("level")
        when(level) {
            "ト音初級" -> {
                questionId = (1..8).random()
            }
            "ト音中級" -> {
                questionId = (1..15).random()
            }
            "ト音上級" -> {
                questionId = (1..18).random()
            }
            "へ音初級" -> {
                questionId = (19..26).random()
            }
            "へ音中級" -> {
                questionId = (19..33).random()
            }
            "へ音上級" -> {
                questionId = (19..36).random()
            }
            "両手初級" -> {
                var levelFrag = (0..1).random()
                if(levelFrag == 0){
                    questionId = (1..8).random()
                }else {
                    questionId = (19..26).random()
                }
            }
            "両手中級" -> {
                var levelFrag = (0..1).random()
                if(levelFrag == 0){
                    questionId = (1..15).random()
                }else {
                    questionId = (19..33).random()
                }
            }
            "両手上級" -> {
                questionId = (1..36).random()
            }
        }

        //番号に応じて画像と答えを設定
        when(questionId) {
            1 -> {
                //画像に右手ドをセット
                ivNote.setImageResource(R.drawable.right_c);
                correctAnswer = "ド"
            }
            2 -> {
                //画像に右手レをセット
                ivNote.setImageResource(R.drawable.right_d);
                correctAnswer = "レ"
            }
            3 -> {
                //画像に右手ミをセット
                ivNote.setImageResource(R.drawable.right_e);
                correctAnswer = "ミ"
            }
            4 -> {
                //画像に右手ファをセット
                ivNote.setImageResource(R.drawable.right_f);
                correctAnswer = "ファ"
            }
            5 -> {
                //画像に右手ソをセット
                ivNote.setImageResource(R.drawable.right_g);
                correctAnswer = "ソ"
            }
            6 -> {
                //画像に右手ラをセット
                ivNote.setImageResource(R.drawable.right_a);
                correctAnswer = "ラ"
            }
            7 -> {
                //画像に右手シをセット
                ivNote.setImageResource(R.drawable.right_b);
                correctAnswer = "シ"
            }
            8 -> {
                //画像に右手高音ドをセット
                ivNote.setImageResource(R.drawable.right_cc);
                correctAnswer = "ド"
            }
            9 -> {
                //画像に右手高音レをセット
                ivNote.setImageResource(R.drawable.right_dd);
                correctAnswer = "レ"
            }
            10 -> {
                //画像に右手高音ミをセット
                ivNote.setImageResource(R.drawable.right_ee);
                correctAnswer = "ミ"
            }
            11 -> {
                //画像に右手高音ファをセット
                ivNote.setImageResource(R.drawable.right_ff);
                correctAnswer = "ファ"
            }
            12 -> {
                //画像に右手高音ソをセット
                ivNote.setImageResource(R.drawable.right_gg);
                correctAnswer = "ソ"
            }
            13 -> {
                //画像に右手高音ラをセット
                ivNote.setImageResource(R.drawable.right_aa);
                correctAnswer = "ラ"
            }
            14 -> {
                //画像に右手高音シをセット
                ivNote.setImageResource(R.drawable.right_bb);
                correctAnswer = "シ"
            }
            15 -> {
                //画像に右手超高音ドをセット
                ivNote.setImageResource(R.drawable.right_ccc);
                correctAnswer = "ド"
            }
            16 -> {
                //画像に右手低音ソをセット
                ivNote.setImageResource(R.drawable.right_ggg);
                correctAnswer = "ソ"
            }
            17 -> {
                //画像に右手低音ラをセット
                ivNote.setImageResource(R.drawable.right_aaa);
                correctAnswer = "ラ"
            }
            18 -> {
                //画像に右手低音シをセット
                ivNote.setImageResource(R.drawable.right_bbb);
                correctAnswer = "シ"
            }


            19 -> {
                //画像に左手ドをセット
                ivNote.setImageResource(R.drawable.left_c);
                correctAnswer = "ド"
            }
            20 -> {
                //画像に左手レをセット
                ivNote.setImageResource(R.drawable.left_d);
                correctAnswer = "レ"
            }
            21 -> {
                //画像に左手ミをセット
                ivNote.setImageResource(R.drawable.left_e);
                correctAnswer = "ミ"
            }
            22 -> {
                //画像に左手ファをセット
                ivNote.setImageResource(R.drawable.left_f);
                correctAnswer = "ファ"
            }
            23 -> {
                //画像に左手ソをセット
                ivNote.setImageResource(R.drawable.left_g);
                correctAnswer = "ソ"
            }
            24 -> {
                //画像に左手ラをセット
                ivNote.setImageResource(R.drawable.left_a);
                correctAnswer = "ラ"
            }
            25 -> {
                //画像に左手シをセット
                ivNote.setImageResource(R.drawable.left_b);
                correctAnswer = "シ"
            }
            26 -> {
                //画像に左手高音ドをセット
                ivNote.setImageResource(R.drawable.left_cc);
                correctAnswer = "ド"
            }
            27 -> {
                //画像に右手低音レをセット
                ivNote.setImageResource(R.drawable.left_dd);
                correctAnswer = "レ"
            }
            28 -> {
                //画像に左手低音ミをセット
                ivNote.setImageResource(R.drawable.left_ee);
                correctAnswer = "ミ"
            }
            29 -> {
                //画像に左手低音ファをセット
                ivNote.setImageResource(R.drawable.left_ff);
                correctAnswer = "ファ"
            }
            30 -> {
                //画像に左手低音ソをセット
                ivNote.setImageResource(R.drawable.left_gg);
                correctAnswer = "ソ"
            }
            31 -> {
                //画像に左手低音ラをセット
                ivNote.setImageResource(R.drawable.left_aa);
                correctAnswer = "ラ"
            }
            32 -> {
                //画像に左手低音シをセット
                ivNote.setImageResource(R.drawable.left_bb);
                correctAnswer = "シ"
            }
            33 -> {
                //画像に左手超低音ドをセット
                ivNote.setImageResource(R.drawable.left_ccc);
                correctAnswer = "ド"
            }
            34 -> {
                //画像に左手超高音レをセット
                ivNote.setImageResource(R.drawable.left_ddd);
                correctAnswer = "レ"
            }
            35 -> {
                //画像に左手超高音ミをセット
                ivNote.setImageResource(R.drawable.left_eee);
                correctAnswer = "ミ"
            }
            36 -> {
                //画像に左手超高音ファをセット
                ivNote.setImageResource(R.drawable.left_fff);
                correctAnswer = "ファ"
            }

        }

    }
```

今回は以上です。
次回は、プレイ時間をカウントするタイマーの実装について解説します。




[①概要](https://qiita.com/tomohiro-yamashita-5664/items/e87f90fef9cf34faf9bf)
[②画面デザイン～トップ画面（Constraint Layout）～](https://qiita.com/tomohiro-yamashita-5664/items/72a529e12f292a8e1538)
[③画面デザイン～ゲーム画面（Linear Layout）～](https://qiita.com/tomohiro-yamashita-5664/items/9674fa7c1d0cc2de1c40)
[④画面デザイン～結果画面（Linear Layoutその2）～](https://qiita.com/tomohiro-yamashita-5664/items/08f99be14d2ac2254634)
[⑤トップ画面からの遷移（インテント(putExtra)）](https://qiita.com/tomohiro-yamashita-5664/items/ae86d6273cfc8c13b482)
[⑥トップ画面から引き継いだデータ表示（インテント(getExtra)）](https://qiita.com/tomohiro-yamashita-5664/items/bf50791fa5355818d7fb)
[⑦問題出題（ロジック実装）](https://qiita.com/tomohiro-yamashita-5664/items/a67eeb3fe9cc63eb1c65)
[⑧回答ボタン押下（効果音再生（MediaPlayer、正誤判定、次の問題出題）（本記事）](https://qiita.com/tomohiro-yamashita-5664/items/8b032855a9377ba9897e)
[⑨タイムカウンターの実装（handler）](https://qiita.com/tomohiro-yamashita-5664/items/8f5633e68f0519d6841f)
[⑩ゲーム画面から引き継いだゲーム結果表示（インテント）](https://qiita.com/tomohiro-yamashita-5664/items/0e208a3c1a75c5b13376)
[⑪当日日付データ取得](https://qiita.com/tomohiro-yamashita-5664/items/59513080e5d5f419d6af)
[⑫DB保存（SQLite、Insert）](https://qiita.com/tomohiro-yamashita-5664/items/5a0d967f2e42aa90ee24)
⑬もう一度、トップ画面へ戻るボタン（インテント）
⑭ランキング表示（SQLite、Select）
⑮実機でのテスト
⑯Google Playで公開