Creating a Car Game in React - Part 6 - Adding High Scores
Tags: gamedev, react, azure, dotnet
Published: 2019-09-06 06:35:41

---
title: Creating a Car Game in React - Part 6 - Adding High Scores
published: true
description: Creating a Car Game in React - Part 6 - Adding High Scores
tags: Game Development, ReactJS, Azure, DotNet
---

<link rel="canonical" href="https://www.pmichaels.net/2019/08/31/creating-a-car-game-in-react-part-6-adding-high-scores/" />

This is the sixth post of a series that starts <a href="https://www.pmichaels.net/2019/06/03/creating-a-car-game-in-react-part-1-drawing-and-moving/">here</a>.

As with previous posts, if you wish to download the code, it's <a href="https://github.com/pcmichaels/ReactTransAm/tree/Part-Six">here</a>; and, as with previous posts, I won't cover all the code changes here, so if you're interested, then you should download the code.

In this post, we're going to create a High Score table.  We'll create an Azure function as the server, and we'll store the scores themselves in Azure Tables.

Let's start with the table.

Create a new storage account in Azure, then add an Azure Table to it:

<a href="https://www.pmichaels.net/wp-content/uploads/2019/08/trans-am-1.png"><img src="https://www.pmichaels.net/wp-content/uploads/2019/08/trans-am-1.png" alt="" width="1580" height="778" class="alignnone size-full wp-image-3870" /></a>


You'll see a sign trying to persuade you to use Cosmos DB here.  At the time of writing, using Cosmos was considerably more expensive than Table Storage.  Obviously, you get increased throughput, distributed storage, etc with Cosmos.  For this, we don't need any of that.

Create a new table:

<a href="https://www.pmichaels.net/wp-content/uploads/2019/08/trans-am-2.png"><img src="https://www.pmichaels.net/wp-content/uploads/2019/08/trans-am-2.png" alt="" width="1014" height="331" class="alignnone size-full wp-image-3869" /></a>

An Azure table is, in fact, a No SQL offering, as you have a key, and then an attribute - the attribute can be a JSON file, or whatever you choose.  In our case, we'll set the key as the user name, and the score as the attribute.

Once you're created your table storage, you may wish to use the <a href="https://azure.microsoft.com/en-gb/features/storage-explorer/">Storage Explorer</a> to create the tables, although that isn't necessary.

Finally, you'll need to add a CORS rule:

<a href="https://www.pmichaels.net/wp-content/uploads/2019/08/trans-am-3.png"><img src="https://www.pmichaels.net/wp-content/uploads/2019/08/trans-am-3.png" alt="" width="1527" height="349" class="alignnone size-full wp-image-3868" /></a>

Obviously, this should actually point to the domain that you're using, rather than a blanket 'allow', but it'll do for testing.


<h1>Adding a username</h1>

Before we can store a high score, the user needs a username.  Let's add one first.

In game status, we'll add a text box:

    <div style={containerStyle}>
    	<input type='text' value={props.Username} onChange={props.onChangeUsername} />
</div>

The state is raised to the main Game.jsx:

    <GameStatus Lives={this.state.playerLives} 
    	Message={this.state.message} 
    	Score={this.state.score} 
    	RemainingTime={this.state.remainingTime}
    	Level={this.state.level}
    	Username={this.state.username} 
    	onChangeUsername={this.onChangeUsername.bind(this)} 
    />

And onChangeUsername is here:

    onChangeUsername(e) {
    	this.updateUserName(e.target.value);
    }

    updateUserName(newUserName) {
    	this.setState({
    		username: newUserName
    	});
    }

<h1>Update High Score</h1>

We'll create an Azure Function to update the table.  In Visual Studio, create a new Windows Azure Function App (you will need to install the <a href="https://www.pmichaels.net/2017/09/17/function-apps-azure/">Azure Workload</a> if you haven't already):

<a href="https://www.pmichaels.net/wp-content/uploads/2019/08/trans-am-5.png"><img src="https://www.pmichaels.net/wp-content/uploads/2019/08/trans-am-5.png" alt="" width="1280" height="888" class="alignnone size-full wp-image-3866" /></a>

You'll be asked what the trigger should be for the function: we'll go with <em>HttpTrigger</em>.  This allows us to call our function whenever we please (rather than the function, being say <a href="https://www.pmichaels.net/2018/02/11/creating-scheduled-azure-function/">scheduled</a>.)  Next, we'll need to install a NuGet package into our project to let us use the Azure Storage Client:

    Install-Package WindowsAzure.Storage

We need some access details from Azure:

<a href="https://www.pmichaels.net/wp-content/uploads/2019/08/trans-am-6.png"><img src="https://www.pmichaels.net/wp-content/uploads/2019/08/trans-am-6.png" alt="" width="1638" height="762" class="alignnone size-full wp-image-3865" /></a>

<h2>Creating the Functions</h2>

We're actually going to need two functions: update and retrieve (we won't be using the retrieve in this post, but we'll create it anyway).  Let's start with a helper method:

    public static class StorageAccountHelper
    {
        public static CloudStorageAccount Connect()
        {
            string accountName = Environment.GetEnvironmentVariable("StorageAccountName");
            string accountKey = Environment.GetEnvironmentVariable("StorageAccountKey");

            var storageAccount = new CloudStorageAccount(
                new Microsoft.WindowsAzure.Storage.Auth.StorageCredentials(
                    accountName, accountKey), true);
            return storageAccount;
        }
    }

For testing purposes, add the account name and key into the local.settings.json:

    {
      "IsEncrypted": false,
      "Values": {
        "AzureWebJobsStorage": "UseDevelopmentStorage=true",
        "FUNCTIONS_WORKER_RUNTIME": "dotnet",
        "StorageAccountName": "pcmtest2",
        "StorageAccountKey": "C05h2SJNQOXE9xYRObGP5sMi2owfDy7EkaouClfeOSKRdijyTQPh1PIJgHS//kOJPK+Nl9v/9BlH4rleJ4UJ7A=="
      }
    }


The values here are taken from above - where we copied the access keys from Azure (whilst these keys are genuine keys, they will be changed by the time the post is published - so don't get any ideas!

First, let's create a function to add a new high Score:


        [FunctionName("AddHighScores")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            var newScore = new HighScore(req.Query["name"], int.Parse(req.Query["score"]));            

            var storageAccount = StorageAccountHelper.Connect();

            CloudTableClient client = storageAccount.CreateCloudTableClient();
            var table = client.GetTableReference("HighScore");

            await table.ExecuteAsync(TableOperation.InsertOrReplace(newScore));

            return new OkResult();
        }

If you've seen the default example of this function, it's actually not that different: it's a POST method, we take the <em>name</em> and <em>score</em> parameters from the query string, build up a record and add the score.  The function isn't perfect: any conflicting names will result in overwritten score, but this is a copy of a spectrum game - so maybe that's authentic!

The second function is to read them:

        [FunctionName("GetHighScores")]
        public static async Task<IList<HighScore>> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            var storageAccount = StorageAccountHelper.Connect();

            CloudTableClient client = storageAccount.CreateCloudTableClient();
            var table = client.GetTableReference("HighScore");
            var tq = new TableQuery<HighScore>();
            var continuationToken = new TableContinuationToken();
            var result = await table.ExecuteQuerySegmentedAsync(tq, continuationToken);
            
            return result.Results;
        }

All we're really doing here is reading whatever's in the table.  This might not scale hugely well, but again, for testing, it's fine.  The one thing to note here is <em>ExecuteQuerySegmentedAsync</em>: there seems to be very little documentation around on it; and what there is seems to refer to <em>ExecuteQueryAsync</em> (which, as far as I can tell, doesn't, or at least, no longer, exists).

Let's run the Azure function locally and see what happens:

<a href="https://www.pmichaels.net/wp-content/uploads/2019/08/trans-am-7.png"><img src="https://www.pmichaels.net/wp-content/uploads/2019/08/trans-am-7.png" alt="" width="1103" height="639" class="alignnone size-full wp-image-3864" /></a>


As you can see, Azure helpfully gives us some endpoints that we can use for testing.  If you don't have a copy already, then download <a href="https://www.getpostman.com/">Postman</a>.  Here you can create a request that calls the function.

I won't go into the exact details of how Postman works, but the requests might look something like this:

    http://localhost:7071/api/AddHighScores?name=test2&score=19


    http://localhost:7071/api/GetHighScores?10


To prove to yourself that they are actually working, have a look in the table.

<blockquote>
There is now an online Storage Explorer in the Azure Portal.  Details of the desktop version can be found in <a href="https://www.pmichaels.net/2017/08/13/creating-basic-azure-web-job/">this post</a>.
</blockquote>


<a href="https://www.pmichaels.net/wp-content/uploads/2019/08/trans-am-8.png"><img src="https://www.pmichaels.net/wp-content/uploads/2019/08/trans-am-8.png" alt="" width="1628" height="430" class="alignnone size-full wp-image-3863" /></a>


<h2>Update High Score from the Application</h2>

Starting with adding the high score, let's call the method to add the high score when the player dies (as that's the only time we know what the final score is):

    playerDies() { 
        this.setState({
            playerLives: this.state.playerLives - 1,
            gameLoopActive: false
        });
    
        if (this.state.playerLives <= 0) {
            this.updateHighScore();
            this.initiateNewGame();
        } else {
            this.startLevel(this.state.level);
        }
    
        this.repositionPlayer();
        this.setState({ 
            playerCrashed: false,
            gameLoopActive: true
        });
    }

The updateHighScore function looks like this:

    updateHighScore() {
    	fetch('http://localhost:7071/api/AddHighScores?name=' + this.state.username + '&score=' + this.state.score, {
    		method: 'POST'
    	}); 
    }

Note (obviously) that here I'm updating using my locally running instance of the Azure Function.

And that's it - we now have a score updating when the player dies.  Next we need to display the high scores - that'll be the next post.


<h1>References</h1>

<a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch">https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch</a>

<a href="https://facebook.github.io/react-native/docs/network">https://facebook.github.io/react-native/docs/network</a>

This was originally posted <a href="https://www.pmichaels.net/2019/08/31/creating-a-car-game-in-react-part-6-adding-high-scores/">here</a>.