Creating a particle explosion animation in Jetpack Compose

Animations play a crucial role in bringing any user interface to life. They not only make the user interface more visually appealing but also provide feedback to the user, creating a more engaging experience

In this article, we'll explore how to create such particle explosion effect using jetpack compose, without relying on any external dependencies

We'll take a step-by-step approach, breaking down each stage of the animation, understanding the underlying physics and mathematics involved, and translating those concepts into code

So, let's dive in!

Anatomy of an explosion

In a typical explosion, a sudden release of energy throws debris into the air which consists of elements of varying sizes that are propelled in all directions.

Each particle is then pulled downwards by gravity, resulting in it following a parabolic trajectory before ultimately falling back down to the ground.

When the particle moves upward, the gravitational acceleration acts in the opposite direction, leading to a change in its velocity over time

To better understand this concept, consider this moving sledge as an example

Initially, the sledge is moving steadily to the right with a constant velocity. When the boosters are activated in the opposite direction, the sledge experiences a net force in the opposite direction, which causes it to undergo negative acceleration

Eventually, the sledge comes to a complete stop, having zero velocity. As time passes, the sledge experiences a displacement in the left direction and starts moving in the opposite direction

Similarly, in our scenario, gravity provides a net force in the downward direction to our particle, which causes it to slow down and eventually stop momentarily before it starts accelerating in the opposite direction.

Particle explosion

With this in mind, let's plot the trajectory of a single particle on a 2D canvas.

We will write some basic compose code, to begin with.

The Explosion composable utilizes a canvas to draw the particle trajectory. It also draws the X and Y axis along with a thin border and takes a progress argument as an input ranging between 0 to 1

The ControlledExplosion composable then simply wraps the Explosion composable, allowing us to precisely control the explosion progress using a Slider

To control the position of the particle on the canvas, we pass an Offset with X and Y coordinates to the center parameter of the drawCircle() function

Considering velocity sizePx/unit and time controlled by the Slider progres, the distance travelled by a particle with constant velocity in a fixed time is given by:

distance = velocity * time = sizePx * progress

By default, the canvas draws every element from the top-left corner, where the coordinates (0,0) are located

But if we want the particle to start from the center, we need to add sizePxHalf to both the X and Y coordinates

Also, when calculating the Y displacement value, we need to subtract it instead of adding it to ensure that the particle goes up instead of down

Perfect, Now let's consider the effect of gravity on the particle

To calculate the vertical displacement of the particle with constant velocity and acceleration due to gravity, we can use the second kinematic motion equation

s = ut + 0.5at^2

where

  • s = displacement (distance from initial position)

  • u = initial velocity

  • a = constant acceleration

  • t = time

Here's how the updated code looks like

We still need to determine the velocity and acceleration of the particle based on maximum height it can reach.

So let's derive the formula using the variables in control i.e. displacement and time, from the fact that

  1. The particle returns to its original position after time t

  2. The velocity on reaching maximum height is 0

Similarly, we know that the acceleration is the change in velocity over time

With this in place, the particle moves in a nice parabolic trajectory

To increase the number of particles, we create a Particle class to hold the state of each particle, including color, X & Y coordinates, and other properties

We also add some variation to maxHorizontalDisplacement and maxVerticalDisplacement for each particle so that it follows its own trajectory
This variation is randomized to provide diversity in each particle's path, producing a more realistic effect

And finally, let's assign each particle a random color

Here's our updated code with a separate Particle class

Now, Let's perform some additional tweaks to the animation

Firstly, we want the particle to travel beyond its final position. To achieve this, we can increase the particle's max travel time (1s) by adding an arbitrary value of 0.4s

Furthermore, even though the particles are moving along their designated trajectory, the overall explosion still looks quite uniform. To create a more realistic explosion effect, we can introduce randomness by adjusting each particle's start and end time.

visibilityThresholdLow is a delay that each particle experiences before it starts its motion relative to the explosion progress. Its value ranges between 0 and 0.14, representing a fraction of the overall animation progress. This parameter improves the initial animation by allowing the particles to appear more like they are being sprayed out, rather than all starting to move at the same time

Another parameter, visibilityThresholdHigh, determines the end gap between the animation progress and particle progress

Consider an example where the value of visibilityThresholdLow is 0.1 and visibilityThresholdHigh is 0.4. In this case, the particle will complete its trajectory from 0 to 1, as the animation progresses from 0.1 to 0.6 (1 - 0.4), and otherwise remain invisible

Overall, the parameters visibilityThresholdLow and visibilityThresholdHigh create a more realistic explosion effect by introducing randomness by controlling the start and end time of each particle's trajectory

Here's the updated Particle class

How can we make further improvements to our animation?

Let's examine additional characteristics of a real explosion

Upon closer inspection, we can notice some differences from our current animation

  1. The debris does not originate from a single center point

  2. As the debris moves closer or farther from the viewer, it seems to alter in size

  3. Certain debris disappears while in mid-air

Let's try to bring these changes to our animation

We can assign a random initialDisplacement ranging randomly between -10dp to 10dp to each particle so it doesn't start from the center

val initialDisplacement = 10.dp.toPx() * randomInRange(-1f, 1f)

To vary particle size over time, we first set the initial radius of all particles to 2dp

Then, we split the particles into two groups. The minority group (20%) expands from 2dp to a random size between 2dp and 7dp during the explosion. The majority group, on the other hand, gradually decreases their radius from 2dp to a random value between 1dp and 2dp

This simple adjustment gives the impression of 3D movement, as if the particles are also travelling on the Z-axis

Finally, we adjust the particles' transparency so that as they move towards the end of their trajectory (70% to 100%), their transparency decreases gradually (100% to 0%), producing a fade out effect

Here's our final Particle class

In the next part, we will develop a library based on this explosion animation

Stay tuned!

Thanks to Rocket Sled and ExplosionField

Check out ExplodingComposable on Github