Are you fast and durable enough to defuse a deadly bomb? Let try to create the bomb defusal game with Android Studio and Kotlin! Video tutorial is at the end of the post.

The mechanic
Players need to click as fast as they can to beat the speed of the timer bomb. When the progress goes down to 0, the bomb will be disabled. In contrast, if it reaches the full bar, the bomb will explode, and it will be a very sad day for the player.
The UI
It is a simple design with 3 widgets:
- An image view
- A progress bar
- A start button
The XML should look similar to this:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="@+id/image"
android:layout_width="0dp"
android:layout_height="0dp"
android:src="@drawable/ic_bomb"
app:layout_constraintBottom_toTopOf="@+id/progress"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ProgressBar
android:id="@+id/progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:indeterminate="false"
android:max="100"
android:padding="20dp"
android:progress="0"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.82" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start"
android:onClick="start"
android:background="@drawable/btn"
android:textColor="#FFFFFF"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/progress" />
</androidx.constraintlayout.widget.ConstraintLayout>
The background music
This is optional. However, games should always include music. We will create a flexible service that can change music based on the resource id. The media player is preferable to play longer music files.
//Kotlin Implementation
class BackgroundSoundService : Service() {
var mediaPlayer: MediaPlayer? = null
var soundID: Int = R.raw.grasshopper
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
soundID = intent.getIntExtra("id", R.raw.grasshopper)
mediaPlayer = MediaPlayer.create(this, this.soundID)
mediaPlayer!!.isLooping = false // Set looping
mediaPlayer!!.setVolume(100f, 100f)
mediaPlayer!!.start()
return startId
}
override fun onDestroy() {
mediaPlayer!!.stop()
mediaPlayer!!.release()
}
}
Progressbar Animation
We animate the progress bar when players start the game. And change the colour from Green to Red using a RGB colour filter. The colour will vary based on the value of the current progress.
class ProgressBarAnimation(
private val progressBar: ProgressBar,
var from: Float,
private val to: Float
) : Animation() {
override fun applyTransformation(interpolatedTime: Float, t: Transformation?) {
super.applyTransformation(interpolatedTime, t)
val value = from + (to - from)*interpolatedTime
progressBar.progress = value.toInt()
progressBar.progressDrawable.colorFilter = LightingColorFilter(
Color.rgb(255 * progressBar.progress/progressBar.max,
255 - 255*progressBar.progress/progressBar.max,
0), Color.BLACK
)
}
}
The main activity
We wire up all logics to this class. It should be able to handle the progress bar and also user click. Therefore, we implement two interfaces, i.e, AnimationListener, View.OnClickListener.
class MainActivity : AppCompatActivity(), AnimationListener, View.OnClickListener { ... }
Don’t forget to register the listener to corresponding component. For example, we can register the bomb or the parent view to receive the click and the progresss bar to monitor the animation.
We may need to consider the reset method to put everything in their initial state.
private fun reset() {
startMusic(R.raw.grasshopper)
image.setImageResource(R.drawable.ic_bomb)
progress.setScaleY(3f);
progress.progress = 0
anim = ProgressBarAnimation(progress, 0f, 100f)
anim.setAnimationListener(this)
anim.duration = 2000
button.isEnabled = true
}
Nevertheless, the most important part is how to control user interaction, especially when they click the bomb continuously. We need to reduce the progress by some value and update the animation accordingly.
override fun onClick(p0: View?) {
progress.progress -= 1
if (progress.progress <= 0) {
progress.clearAnimation()
} else {
anim.from = progress.progress.toFloat()
progress.startAnimation(anim)
}
}
Finally, we can make the decision when animation finished, i.e, when the progress reach 0 or full bar.
override fun onAnimationEnd(p0: Animation?) {
if (progress.progress == progress.max) {
Toast.makeText(this, "OMG! You did it!", Toast.LENGTH_LONG).show()
image.setImageResource(R.drawable.ic_explode)
startMusic(R.raw.explosion_1)
progress.setOnClickListener(null)
} else {
Toast.makeText(this, "Woohoo! You finished it!", Toast.LENGTH_LONG).show()
image.setImageResource(R.drawable.ic_melon)
startMusic(R.raw.wow)
}
Handler().postDelayed({reset()}, 10000)
}
Video tutorial
Enjoy the 10 minute video tutorial for the bomb defusal game implementation.
Other useful links
- Other Kotlin tutorial
- Subscribe to Petamind channel
- Github source code