0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2021-06-16

#1.今回のテーマ

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

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

①各回答ボタンにlistenerを設定

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

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

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
次にどのボタンが押されたかを判定します。
①で定義したAnswerButtonClickListenerクラス内で実装していきます。

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

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"/>

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

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

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

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

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

if(answer == correctAnswer){}

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

correctAnswerを設定するコードは以下(前回の記事参照)

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

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

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

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

class GameActivity : AppCompatActivity() {

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

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

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

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

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

まずは、再生する音声ファイルをプロジェクトに読み込ませます。
プロジェクトエクスプローラーを表示させ、res配下にrawディレクトリを作成します。
image.png
「res」で右クリック ⇒ 「新規」 ⇒ 「Androidリソース・ディレクトリー」を選択
リソースタイプ:rawを選択してOKボタンを押下。

次に作成したrawフォルダに、音声ファイルをコピーします。
画像をdrawableフォルダにコピーするのと同じ要領です。
今回はcorrect.mp3incorrect.mp3という名前でそれぞれ、正解音・不正解音を保存しました。
image.png

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

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

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

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

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

 _player?.start()

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

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

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問出し終わっている場合は、結果画面に遷移します。
結果画面に渡すデータは、正解数とレベル、そしてプレイ時間です。
プレイ時間については、次回の記事で解説します。

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を生成して

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

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

                //タイム(テキスト)
                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)

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

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

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

    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 = "ファ"
            }

        }

    }

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

①概要
②画面デザイン~トップ画面(Constraint Layout)~
③画面デザイン~ゲーム画面(Linear Layout)~
④画面デザイン~結果画面(Linear Layoutその2)~
⑤トップ画面からの遷移(インテント(putExtra))
⑥トップ画面から引き継いだデータ表示(インテント(getExtra))
⑦問題出題(ロジック実装)
⑧回答ボタン押下(効果音再生(MediaPlayer、正誤判定、次の問題出題)(本記事)
⑨タイムカウンターの実装(handler)
⑩ゲーム画面から引き継いだゲーム結果表示(インテント)
⑪当日日付データ取得
⑫DB保存(SQLite、Insert)
⑬もう一度、トップ画面へ戻るボタン(インテント)
⑭ランキング表示(SQLite、Select)
⑮実機でのテスト
⑯Google Playで公開

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?