Exploring Canvas in Jetpack Compose — Crafting Graphics, Animations, and Game Experiences | by Nirbhay Pherwani | Sep, 2023
The Canvas
composable isn’t limited to graphics; it’s also used in creating interactive and immersive game experiences directly within your app. Let’s look at a simple game concept — a bouncing ball.
@Composable
fun BouncingBallGame() {
val position = remember { mutableStateOf(Offset(300f, 0f)) }
val velocity = remember { mutableStateOf(Offset(3f, 3f)) }LaunchedEffect(Unit) {
while (true) {
position.value += velocity.value
// change > condition to size of screen,
// here just using a static value for demo purposes
if (position.value.x < 0f || position.value.x > 1000f) {
velocity.value = Offset(-velocity.value.x, velocity.value.y)
}
if (position.value.y < 0f || position.value.y > 1200f) {
velocity.value = Offset(velocity.value.x, -velocity.value.y)
}
delay(16L)
}
}
Column(
modifier = Modifier.background(
brush = Brush.horizontalGradient(
listOf(
Color.Red,
Color.Blue
)
)
)
) {
Canvas(
modifier = Modifier
.height(460.dp)
.fillMaxWidth()
) {
drawCircle(
brush = Brush.horizontalGradient(listOf(Color.Blue, Color.Red)),
center = position.value,
radius = 60f
)
}
Divider(thickness = 5.dp, color = Color.Red)
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Button(
colors = ButtonDefaults.buttonColors(containerColor = Color.Red),
onClick = {
val random = (-1..1).random()
if (random != 0) {
velocity.value += Offset(random * 10f, random * 10f)
}
},
) {
Text(text = "Change Bounce")
}
Text(
text = "Velocity: ${velocity.value.x}, ${velocity.value.y}",
color = Color.White,
)
}
}
}
Key Concepts —
- Position and Velocity State — The ball’s position (
position
) and velocity (velocity
) are defined as mutable state using themutableStateOf
function. Theposition
state variable controls the ball’s movement on the canvas. Velocity does not necessarily need to be a state variable unless we are using it (ex. displaying velocity in aText
).
Text(
text = "Velocity: ${velocity.value.x}, ${velocity.value.y}",
color = Color.White,
)
- LaunchedEffect Animation Loop — The
LaunchedEffect
is used to create an infinite animation loop. Inside the loop, the ball’s position is updated by adding the velocity to it. When the ball reaches the screen edges, its velocity is reversed to simulate bouncing. - Canvas Composable: The
Canvas
composable is used to draw the bouncing ball. ThedrawCircle
function is used to draw the ball at the current position with a gradient brush. - Change Bounce Button — The
Button
allows users to change the ball’s velocity, simulating a change in bounce behavior.