Detect Collision between two Sprites in an Android Kotlin Game
Collision detection in a 2D Android game means checking whether two game objects occupy the same area on the screen. In this Kotlin Android game tutorial, we detect collision between two sprites represented by bitmaps: Grenade and Player.
To detect collision between two Sprites among many of the existing, we have to maintain a list of all the sprites that are drawn on the Canvas, and in every update (of all Sprites) to the Canvas, we have to run a loop among the available Sprites, if there is an overlap.
In our previous Android Game Development tutorial, we have gone to the extent of making the sprites move and responding the sprites to the user input (touch). In this tutorial, we shall learn how to detect collision between the two Sprites, Grenade and Player. This tutorial is built on the previous tutorial, so you may have a look at it.
The method used here is rectangle-based collision detection. It is also called bounding box collision detection. It is simple, fast, and suitable for many beginner 2D games where each sprite can be approximated by a rectangle.
How rectangle collision detection works for Android sprites
Every bitmap sprite has a position and size. If the sprite is drawn at x and y, and its bitmap has width w and height h, the rectangular area covered by the sprite can be represented as:
- left:
x - top:
y - right:
x + w - bottom:
y + h
Two sprites collide when their rectangles overlap. Android provides the Rect class, so we can create one rectangle for the grenade and one rectangle for the player, then check whether they intersect.
Following is a step by step guide.
Step 1: Get Rectangles from your Sprites.
val grenadeRect: Rect = Rect(grenade.x, grenade.y, grenade.x+grenade.w, grenade.y+grenade.h)
val playerRect: Rect = Rect(player.x, player.y, player.x+player.w, player.y+player.h)
Step 2: Check for Intersection.
val grenadeRect: Rect = Rect(grenade.x, grenade.y, grenade.x+grenade.w, grenade.y+grenade.h)
val playerRect: Rect = Rect(player.x, player.y, player.x+player.w, player.y+player.h)
if(grenadeRect.intersect(playerRect)){
collided=true
System.out.println("Collided.")
}
Step 3: Update the Sprites based on the “collided” status.
Use Rect.intersects() when you only want to test sprite overlap
The earlier code uses grenadeRect.intersect(playerRect). It detects overlap, but it can also modify the rectangle on which it is called. When you only want a true or false collision result, the static Rect.intersects(rect1, rect2) method is usually clearer.
val grenadeRect = Rect(
grenade.x,
grenade.y,
grenade.x + grenade.w,
grenade.y + grenade.h
)
val playerRect = Rect(
player.x,
player.y,
player.x + player.w,
player.y + player.h
)
val collided = Rect.intersects(grenadeRect, playerRect)
You can then use collided to stop the game, reduce health, play a sound, show a game over screen, or reset the sprite position.
Add sprite collision detection inside the GameView update loop
Collision detection should usually run after the sprites update their positions and before the frame is drawn. In this example, the grenade position is updated first. If the player is being touched, the player position is updated. Then the two rectangles are compared.
private var collided = false
fun update() {
grenade?.update()
if (touched) {
player?.updateTouch(touched_x, touched_y)
}
val currentGrenade = grenade
val currentPlayer = player
if (currentGrenade != null && currentPlayer != null) {
val grenadeRect = Rect(
currentGrenade.x,
currentGrenade.y,
currentGrenade.x + currentGrenade.w,
currentGrenade.y + currentGrenade.h
)
val playerRect = Rect(
currentPlayer.x,
currentPlayer.y,
currentPlayer.x + currentPlayer.w,
currentPlayer.y + currentPlayer.h
)
collided = Rect.intersects(grenadeRect, playerRect)
}
}
This example uses safe nullable checks instead of force-unwrapping with !!. That makes the game loop less likely to crash if a sprite is not initialized yet.
Expose sprite bounds from each Kotlin game object
As the game grows, it is better to keep rectangle creation inside each sprite class. This keeps GameView cleaner and avoids repeating the same bounds code for every sprite.
import android.graphics.Rect
fun getBounds(): Rect {
return Rect(x, y, x + w, y + h)
}
If both Grenade and Player expose a getBounds() function, the collision check becomes shorter.
val collided = Rect.intersects(
grenade.getBounds(),
player.getBounds()
)
This approach also makes it easier to add more enemies, coins, bullets, walls, or power-ups later.
Detect collision among many sprites in a Kotlin Android game
When there are only two sprites, one collision check is enough. When the game has many sprites, you can keep related sprites in a list and loop through them. For example, a player may collide with many grenades.
for (grenade in grenades) {
if (Rect.intersects(player.getBounds(), grenade.getBounds())) {
collided = true
break
}
}
This is simple and readable for a small game. For a larger game with hundreds of moving objects, checking every sprite against every other sprite can become expensive. In that case, you can first do a broad check using simple rectangles, and only then do more detailed checks for the objects that are close enough to collide.
Rectangle collision, circle collision, and pixel-perfect collision for bitmaps
There are different ways to detect collision between sprites. The right method depends on the shape of the game objects and how accurate the collision needs to feel.
| Collision method | Best used when | Trade-off |
|---|---|---|
| Rectangle collision | Sprites are box-shaped or approximate accuracy is acceptable | Fast and simple, but can detect collision in transparent corner areas of a bitmap |
| Circle collision | Objects are round, such as balls, bubbles, or circular players | Simple and often more natural for round sprites, but not suitable for long or irregular shapes |
| Pixel-perfect collision | The visible pixels of the bitmap must match very closely | More accurate, but slower and more complex than rectangle checks |
For the grenade and player example, rectangle collision is enough to learn the concept. If your bitmap has large transparent areas, rectangle collision may feel unfair because the invisible part of the bitmap is still included in the rectangle. In such cases, use a smaller hitbox or consider pixel-level collision after a rectangle check confirms that the sprites overlap.
Circle collision detection for round Android sprites
If both sprites are round, you can compare the distance between their center points. A collision happens when the distance between centers is less than or equal to the sum of the two radii.
import kotlin.math.sqrt
fun areCirclesColliding(
x1: Float,
y1: Float,
radius1: Float,
x2: Float,
y2: Float,
radius2: Float
): Boolean {
val dx = x1 - x2
val dy = y1 - y2
val distance = sqrt(dx * dx + dy * dy)
return distance <= radius1 + radius2
}
This method works well when your player sprite is a circle. For faster code, you can compare squared distance and avoid calling sqrt(), but the above version is easier to read for beginners.
Pixel-perfect collision detection for Android bitmaps
Pixel-perfect collision detection checks whether the non-transparent pixels of two bitmaps overlap. This is useful when the sprite shape is irregular and rectangle collision is too rough.
A common practical approach is:
- First run a fast rectangle collision check.
- If the rectangles do not overlap, there is no collision.
- If the rectangles overlap, check only the overlapping area at pixel level.
- Treat two pixels as colliding only when both pixels are visible enough, usually by checking their alpha values.
Pixel-perfect checks can be expensive if they run for many sprites on every frame. Use them only where the extra accuracy matters.
Show a basic game over response after sprite collision
After detecting collision, decide what should happen in the game. In a simple avoid-the-grenade game, you may stop movement and draw a game over message.
override fun draw(canvas: Canvas) {
super.draw(canvas)
grenade?.draw(canvas)
player?.draw(canvas)
if (collided) {
val paint = Paint()
paint.textSize = 64f
canvas.drawText("Game Over", 80f, 120f, paint)
}
}
If you add this example to your project, import android.graphics.Paint. In a complete game, you may also pause the thread, show a restart button, update score, or navigate to a separate result screen.
Common mistakes in Android sprite collision detection
- Checking collision before updating positions: This can make the game react one frame late.
- Using full bitmap bounds for transparent images: The player may appear to collide before visible pixels touch. Use a smaller hitbox if needed.
- Creating too many objects in every frame: Creating new
Rectobjects repeatedly is fine for a beginner example, but larger games should reuse objects where practical. - Forgetting null checks: Collision code can crash if a sprite has not been created before the update loop runs.
- Using one collision method for every shape: Rectangles, circles, and pixel-perfect checks each fit different sprite shapes.
QA checklist for this Android bitmap collision tutorial
- Both
GrenadeandPlayerexpose their currentx,y, width, and height values correctly. - The rectangle uses
x + wfor right andy + hfor bottom. - The collision check runs after sprite position updates inside the game loop.
- The project uses
Rect.intersects()when the rectangle should not be modified. - The player and grenade bitmap resources are loaded before collision checks run.
- The collision response is visible in the game, such as game over text, score change, or sprite reset.
- Transparent bitmap padding is considered when testing whether the collision feels correct.
- The game is tested on a real Android device with touch movement and moving sprites.
FAQ on collision detection between Android sprites
How do you create collision detection in a 2D Android game?
Create a shape that represents each sprite, such as a rectangle or circle. Update the sprite positions, compare the shapes for overlap, and then run a game response if collision is detected.
What is the simplest collision method for two bitmap sprites?
Rectangle collision is the simplest method. Create a Rect around each bitmap and use Rect.intersects() to check whether the two rectangles overlap.
When should I use pixel-perfect collision in an Android game?
Use pixel-perfect collision when the sprite has an irregular shape and rectangle collision feels inaccurate. For performance, first check rectangle overlap and run pixel-level checks only inside the overlapping area.
Why does my sprite collide before the images visually touch?
This usually happens when the bitmap has transparent padding. The rectangle includes the transparent area too. Crop the image, use a smaller hitbox, or use a more accurate collision method.
Should collision detection run in update() or draw()?
Collision detection should generally run in update(), after movement is calculated. The draw() function should mainly render the current game state on the Canvas.
Conclusion: Detecting collision between two bitmap sprites in Kotlin
In this Kotlin Android Tutorial, we have learnt to detect collision between two sprites. We used Android Rect objects to represent the bounds of two bitmaps and checked whether those rectangles overlap.
Rectangle collision detection is a good first method for Android game development because it is easy to understand and fast to run. As your game improves, you can use smaller hitboxes, circle collision, or pixel-perfect collision for sprites that need more accurate interaction.
TutorialKart.com