Build a scoreboard with running commentary using React VR

build-scoreboard-running-commentary-react-vr-header.png

A tutorial demonstrates how to create a 3D football commentary scoreboard with running commentary using React VR to give sports lovers a unique way to experience the games.

Introduction

Over the years, with the advancement of technology, different breakthroughs have been made in our interaction with computers. The experience that was limited to viewing 2D objects on a screen has evolved to the stage that we have augmented reality and virtual reality, in which we can have an immersive experience in our applications with the help of headsets connected to our machines. We will explore building an application using React VR.

This opens up endless possibilities. It allows users to experience computers and the world like they have never done before. From Virtual Tours of Tourist Centres to magnificent virtual reality games with Oculus and Vives.

In this article, we are going to be looking at how to build a scoreboard with running commentary to give sports lovers a different way to experience games.

Requirements – build-scoreboard-running-commentary-react-vr

To get started, you would need the following:

  • NodeJS and NPM installed locally.
  • Basic knowledge of JavaScript.
  • Knowledge of ReactJS.

When you have the requirements listed above, let’s continue with the article.

Creating the project with React VR

First, we need to install the React VR CLI tool. We will need this to initialize new ReactVR projects. To install the tool, run this command on your terminal:

npm install -g react-vr-cli

Once this is done, we create our simple ReactVR project. To create a ReactVR application run the following command:

react-vr init scoreboard-vr
react-vr init

To start the development server, run this command on your terminal:

1cd scoreboard-vr
2npm start

Now that we have set up the base application, you can view the app here: http://localhost:8081/vr/. This will launch something similar to this:

3D preview

Creating scenery

When you create the project using the init function, some basic files are created by default. Since we are making a scoreboard application, we want to set the scenery. In the index.vr.js replace the contents of the render function with this:

1[...]
2render() {
3return (
4<View style={{
5flex: 1, flexDirection: 'column', width: 2, alignItems: 'stretch'
6}}>
7<Pano source={asset('lille-pitch.jpg')}/>
8</View>
9[...]

We set the source to the image in our static_assets directory . When you visit the app, we have:

Scenery screenshot 1
Scenery screenshot 2

Changing the background

If you wish to change the background, you can do so by placing the image you want in the static_assets folder and then supplying the relative path to the image in the Pano component of your index.vr.js:

1[...]
2<Pano source={asset('relative/file/path')} />
3[...]

Components

For this application, we have one basic component, the commentary component. This component, as the name suggests, is responsible for displaying commentary as the game goes on. Ideally, we can get comments using an API or a service, but in this case, we are going to use some stock JSON data obtained from Goal.com.

Teams component

We create a component that displays the teams, we make a components directory and then create Teams.js in it:

1mkdir components
2touch Teams.js

Our Team component looks like this:

1import React, {Component} from 'react';
2import {
3View,
4Text,
5} from 'react-vr';
6
7export default ({teamA, teamB}) => {
8return (
9<View>
10<Text
11style={{
12backgroundColor: '#777879',
13fontSize: 0.8,
14layoutOrigin: [0.5, 1],
15paddingLeft: 0.1,
16paddingRight: 0.1,
17textAlign: 'center',
18textAlignVertical: 'center',
19transform: [{ translate: [0, 0, -4],}],
20width: '50'
21}}
22>{teamA} vs {teamB} !</Text>
23</View>
24);
25}

In our index.vr.js we use the component:

1[...]
2import Teams from './components/Teams';
3[...]
4export class scoreboard_vr extends React.Component {
5render(){
6[...]
7<Teams teamA={"Losc Lille"} teamB={"Moncao"} />
8[...]
9);
10}

Now when we go back to our app, we have this:

Scoreboard with teams

Commentary component

Our comment component is also a text component, but here, we display the time and what occurred at that time. We make the file by running the following in our components directory:

touch Commentary.js

Our Commentary.js looks like this:

1import React, { Component } from 'react';
2import {
3View,
4Text,
5} from 'react-vr';
6
7export default ({ time, comment }) => {
8return (
9<View>
10<Text
11style={{
12backgroundColor: '#ffffff',
13color : '#333333',
14fontSize: 0.8,
15layoutOrigin: [0.5, 0],
16paddingLeft: 0.2,
17paddingRight: 0.2,
18textAlign: 'center',
19textAlignVertical: 'center',
20transform: [{
21translate: [0, 0, -7]
22}],
23}}
24>{time} - {comment}</Text>
25</View>
26);
27}

Comment model

In our comment model, we have our comments stored in an array as shown in the file below. We create a model directory in the root of our application and then create the comment.js file that is shown below:

1mkdir models
2touch comments.js

Add this code to comment.js file:

1export class Comments {
2comments =
3[
4{
5"time": "1",
6"comment": "Attempt blocked. Falcao (Monaco) right footed shot from the left side of the box is blocked. Assisted by Stevan Jovetic."
7},
8{
9"time": "3",
10"comment": "Foul by Falcao (Monaco)."
11},
12{
13"time": "3",
14"comment": "Ibrahim Amadou (Lille) wins a free kick in the attacking half."
15}, {
16"time": "5",
17"comment": "João Moutinho (Monaco) wins a free kick in the defensive half."
18}, {
19"time": "5",
20"comment": "Foul by Thiago Maia (Lille)"
21}, {
22"time": "5",
23"comment": "Offside, Lille. Yves Bissouma tries a through ball, but Anwar El Ghazi is caught offside."
24}, {
25"time": "24",
26"comment": "Goal! Lille 0, Monaco 1. Stevan Jovetic (Monaco) right footed shot from outside the box to the bottom right corner."
27}, {
28"time": "90",
29"comment": "Match ends, Lille 0, Monaco 4."
30}
31];
32}

Displaying our comments

In our index.vr.js we fetch the comments and then display them via a loop in the view. Instead of displaying all our comments at once, what we can do is to display the comments in particular chunks. In this case we are going to display them four at a time:

1[...]
2import Commentary from './components/Commentary';
3import { Comments } from './models/comments';
4[...]
5export class scoreboard_vr extends React.Component {
6constructor(props) {
7super(props);
8this.state = {
9comment_index: 0,
10};
11}
12
13componentDidMount(){
14let comments = new Comments().comments.length;
15setInterval(() => {
16this.setState({
17comment_index : (this.state.comment_index > comments.length) ? comments.length-4 : this.state.comment_index+3
18})
19}, 5000);
20};
21
22render() {
23let comment_list = new Comments().comments;
24let comment_length = comment_list.length;
25let comments = (this.state.comment_index < comment_length ) ?
26comment_list.slice(this.state.comment_index, this.state.comment_index+3) :
27comment_list.slice(comment_length-1, comment_length);
28return (
29[...]
30{comments.map(function (comment) {
31return <Commentary time={comment.time} comment={comment.comment} />
32})}
33[...]
34);
35}
36};

We first set the comment index to zero and then the final view is updated periodically using the ComponentDidMount method. So if you were fetching your data from an external API, you could keep fetching data and updating by placing the logic to fetch the data in the method.

Board with comments

Styling the Comments

To adjust how close the comment view is to the user, we revisit the commentary component. Instead of making the comments appear so close to the user, we adjust the distance from the user in the styling by changing the Commentary.js component style to :

1[...]
2export default ({ time, comment }) => {
3return (
4[...]
5<Text
6style={{
7backgroundColor: '#ffffff',
8color : '#333333',
9fontSize: 0.8,
10layoutOrigin: [0.5, 0],
11paddingLeft: 0.2,
12paddingRight: 0.2,
13textAlign: 'left',
14textAlignVertical: 'center',
15transform: [{
16translate: [1, 1, -15]
17}],
18width : 15
19}}
20>
21[...]
22</Text>
23[...]
24);
25}

In the above, we set :

transfrom: [{ translate: [1,1, -15]}]

This moves the commentary text to about 15m away from the user and this can be adjusted to fit your preference.

Board repositioned

Conclusion

In this article, we have successfully seen one of the many implementations of React VR and how to use it. Here’s a link to the GitHub repository if interested.