#1.今回のテーマ
前回は、トップ画面で選択したレベルに応じた問題を出題(問題番号カウントアップ、問題画像表示、正解文字列セット)するところまで実装しました。
今回は回答ボタンを押したときの処理を実装していきます。
#2.処理概要
① 各回答ボタンにlistenerを設定
② 押された回答ボタンからタグを取得
③ ②で取得したタグと、問題表示の際に設定した正解文字列セットを比較
④-1 正解の場合:正解数をカウントアップして正解音を鳴らす
④-2 不正解の場合:不正解音を鳴らす
⑤ 問題数が10だったら次の画面に遷移、10未満のときは次の問題を出題
です。
①各回答ボタンにlistenerを設定
第5回の記事で解説しましたが、ボタンが押されたことを検知するために、各ボタンオブジェクトに対して、listenerを設定します。
https://qiita.com/tomohiro-yamashita-5664/items/ae86d6273cfc8c13b482
listenerは、ゲーム画面が起動された際に設定する必要があるので、onCreateメソッド内に記述していきます。
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には押されたボタンオブジェクトを渡せるので、中身の処理はボタンごとの違いはありません。
②押された回答ボタンからタグを取得
次にどのボタンが押されたかを判定します。
①で定義したAnswerButtonClickListenerクラス内で実装していきます。
画面編で解説しましたが、各ボタンにはtagとして、ド~シの文字列をセットしています。
<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"/>
ソースコードは以下の通りです。
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ディレクトリを作成します。
「res」で右クリック ⇒ 「新規」 ⇒ 「Androidリソース・ディレクトリー」を選択
リソースタイプ:rawを選択してOKボタンを押下。
次に作成したrawフォルダに、音声ファイルをコピーします。
画像をdrawableフォルダにコピーするのと同じ要領です。
今回はcorrect.mp3、incorrect.mp3という名前でそれぞれ、正解音・不正解音を保存しました。
次にクラス変数として、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だった場合の処理として記載します。
③④をまとめると、以下の通りです。
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問出し終わっている場合は、結果画面に遷移します。
結果画面に渡すデータは、正解数とレベル、そしてプレイ時間です。
プレイ時間については、次回の記事で解説します。
//インテントからレベルを取得
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で公開