Build a Multiplatform Quiz Game with Unity 3D and Syncano

Sebastian SztangierskiSebastian Sztangierski

Learn how to create a ‘Who Wants To Be A Millionaire’ style game in Unity with the Syncano platform as backend.

Have you ever wondered what it would be like to have your own version of the ‘Who Wants To Be A Millionaire’ show? If so, then you will find this blog post useful, as it covers all the basics of creating such an application to be deployed on Android, iOS, PC and WebGL!

In this tutorial we use the Unity3D free edition as the game engine for our frontend and Syncano as the backend for performing operations on data. Unity3D is a cross-platform game engine used to develop video games for PC, consoles, mobile devices and websites. According to Unity resources, it has over 5.5 million registered users and over 770 million people playing Unity-made games.

Unity offers a powerful set of tools for networking. However, the built-in networking doesn’t always meet our requirements because it has, for example, some restrictions when using WebGL or simply because we need a different approach when transferring data between various devices. Another advantage of using an external backend is how data is managed. Syncano, for instance, has an intuitive Dashboard for data administration. Managing data directly from the Dashboard is convenient, especially when the application is in the prototype phase and there is a need for prototyping data schemas within a short time. There‘s even more that Syncano offers. For example, Scripts are a powerful tool that can handle complex logic from server-side. Syncano has many more benefits, so let’s get started!

Tutorial

Requirements

For a desktop/WebGL build, we only need to install the Unity3D free edition version 5.4.0f3 or higher. Download it here!

Table of Contents

  1. Create a Class
  2. Get the Syncano Quiz App Repository
  3. Working with Syncano Scripts
  4. Connecting Unity with Syncano
  5. How It Actually Works
  6. Moderating Questions
  7. Unity Syncano API Examples

Create a Class

The first thing we need to do is to log in to the Dashboard and create a template Class for questions that will appear later in the application. A template is actually a schema that defines a structure and all fields in a Data Object. Follow all the steps below in order to go to the next phase.

  1. Go to https://www.syncano.io/ and press the SIGN UP button located at the top right corner and create a new account.
  2. Log in to the Dashboard.
  3. Add a new Instance.
  4. Select your Instance and go to the Classes panel from the left sidebar.
  5. Click the ADD button located at the top right corner.
  6. Create a Class named ‘question’ and add fields that match the screenshot below.

Get the Syncano Quiz App Repository

  1. Download the Syncano quiz repository from our Syncano Community GitHub page.
  2. Unpack the repository, open Unity, click the OPEN button, locate the unpacked repository and add it.
  3. In Unity, locate the Project tab, find the Scenes folder and, inside this folder, double click on the Main Menu Scene.

The game is nearly ready to use. What we need now is to add some questions and handle the data transfer between Syncano and our project. We can use the Dashboard to add questions manually by using the built-in API, or we can create a server-side Script, which generates 15 dummy questions.

Working with Syncano Scripts

Of the many features Syncano offers, Scripts are my favourite. I’ll briefly introduce how Scripts work, so we can use them in our example for generating and downloading data we will use in the project. In our first example, we will create a Script that generates 15 dummy questions that will be used later in our application, so let’s get started!

Introduction

A Script is an object that contains code that can be run on Syncano's servers. With a Script you can, for instance, compute tasks that are too expensive to compute on the mobile/frontend side or create your own logic in the cloud that can be accessed by an API built on Script Endpoints.

Before We Start

When using the Syncano API, we always need to know the Instance name and API Key. The Instance name can be copied from the top left corner of the Dashboard.

The API Key can be obtained by clicking the API Keys panel at the bottom left sidebar and then by clicking the ‘Add an API Key’ button. When creating a key set the Ignore ACL flag to true!

Important note: The ignore ACL flag makes the API Key very powerful. It has permissions similar to an Account Key so be careful when using it. This flag should be only used in Scripts on Syncano's side. For production apps, set appropriate permissions in classes and data objects instead. You can read more about data permission here

Save these two variables for later, because we will use them when communicating with Syncano. Also make sure you followed all of the previous steps and created a Class named ‘question’ with all fields like in the example.

Generate 15 Dummy Questions Script Example

  1. Log in to the Dashboard https://dashboard.syncano.io
  2. Select your Instance.
  3. Go to the Scripts panel from the left sidebar and click the ADD button located at the top right corner.
  4. Give the Script a label and for Runtime environment select NodeJS then click the Confirm button.
  5. Once you created an empty Script, copy and paste the code below:
//This is a simple script to generate at least 15 empty questions for millionaire application

//Include request class for making simple POST and GET calls
var request = require('request');

//API Key can be obtained from Settings panel under API Keys section.
var api_key = "YOUR_API_KEY";

//Instance name can be seen at top left corner of the dashboard
var instance_name ="YOUR_INSTANCE_NAME";

//The number of questions to create
var questions_count = 15;

//Here we loop and make a single call to Syncano with dummy question
for(i = 0; i < questions_count; i++) {

    //There are three levels of difficulty. 0 stands for easy, 1 medium and 2 hard.
    //Questions are later ordered by their difficulty level.
    var difficultyType = i % 3;

    //Options variable is used to prepare all necessary data to create a question
    var options = {

      url: 'https://api.syncano.io/v1.1/instances/' + instance_name + '/classes/question/objects/',
      headers: {
        'X-API-KEY': api_key,
      },
      //Form dictionary is used to carry data of our object to create
      form: {
        text: "Question " + i,
        isModerated: true,
        difficultyType: difficultyType,
        //Important note. You need to use JSON.stringify in most cases when sending data to either Syncano server or to your application!!
        //We always set correct answer as first one.
        answers: JSON.stringify(['Correct','Wrong1','Wrong2','Wrong3'])
      }
    };

    //Send our request to create new question to Syncano
    request.post(options);
}

Then follow these steps:

  1. Set the Instance name and API Key variables.
  2. Click the RUN button at the top left corner.
  3. If you go to the Classes panel you should now see that the question object contains 15 dummy questions.

Get the 15 Random Questions Script

Once we have the questions, the next thing we need is a Script that returns 15 random questions to us for our application in Unity. To create such a Script, follow the steps below:

  1. In the Dashboard, go to the Scripts panel and create a new Script. Remember to select NodeJS for the runtime environment.
  2. Copy and paste the code below:
//include Syncano
var Syncano = require("syncano");  
 //include lodash library
var _ = require("lodash");

//API key with ignore ACL permission
var api_key = "YOUR_API_KEY";  
//class name which we take data from
var class_name = "question";  
//Your Instance Name
var instance_name ="YOUR_INSTANCE_NAME";

//Syncano object instance
var connection = Syncano({apiKey: api_key,  
defaults: {instanceName : instance, className: class_name} });

 //data object we operate on
var DataObject = connection.DataObject;

//we use this variable to filter valid only questions
var filter = {"isModerated":{"_eq":true}};  
 //exclusive fields we want to return only
var fields = ["text", "answers", "difficultyType", "id"];

 //get all questions
var list_of_questions = DataObject.please().list();

//filter validated questions, then order by difficulty level and take only fields specified in fields variable
list_of_questions.filter(filter)  
    .orderBy("difficultyType").fields(fields).then(function(dataobjects, raw) {

    // number of questions to return per difficulty level
    var number_of_questions_to_return = 5;

    //._filter(...) is an example of usage lodash library to filter objects
    var questions_with_lvl_easy   = _.filter(raw.objects, function(o) { return o.difficultyType === 0 });
    var questions_with_lvl_medium = _.filter(raw.objects, function(o) { return o.difficultyType === 1 });
    var questions_with_lvl_hard   = _.filter(raw.objects, function(o) { return o.difficultyType === 2 });

    //get five random questions per difficulty level. we also use _.sampleSize function from lodash library
    questions_with_lvl_easy   = _.sampleSize(questions_with_lvl_easy, number_of_questions_to_return);
    questions_with_lvl_medium = _.sampleSize(questions_with_lvl_medium, number_of_questions_to_return);
    questions_with_lvl_hard   = _.sampleSize(questions_with_lvl_hard, number_of_questions_to_return);

    //merge three lists with questions into one
    var to_return = _.concat(questions_with_lvl_easy, questions_with_lvl_medium, questions_with_lvl_hard);

    //return list of questions in JSON format
    console.log(JSON.stringify(to_return));

}).catch(function(err) { console.log(err);});

Then:

  1. Set the Instance name and API Key variables.
  2. Run the Script to test it. You should see a serialized array of questions at the right bottom corner.

Calling a Script from Unity

Everything should work now except one little detail. How can I run the Script I created from my Unity app? To solve this problem, we need to create a Script Endpoint. According to Syncano docs, a Script Endpoint is simply a URL that a website or application can make a HTTP request to. In the case of Syncano, this HTTP request to the URL will cause a Script execution. Follow these steps to create a Script Endpoint:

  1. In the Dashboard, go to the Sockets panel, which is located at the top left sidebar.
  2. Click the ADD SOCKET button.
  3. Select Socket Endpoint from the endpoint list.
  4. Create a new endpoint, give it a name and select our Script, which returns 15 questions. Important, make this Script public, otherwise it won’t be accessible from Unity!

Now we can copy the endpoint URL and paste it in any browser. It will return to us a serialized array of questions in JSON format.

So, this was the hardest part. In the next step, we will configure Unity to call the endpoint and transform received data into objects.

Connecting Unity with Syncano

To run the millionaire quiz app, we need to set four variables in the Unity project. Go to <project_directory>/ Assets/Source/General/Constant.cs and set

  1. API_KEY
  2. INSTANCE_NAME
  3. SCRIPT_ENDPOINT_GET_QUESTIONS_URL

SCRIPT_ENDPOINT_GET_QUESTIONS_URL is a URL pointing to the Script which returns questions to create the quiz. It can be found in the Sockets tab under the Script Endpoints section. With these variables set, we can now hit the play button in Unity and see the application working!

How It Actually Works

Let’s take a closer look at how Unity is communicating with Syncano, and how a serialized array of questions is turned into an array of actual objects.

If we go to <project_folder>/Assets/Source/Syncano/ we can find the source code responsible for networking between Syncano and the application. The core of the communication is the SyncanoHttpClient Class. It uses SyncanoWebRequest from UnityEngine.Networking namespace to make POST, DELETE or GET requests in case you are either operating with Data Objects or calling Script Endpoints.

So, how does it work in the millionaire app? If we go and open the <project_folder>/Assets/Source/ScenesMainMenu/MainMenu.cs Script, we can find the OnPlayClick method. This method is run when a player clicks the Play button. Then the DownloadQuestions method is triggered, which calls the Syncano Endpoint with a callback like this:

syncano.Please().RunScriptEndpointUrl(Constant.SCRIPT_ENDPOINT_GET_QUESTIONS_URL, OnQuestionsDownloaded);  

The syncano.Please().RunScriptEndpointUrl method takes two parameters. First is the endpoint URL, and second is a callback, which is triggered after we receive data from Syncano. In our case, if we go to the OnQuestionsDownloaded method, which is our callback, we can see that if the request is successful and returned data is valid we turn the data into a Quiz Object that contains an array of question objects, the very same objects we use in Syncano to store questions data! The magic happens in the Quiz Class in the FromJSON method, where we use Unity’s built-in API for turning a JSON array into an array of objects like this:

instance.questions = JsonConvert.DeserializeObject<List<Question>>(json);  

… and it is as simple as that! Before calling anything from Syncano, make sure to call the Init method on the Syncano object with a valid API Key and Instance name, like we did in MainMenu.cs line 17:

syncano = SyncanoClient.Instance;  
syncano.Init(Constant.API_KEY, Constant.INSTANCE_NAME);  

Also, when creating a custom Class, make sure it derives from SyncanoObject like the Question class in this example:

public class Question : SyncanoObject  

Going Further - Add and Moderate Questions from the App

What if we wanted more functionality and, let’s say, we wanted to add methods for adding and moderating questions? With Syncano it is a piece of cake! The first step we need to take is adding a question to Syncano. To accomplish this task, we could either use Scripts or simply use the framework we provided in this example and operate straight on the Data Objects. Please note that if we want to save or moderate an object from a Syncano Instance, it has to derive from the SyncanoObject Class.

So, to make the magic happen, we use only one line of code:

SyncanoClient.Instance.Please().Save(question, OnSubmitSuccess, OnSubmitFail);  

This method is called in <project_folder>/Assets/Source/Scenes/QuestionManager/SubmitPanel.cs from the SubmitQuestion method. So Unity creates an empty question object when the user goes to add a question panel. When the form is filled with data and the user clicks the Submit button, the values are copied to the question object (question text and an array of answers) and the object is serialized to JSON and sent to Syncano.

With OnSubmitSuccess and OnSubmitFail callbacks, we can handle both success and failure cases and, in the example, we inform the user that the question was sent to the server or an error occured and we display it so the error can be handled.

Moderating Questions

Moderating questions is as simple as adding a new object. What we need to do is to create a Script that returns to us one unconfirmed question, and here is the code to achieve that:

var Syncano = require("syncano");  // CommonJS  
var account_key = "YOUR_ACCOUNT_KEY";  
var instance_name = "YOUR_INSTANCE_NAME";

var connection = Syncano({accountKey: account_key});  
var DataObject = connection.DataObject;

var list = {instanceName: instance, className: "question"};  
var filter = {"isModerated":{"_eq":false}};  
var fields = ['isModerated', 'text', 'answers', 'difficultyType', 'id'];

DataObject  
    .please()
    .list(list)
    .filter(filter)
    .fields(fields)
    .pageSize(1)
    .then((dataobjects, raw) => {
        console.log(JSON.stringify(raw.objects[0]))
    })
    .catch((error) => {
        console.log('error', error)
    });

Also, don't forget to set your Instance Name and API Key.
So, now that we have a Script responsible for returning a question for us to moderate, we need to set its name and ID in <project_folder>/Source/General/Constant.cs like we did in previous example. The only variable we need to set are SCRIPT_ENDPOINT_GET_QUESTION_TO_MODERATE_URL for the Script Endpoint URL. With the Script and this variable set we can now accept, modify or reject questions added by users!

Unity Syncano API Examples

In this section, you can find some examples of use of the C# library. These are plain examples provided for learning purposes. Try it out yourself, it is really simple!

Add a question

SyncanoClient.Instance.Init("YOUR_API_KEY", "YOUR_INSTANCE_NAME");  
Question question = new Question();  
question.text = "Question text";  
question.answers = new List<string> { "correct answer", "wrong answer1", "wrong answer 2", "wrong answer 3", "wrong answer 4" };  
SyncanoClient.Instance.Please().Save(question, OnSubmitSuccess, OnSubmitFail);  

Modify a question

void Start()  
{    
    SyncanoClient.Instance.Init("YOUR_API_KEY", "YOUR_INSTANCE_NAME");
    SyncanoClient.Instance.Please().Get(1, OnSuccess); // question with id = 1
}

private void OnSuccess(Response<Question> response)  
{
    response.Data.text = "new, updated text";
    SyncanoClient.Instance.Please().Save(response.Data, OnSaveQuestionSuccess, OnFailureSuccess);
} 

Call a Script Endpoint

void Start()  
{
     SyncanoClient.Instance.Init("YOUR_API_KEY", "YOUR_INSTANCE_NAME");
     SyncanoClient.Instance.Please().RunScriptEndpointUrl("ENDPOINT_URL", OnScriptCalled);
}   

private void OnScriptCalled(ScriptEndpoint response)  
{
    if(response.IsSuccess)
    {
        Question question = Question.FromJson(response.stdout);
    }
} 

Using Syncano in Unity

To start using Syncano you can create an account here. To install Unity Library, visit the Syncano Unity Github page. The latest unitypackage and .dll files with instructions are available on the Release page.

Conclusion

When I was working on this project I found working with Scripts and Data Objects to be very handy. Not only because using them is pretty straightforward, but also because really powerful tasks can be accomplished, especially with the help of Syncano Scripts.

In this example, we didn’t have to use any external databases, modules, services, etc. No installation of anything on your machine was required. Everything was done with Syncano! Moreover, with Unity we can publish our game on multiple platforms, like Android, iOS, WebGL and many more - and it still does not require any additional work! Don’t forget to take a look at our example and feel free to add your own questions. Also, you can share your score on Facebook and let everyone know what your salary should be! :) Source code can be found on our Syncano Community Githib page.

Questions? Feedback? Let us know!

Let us know your thoughts - Join our Slack community to post your ideas, write to our support team at [email protected] or simply leave a comment below! For more Unity tutorials, subscribe to our newsletter or follow us on Twitter.

Build powerful apps in half the time

Use our serverless platform to set up your backend in minutes.

Learn more