React Native Animated in JavaScript Game

React Native Animated library is a simple, but powerful tool to manage animation. I highly recommend you to read the official documentation to catch the basics. Not right now, but definitely a must-read.

In this post, we will discuss easy and cute transformation examples based on one small piece from my hobby-programming indie game. From time to time I do some primitive games in JS and Elm because it is fun and I can learn something new. Let’s begin!

Water planet

For such a small topic, I don’t think, it’s really necessary to talk about the game itself. Just know, that in the game there are such elements as planets. Planets flying in the space, surround the main character and compose the game world: Stone planet, Ice planet, Electro planet, Lava planet, Cloud planet and finally Water planet.

Design and Art-work by El’tons Studio

Before this tropical style, I have been thinking about something more dark, dangerous and silent like the ocean of Lem’s Solaris (highly recommend reading this novel as well). But the concept was changed and finally, I end up with mini-Hawaii. Hard world of indie game dev. ¯\_(ツ)_/¯

Animation of Breathe

Without movements, Water planet just a boring, static image. The game should be as much fun as possible, so I definitely need to breathe life into game objects. Actually, breathing is a good idea for Water planet animation, is not it? Let’s do it!

“Breathing” is quite an easy thing. All we need is to change the size of the object from the original value to something a bit bigger and get back to the original size. We should do this again and again in an infinite loop. The simplest implementation of “breathing” is:
1) Transform size from 1 to 1.X in some period of time
2) Transform size from 1.X back to 1 in the same period of time
3) Loop these steps

Explanation

I hope example looks very easy to understand. But anyway, let me repeat how animation works.

The top-level Animated.sequence build a composition of 2 animations and declares that they going to be executed sequentially (the second animation will be executed right after the first one).

First Animated.timing manage a scaleValue from the state with a duration of 1.5 seconds in an Easing.linear manner changes the value from the initial 1 to 1.2 (toValue).

Second Animated.timing animation change scaleValue from planned 1.2 back to 1.

As a callback of the start method, we do a call of waterAnimation to start the animation again (this is how we do the loop).

Interpolation

We can change the current implementation with the usage of interpolation.

Interpolation gives us the ability to segregate animated value (scaleValue) and map it before component uses this value. Interpolation is a very simple but powerful concept.

const [scaleValue] = useState(new Animated.Value(0))scale: scaleValue.interpolate({
inputRange: [0, 0.5, 1],
outputRange: [1, 1.2, 1]
}

With interpolation, we can project real scaleValue to some another value we want to set for the component. For example, we can let scaleValue changes from 0 to 1 but set to component scale property values as we want: 1 and 1.2 instead. Catch the idea? Here is the full implementation.

You can also notice, that now first animation is playing the whole breathing (up and down in 3 seconds), while the second animation is just an immediate reset of scaleValue to original zero.

Better Animation of Breathe

Animation works, it is a good starting point, but… it looks a bit cheap and fake. Why fake?

From the point of Physics, we have a problem! Let’s think for a moment, when the planet getting bigger, for example, trees on it or clouds in the sky, also become bigger? Of course, not :-)

Let’s try to make animation more realistic. To be honest, we should scale only the planet’s globe and let islands and clouds drift on top of the surface.

I am not sure, but I also think that clouds should move a bit less, than islands. They are not in the water, but in the atmosphere, so they less affected from the planet breathing. Maybe it’s too aggressive requirements for such a small game object, but we want to have some fun!

Game objects with layers

Instead of one single image, I need seven now: 1 for planet globe, 3 for each island and 3 for each cloud.

It is important to think in advance about every significant object’s element. If you plan to move, hide, swap, scale or whatever — you better to have separate images. It will allow you to disassemble objects on pieces and even try new animation ideas in the future.

Each image is a separate layer. In my real game, I have even extra layers for islands: sand, water glow, and jungle — all separated. Who knows what I will need to do in the future? I have many images for my game objects and I can merge layers into one file picture any time I want.

Implementation

Once again: the globe is still scaling as before, but islands and clouds are only moving without scaling. Clouds move less than islands.

We will change the position of islands and clouds via transform TranslateX and TranslateY configurations.

We can reuse the first implementation with a mapping of animationValue (renamed from scaleValue) as a single animation value source for different outputs for each of our layers.

Seven projections in each image to scale globe, moving islands and clouds. When I said “projection”, as you understand, I mean React Native interpolation.

As you may notice, I also played a bit with duration and delay. The configuration with delay gives me the ability to take a little pause before the next breath. Looks very smooth and nice.

Results

The road from idea to implementation successfully passed with regards by React Native Animated library. I am satisfied with the results: Water planet breathing “correctly” and looks cute enough.

The balance between the imagination of what you want & understanding of how to create it — is an essential part of indie game development and any other development process.

This is how Water planet currently animated in my game

Homework

Small homework for all, who want to try game-developer skills: try to make a random breathing. For example, take 2 breaths one by one, then paused, then take 1 breath, paused, then 3 breaths, paused and so on randomly from 1 to 3 breaths. Sounds fun!

Feel free to share your questions and results in comments. Happy coding!

References

Engineering Technical Lead @ Agoda. Neo4j Featured Community Member. Certified Neo4j Professional. Articles brewed on web, hops and indie rock’n’roll.