Scope

In this tutorial, we are going to learn how animations work in ReactVR. Even though animations are fairly simple, for some one coming from a non-3D/VR background, it can seem quite an uphill task! To begin, it is essential to understand quickly the basics of ReactVR Animations and the Animated API.

Let’s start by setting up a starter project where we create a hopping animation on a 3D object, and work our way up from there.

Creating a New Project

Let’s create a new project called AnimatedHotspot according to the project setup guide here.

Run the following in a terminal:

react-vr init AnimatedHotspot

To start the application, cd into the project folder and run npm start and open up http://localhost:8081/vr in your browser.

Once that is finished, open the project folder in an editor of your preference and open index.vr.js.

Adding the Animated Components

Once the above setup is up and running, it is time to add an animated component to our scene. Let’s create a new component called Hotspot in a separate file named Hotspot.js.

import React from 'react';
import { Animated, Image, VrButton, View } from 'react-vr';
import Easing from 'Easing';

export default class Hotspot extends React.Component {
  static defaultProps = { position: [0, 0, -10], rotation: [0, 90, 0], iconURL: '' };

  constructor(props) {
    super(props);
    this.state = Object.assign({}, this.props);
  }

  render() {
    return (<VrButton style={{
      position: 'absolute',
      width: 1,
      height: 1,
      transform: [{ rotateY: this.state.rotation[1] }, { rotateX: this.state.rotation[0] }, { rotateZ: this.state.rotation[2] }, { translate: this.state.position }],
    }}><Imagestyle={{ width: 1, height: 1, transform: [{ scale: 0.7 }] }} source={{ uri: this.state.iconURL }}></Image></VrButton>);
  }
}

Now that we have our Hotspot component setup, let’s include it into our Scene. Inside index.vr.js add:

import Hotspot      from './Hotspot';

...
render() {
  return (
    <View>
      <Pano source={asset('chess-world.jpg')}/><Hotspot/>
    </View>
  );
}

You should be able to see something like this in the browser:

Animate!

We have now successfully added a hotspot to our scene. Now it’s time for the fun stuff — the animations. ReactVR animation supports View, Text and Image components out of the box, but any component can be converted into an animatable component by using the Animated API. Let’s replace our Image component by Animated.Image.

<Animated.Image 
  style={{ 
    width: 1, 
    height: 1, 
    transform: [{ 
      scale: 0.7 
    }] 
  }}
  source={{ uri: this.state.iconURL }}>
</Animated.Image>;

We will now add a hopping animation to the hotspot. This animation composes of two separate animations. Consider raising a ball to a certain height above ground level and then dropping it. This will produce a bouncing effect on the ball when it hits the ground. Let’s break this into 2 separate animations — first, raise the hotspot to a certain height and second, drop it back to the starting position from there. This means, we will be working with the translateY value of the transform, raising the hotspot to a +ve Y value and then dropping it from there.

Append the following code to your Hotspot.js file:

constructor(props);
{
  super(props);
  this.state = Object.assign({}, this.props, { translateValueY: new   Animated.Value(0) });
}
...
<Animated.Image 
  style={{
    width: 1, 
    height: 1, 
    transform: [{ 
      translateY: this.state.translateValueY 
    }, {
      scale: 0.7 
    }] 
  }}
  source={{ uri: this.state.iconURL }}>
</Animated.Image>;

We have basically set our translateY value to an instance of Animated object and this is the value that we animate. NOTE: Animate.Value(x) works only with Animated components(Text, Image, View). We will cover how to create custom animated components in a separate tutorial.

Next up, starting the animation. Create a new function named animate and call this function from componentDidMount.

componentDidMount() { 
  this.animate();
}

Inside the animate function add the following:

Animated.sequence([
  Animated.timing(
    this.state.translateValueY, {
      toValue: 0.1,
      duration: 200,
    }),
  Animated.timing(
    this.state.translateValueY, {
      toValue: 0,
      duration: 900,
      easing: Easing.elastic(6),
    })]).start(() => {
  this.animate();
});

What we do here is, run two separate animations in a sequence, raise the hotspot to 0.1 M and then drop it back to 0M. We use an Elastic easing function here to represent the bounciness. And finally when the sequence of animation is complete, we restart it in the start callback handler.

You should finally see something like this.

See it in action here.



How do you animate your components? I’d love to discuss below!

Tags