Android & Kotlinの環境でマインスイーパーを開発する方法を説明します。
今回は、ゲームのリセットボタンを実装します。
リセットボタンは、実行するとゲームをリセットする機能以外に「通常状態」、「ゲームオーバー」、「ゲームクリア」の状態を表す機能を持たせます。
動作イメージ
リセットボタンは、画面上段真ん中に配置している黄色いやつです。
通常状態
ゲームオーバー
ゲームクリア
そそたた
レセットボタンのイメージは仮です。
ソースコード
開発環境は次の通りです。
PC | MacBook Pro(2016年モデル) |
IDE | Android Studio 4.0.1 |
Android SDK | minSdkVersion 16 targetSdkVersion 30 |
言語 | Kotlin 1.3.72 |
package com.sosotata.minesweeper.ui.main
import android.graphics.BitmapFactory
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.Animation
import android.view.animation.ScaleAnimation
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProviders
import com.sosotata.minesweeper.R
import com.sosotata.minesweeper.model.TileController
import com.sosotata.minesweeper.model.TileType
import com.sosotata.minesweeper.ui.widgets.PlayTimeCounter
import kotlinx.android.synthetic.main.game_fragment.*
class GameFragment : Fragment() {
companion object {
fun newInstance() = GameFragment()
}
private lateinit var viewModel: GameViewModel
private var playTimeCounter: PlayTimeCounter? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.game_fragment, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProviders.of(this).get(GameViewModel::class.java)
viewModel.tile = TileController.create(TileType.Square)
viewModel.tile.startedGame = {
playTimeCounter?.start()
}
viewModel.tile.gameOver = {
playTimeCounter?.stop()
animateResetButton {
resetButton.setImageBitmap(BitmapFactory.decodeResource(context?.resources, R.drawable.reset_button_gameover))
}
}
viewModel.tile.clearedGame = {
playTimeCounter?.stop()
animateResetButton {
resetButton.setImageBitmap(BitmapFactory.decodeResource(context?.resources, R.drawable.reset_button_victory))
}
}
viewModel.tile.initialize(requireContext())
playTimeCounter = PlayTimeCounter(playTimer)
squareView.initialize(viewModel.tile)
resetButton.setOnClickListener {
animateResetButton {
viewModel.tile.initialize(requireContext())
squareView.initialize(viewModel.tile)
resetButton.setImageBitmap(BitmapFactory.decodeResource(context?.resources, R.drawable.reset_button_normal))
playTimeCounter?.stop()
playTimeCounter?.reset()
}
}
}
override fun onResume() {
playTimeCounter?.resume()
super.onResume()
}
override fun onPause() {
playTimeCounter?.pause()
super.onPause()
}
private fun animateResetButton(Animated: () -> Unit)
{
val btnEffect = ScaleAnimation(
1.0f, 1.3f, 1.0f,1.3f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f)
btnEffect.duration = 100
btnEffect.setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationStart(animation: Animation) {}
override fun onAnimationRepeat(animation: Animation) {}
override fun onAnimationEnd(animation: Animation) {
Animated()
}
})
resetButton.startAnimation(btnEffect)
}
}
解説
リセットボタンは、#6でアニメーションを使ってボタンっぽいエフェクトをかけています。
ボタンの状態が変わった時にも同じエフェクトをかけたいのでanimateResetButton()を定義して共通処理にします。
private fun animateResetButton(Animated: () -> Unit)
{
val btnEffect = ScaleAnimation(
1.0f, 1.3f, 1.0f, 1.3f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f)
btnEffect.duration = 100
btnEffect.setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationStart(animation: Animation) {}
override fun onAnimationRepeat(animation: Animation) {}
override fun onAnimationEnd(animation: Animation) {
Animated()
}
})
resetButton.startAnimation(btnEffect)
}
そそたた
エフェクトのアニメーション実行後に処理したいことがそれぞれ違うため、引数に関数を指定する形にして対処します。
リセットボタン実行。
resetButton.setOnClickListener {
animateResetButton {
viewModel.tile.initialize(requireContext())
squareView.initialize(viewModel.tile)
resetButton.setImageBitmap(BitmapFactory.decodeResource(context?.resources, R.drawable.reset_button_normal))
playTimeCounter?.stop()
playTimeCounter?.reset()
}
}
ゲームオーバー。
viewModel.tile.gameOver = {
playTimeCounter?.stop()
animateResetButton {
resetButton.setImageBitmap(BitmapFactory.decodeResource(context?.resources, R.drawable.reset_button_gameover))
}
}
ゲームクリア。
viewModel.tile.clearedGame = {
playTimeCounter?.stop()
animateResetButton {
resetButton.setImageBitmap(BitmapFactory.decodeResource(context?.resources, R.drawable.reset_button_victory))
}
}
コメント