Create a Unity Game with Realm
On this page
- Overview
- Part 1: Set up the Game
- Download and Import Unity's Platformer Microgame
- Update Your Project Manifest
- Download the Realm Tutorial Repository
- Explore the Realm Tutorial Repository
- Explore the Schemas
- Create a RealmController Game Object
- Open a Realm
- Set a Logged In User
- Update the Stats and Watch for Changes
- Restart the Game When the Player Wins
- Delete the Current Playthrough Stats When the Player Loses
- Customize Your Game Assets (Optional)
- Run and Test
- Part 2: Add Sync to the Game (Optional)
- Enable Realm Sync
- Connect to Your MongoDB Realm App
- Open a Synced Realm
- Update the Authentication Screen and Manager
- Setup Authentication in your Game
- Create a Real-Time Leaderboard with Realm Sync
- Run and Test
- What's Next?
Overview
In this tutorial, you will create a Unity project that uses Unity's Platformer Microgame and MongoDB Realm.
The project is made up of two parts:
- The Platformer Microgame: A working microgame provided by Unity that does not store any data in a database.
- The Realm Tutorial repository: A repository we've created to simplify the creation of the User Interface and storing of data in Realm.
In Part 1 of this tutorial, you will set up the platformer microgame, clone and import the Realm tutorial repository, and then add functionality to manage players and a list of game statistics in Realm Database.
Once you've completed the local version of the app, you can enhance your application in Part 2 Realm Sync to:
- Register users with email and password.
- Sign users into accounts with email and password and sign out later.
- Create a synced global leaderboard of top user scores.
Part 1 should take around 30 minutes to complete. The optional part 2 should take an additional 30 minutes.
If you prefer to explore on your own rather than follow a guided tutorial, you can check out the following documentation:
Part 1: Set up the Game
The prerequisites below list the latest versions of the necessary downloads at the time of writing this documentation:
- Unity 2020.3.12f1 (2020 LTS).
- Unity Hub version 2.4.5 or higher.
- An installed text editor, such as Visual Studio.
Download and Import Unity's Platformer Microgame
Unity Hub comes pre-installed with templates, such as the Platformer Microgame, to help users learn to develop games for Unity. You'll start by loading the Platformer Microgame template. In later steps, you will import and add Realm functionality to the game.
Click the Learn tab on the left side of Unity Hub to view the list of template projects. Scroll to the Platformer Microgame and click it.

On the Modal that appears, click the Download Project button to download the project. When the download is complete, click Open Project to open the project in Unity.

When you open the Platformer Microgame template, Unity prompts you with the option to Load Scene or Load Tutorials.
If you are new to developing with Unity, click Load Tutorials to learn Unity editor basics, interacting with Game Objects, and more. Once you feel comfortable working with the Unity Editor, you can continue to the next step. Alternatively, if you are already comfortable working with the Unity editor, click Load Scene and continue to the next step in this tutorial.
Once the scene is loaded, click the play button on the top of the screen to enter play mode and play the game.

Try the game to get a feel of what your users will experience. Use the arrow keys for Player
movement and the spacebar
to jump. Navigate through a series of platforms and defeat the "red slime" enemies by hopping on them, making them disappear.
Collect the yellow "tokens" by touching them. Get to the end of the level to win the game.
In later steps, you will use Realm Database to record:
- how many enemies the
Player
defeated per playthrough - how many tokens were collected
- a score that is calculated based on the statistics for the current playthrough and how quickly you completed the playthrough
Unity stores the game's files in a temporary directory when you load a template project from the Learn tab. To save them to a local folder on your machine, click the X button at the top of the screen to close Unity. A modal opens and prompts if you want to keep this project. Select the Keep button and pick a folder to save your new project in.

Navigate to the Unity Hub menu to reopen your game. Select the Add button in the menu and click your project folder to add your new locally saved project to your list of projects on Unity Hub.

Update Your Project Manifest
Unity uses the project manifest to determine packages to install into your project. You'll need to update your project's manifest file to install Realm Database, and the Unity UI ToolKit and UI Builder packages to develop user interfaces to interact with and display data stored in realm.
Open your project's manifest file by navigating to your project on Unity Hub
and expanding the dropdown menu on the right-hand side of your project name.
Click the Reveal in Finder option if you're on a Mac or the
Show in Explorer option if you're on a Windows machine. Open your
project's /Packages/manifest.json
file in a text editor.

Update your project's manifest file to include the following dependencies and scoped registries:
{ "dependencies": { // ... "io.realm.unity": "10.5.0", "com.unity.ui": "1.0.0-preview.17", "com.unity.ui.builder": "1.0.0-preview.17" }, "scopedRegistries": [ { "name": "NPM", "url": "https://registry.npmjs.org/", "scopes": [ "io.realm.unity" ] } ] }
UI ToolKit and UI Builder are preview packages that are in development by the Unity engineering team. While they provide a simple API to develop user interfaces for a tutorial, they should not be used in production yet.
If you are experiencing the compilation error: "The type or namespace 'UIDocument could not be found", this is a bug in the UI Toolkit package. As a workaround, create an Assembly Definition Reference. Click Assets at the top of the screen. Then select Create in the dropdown that appears. Finally, select Assembly Definition Reference. This will cause Unity to recompile without the error.
Download the Realm Tutorial Repository
Now that you have installed Realm, UI Builder, and UI Toolkit, you can begin recording data into Realm and building a user interface that can read and interact with that data.
We've already put together a repository with most of the code you'll need to accomplish that. You can clone or download the Realm Tutorial repository directly from GitHub:
Explore the Realm Tutorial Repository
In your text editor of choice, such as Visual Studio, you can see the script files you will need to add to the game. The relevant files are as follows:
File | Purpose |
---|---|
UI Toolkit/Leaderboard.uxml | UXML file; defines
the structure of the Leaderboard user interface. |
RealmScripts/LeaderboardManager.cs | Query Realm and display the top Stat objects. |
UI Toolkit/ScoreCard.uxml | UXML file; defines
the structure of the Scorecard user interface. |
RealmScripts/ScoreCardManager.cs | Listen for changes to the current playthrough Stat and update the Scorecard UI. |
UI Toolkit/Authentication.uxml | UXML file; defines
the structure of the Authentication Screen user interface. |
RealmScripts/AuthenticationManager.cs | Interacts with the TextField's of AuthenticationScreen.uxml to
implement user login. In part 2, you'll add user authentication with the MongoDB Realm
Email/Password provider. |
RealmScripts/RealmController.cs | Open a realm, query Realm the realm
for an existing Player or create a new one and a new Stat for the current
playthrough. Perform write transactions on the realm
objects. |
RealmScripts/PlayerModel.cs | Defines the Player Realm Object Model. |
RealmScripts/StatModel.cs | Defines the playthrough Stat Realm Object Model. |
RealmScripts/Constants.cs (Part 2) | Part 2: Declare the Realm App ID for the Realm Sync portion of the tutorial. |
Explore the Schemas
In the realm-tutorial-unity
project that you have cloned, navigate to the
PlayerModel.cs
and StatModel.cs
files in a text editor. These C#
classes define the schemas for the objects we store in our realms.
Note the following about the schemas:
- A
Stat
is a realm object representing the statistics of a playthrough of the game. For instance, in one playthrough of the game, aPlayer
may have defeated 10 enemies, collected 15 tokens, and had a score of 210. EachStat
has astatOwner
that is aPlayer
object. - A
Player
is a realm object representing the user's logged-in character. EachPlayer
has a collection (IList) ofStat
objects. - A
Player
has a string property,_id
, that defines thePlayer
objects' unique partition.
Create a RealmController Game Object
The RealmController.cs
file is a script that contains boilerplate code for
this tutorial, such as a Start()
method that automatically generates
Leaderboard, Authentication, and ScoreCard UI objects and attaches
the AuthenticationManager.cs
, LeaderboardManager.cs
, and
ScoreCardManager.cs
scripts to their respective UI Game Objects
. In later
steps, you will add functionality to the RealmController
script to perform
the following:
- Open a realm.
- Set a logged-in
Player
. - Interact with the
Player
andStat
models. - Create, read, update, and delete the current playthrough
Stat
object.
Before you begin updating the code in the RealmController.cs
file, you'll
need to create a new Game Object
for it.
Create an empty Game Object
by right-clicking the hierarchy window and
selecting Create Empty. Name the object RealmController
.

Next, open the inspector window by clicking the new RealmController object.
If your inspector window does not open after clicking the Game Object
,
click Window > General > Inspector.
Then click the Game Object
again to open its inspector window.
Next, attach
the RealmController.cs
script to the RealmController
object. Click the
Add Component button, and select the Scripts option in the dropdown.

Finally, select the RealmController.cs
script to attach it to the
RealmController
object.

Click the play button on the top of the screen to enter play mode and play the game. You should see something like the following:

Notice, when you type a username and click Login & Start Game, Unity navigates you to the platformer game, but the username field on the right-hand side of the game screen is a static username rather than the one you inputted. You'll add functionality to replace the static username value with a dynamic user input later.

Set a Logged In User
In the RealmController.cs
file, you will need to implement a function to set
the logged-in user. The AuthenticationManager.cs
file calls this function
when a user clicks the Login & Start button.
The RealmController.SetLoggedInUser()
method takes a string, userInput
.
You will create code to do the following in this method:
- Query the realm to determine if a
Player
object already exists for the givenuserInput
. - Create an if-else block that creates a new
Player
and a newStat
realm object if thePlayer
does not exist, and uses the existingPlayer
and creates a newStat
object if thePlayer
does exist.
Add the following code to your RealmController.SetLoggedInUser()
method:
// query the realm to find any Player objects with the matching name var matchedPlayers = realm.All<Player>().Where(p => p.Name == userInput); if (matchedPlayers.Count() > 0) // if the player exists { currentPlayer = matchedPlayers.First(); var stat = new Stat(); stat.StatOwner = currentPlayer; realm.Write(() => { currentStat = realm.Add(stat); currentPlayer.Stats.Add(currentStat); }); } else { var player = new Player(); player.Id = ObjectId.GenerateNewId().ToString(); player.Name = userInput; var stat = new Stat(); stat.StatOwner = player; realm.Write(() => { currentPlayer = realm.Add(player); currentStat = realm.Add(stat); currentPlayer.Stats.Add(currentStat); }); }
After the above code is executed, the RealmController.SetLoggedInUser()
function calls startGame()
to begin the timer. The timer increments the
RealmController's runTime
variable, and we use the runTime
variable to
calculate bonus points in the playerWon()
method when the game has
completed.
Update the Stats and Watch for Changes
You've set the current Scorecard to the initial playthrough statistics for the
current playthrough of the game, but collecting tokens or defeating
enemies will not impact the current Stat
object yet. To implement that, you'll edit the
CollectToken()
and DefeatEnemy()
methods in the RealmController
.
Add the following code to the RealmController.CollectToken()
method to
perform a write transaction and update the variable
currentStat
that you created in the last step:
realm.Write(() => { currentStat.TokensCollected += 1; });
Call the CollectToken()
method when the Player
collides with the token
instance. This occurs in the platformer microgame file:
/Assets/Scripts/Mechanics/TokenInstance.cs
.
In the TokenInstance.cs
file, the OnPlayerEnter()
occurs when a Player
has collided with the token instance. Add the following code to
OnPlayerEnter()
after collected = true
.
RealmController.CollectToken();
Add the following code to the RealmController.DefeatEnemy()
method to
perform a write transaction and update the variable
currentStat
that you created in the last step:
realm.Write(() => { currentStat.EnemiesDefeated += 1; });
Navigate to the /Assets/Scripts/Gameplay/EnemyDeath.cs
file and call
RealmController.DefeatEnemy()
at the beginning of the Execute()
method.
RealmController.DefeatEnemy();
Finally, create a listener that reacts to changes to the current
playthrough's Stat
and updates the Scorecard in the UI. In the`
ScoreCardManager.cs
file, you can add a change listener to the current
Stat
realm object defined as the RealmController.currentStat
variable. In the WatchForChangesToCurrentStats()
method, handle the Stat
object's
PropertyChanged event:
propertyHandler = new PropertyChangedEventHandler((sender, e) => UpdateCurrentStats()); currentStat.PropertyChanged += propertyHandler;
The Scorecard now updates if the Player
defeats an enemy or collects a token.

Restart the Game When the Player Wins
When the Player
reaches the end of the Microgame level, the game is complete,
but nothing else happens. To expand upon this, you will update the code to do
the following when the Player
wins the game:
- Call the
RealmController.PlayerWon()
method to calculate and write the final score to realm - Display a dialog with the final score
- Respawn the
Player
and restarts the game if thePlayer
clicks the restart button
Navigate to the Platformer Microgame file, /Assets/Scripts/Gameplay/PlayerEnteredVictoryZone.cs
,
in your text editor. This script is executed when the Player
enters the victory zone.
To create a dialogue, you'll need the UnityEditor.EditorUtility class. Add the following code to the top of the file:
using UnityEditor;
Replace the existing Execute()
method in the PlayerEnteredVictoryZone
script with the snippet below:
public override void Execute() { var finalScore = RealmController.PlayerWon(); var didClickRestart = EditorUtility.DisplayDialog("You won!", $"Final Score = {finalScore}", "restart game"); if (didClickRestart == true) { Simulation.Schedule<PlayerSpawn>(2); RealmController.RestartGame(); } }
Delete the Current Playthrough Stats When the Player Loses
When the Player
loses by colliding with an enemy or by falling from a
platform, the game starts a new playthrough and respawns the Player
back to
the start point but does not create a new Stat
object for the new playthrough.
To expand upon this, you'll perform the following when the Player
loses the game:
- Update the
RealmController.DeleteCurrentStat()
method to delete the currentStat
object for the current playthrough - Call the
RealmController.DeleteCurrentStat()
method - Call the
RealmController.RestartGame()
method to create a newStat
object for the new playthrough
Navigate to the RealmController.DeleteCurrentStat()
method and add the following code at the bottom of that method:
realm.Write(() => { realm.Remove(currentStat); currentPlayer.Stats.Remove(currentStat); });
Next, open the Platformer Microgame file,
/Assets/Scripts/Gameplay/PlayerDeath.cs
, which handles the player death
event. Add the following code to the end of the PlayerDeath's Execute()
method:
RealmController.DeleteCurrentStat(); RealmController.RestartGame();
Return to the Unity Editor, and click play to enter play mode
. The next
time your Player
loses, the game respawns the Player
to the start point with a new
Stat
object showing 0 enemies defeated, 0 tokens collected.
Customize Your Game Assets (Optional)
To add a personal touch to the game, you can modify its assets from the Unity
Editor. Navigate to Assets/Tiles
in the Project Window to find a set of tiles
that the game uses.
To modify a tile, click the tile to open its inspector window. From the inspector window, you can change the sprite that the tile uses and its color.

In the example below, we replaced the fence tile's sprite with the
fence_brown
sprite that comes with the Platformer Microgame.

You can choose any tile colors and sprites you would like. We went with the following for an earth-toned and friendly look:
Tile Name | Sprite |
---|---|
Fence | fence_brown |
House | house_green |
Plant | plant_green |
TileFloatingLeftEdge | TileFloatingLeftEdge_green |
TileFloatingRightEdge | TileFloatingRightEdge_green |
TileFloatingMiddle | TileFloatingMiddle_green |
TileGround | TileGroundDark_green |
TileGroundTop | TileGroundTop_green |

Run and Test
Once you have completed the code, you can run the app and check its functionality.
Click the play button on the top of the screen to enter play mode and play the game. Once the Unity Editor opens the GameView, here are some things you can try out:
- Logging in with a username.
- Achieving a new high score and seeing the leaderboard update with it on the next playthrough.
- Achieving a new high score using a different user and seeing the leaderboard update with the highscore on the next playthrough.
Part 2: Add Sync to the Game (Optional)
- Completed Part 1.
- A MongoDB Realm application with Email/Password authentication enabled.
To view a complete synced version of the app:
Navigate to the root directory of the Realm Tutorial repository:
cd realm-tutorial-unity Check out the
sync
branch:git checkout sync - In Constants.cs, replace
<your-realm-app-ID-here>
with your Realm app ID, which you can find in the Realm UI. - Run the game by clicking the "Play" button at the top of the Unity UI to enter Play mode.
Enable Realm Sync
Before you can add Sync functionality within your game, you must enable Realm Sync in your MongoDB Realm app.
To enable Realm Sync, follow the steps in the Enable Realm Sync guide. When enabling Sync, you will need to configure your app to:
- use
Development Mode
- add a required Partition Key with the name
"_partition"
and with the typestring
Connect to Your MongoDB Realm App
To get the app working with your backend, you first need to add your MongoDB Realm App
ID to the Constants.cs
file:
public const string AppId = "<your-realm-app-ID-here>";
Change the value of AppId
to your MongoDB Realm app ID, which you can find in
the MongoDB Realm UI.
Open a Synced Realm
To configure Realm to automatically synchronize data between devices, you'll need to replace your local realm with a synced realm.
In the RealmController.cs
file, replace the existing GetRealm()
method
with the one that takes in a User as a parameter and asynchronously gets a
synced realm instance:
// GetRealm() is an asynchronous method that returns a synced realm // GetRealm() takes a logged in Realms.Sync.User as a parameter private static async Task<Realm> GetRealm(User loggedInUser) { var syncConfiguration = new SyncConfiguration("UnityTutorialPartition", loggedInUser); return await Realm.GetInstanceAsync(syncConfiguration); }
Opening a synced realm requires a logged-in realm user; you'll set that up in the next step.
Update the Authentication Screen and Manager
To add support for Email/Password Authentication, you'll need to update your Authentication Screen to have a password field and a button that allows users to toggle between a registration mode and login mode.
Replace the code in your Authentication.uxml
with the following:
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False"> <Style src="Stylesheet.uss" /> <ui:VisualElement name="auth-wrapper" class="auth-wrapper" > <ui:Label text="Realm Platformer" display-tooltip-when-elided="true" name="game-title" class="game-title" /> <ui:Label text="Defeat Enemies and Collect Tokens!" display-tooltip-when-elided="true" name="defeat-enemies-subtitle" class="game-subtitle"/> <ui:Label text="Earn Bonus Points by Completing the Game Quicker!" display-tooltip-when-elided="true" name="earn-bonus-points-subtitle" class="game-subtitle"/> <ui:Label text="Play Your Way to the Top of the Leaderboard!" display-tooltip-when-elided="true" name="play-to-leaderboard-subtitle" class="game-subtitle" /> <ui:Label text="Login:" display-tooltip-when-elided="true" name="subtitle" class="subtitle" /> <ui:TextField picking-mode="Ignore" label="username" value="username" text="your.name@example.com" name="username-input" class="auth-input" /> <ui:TextField input-type="password" picking-mode="Ignore" label="password" value="password" name="password-input" class="auth-input" /> <ui:Button text="Login & Start Game" display-tooltip-when-elided="true" name="start-button" class="start-button" /> <ui:Button text="Don't have an account yet? Register" display-tooltip-when-elided="true" name="toggle-login-or-register-ui-button" class="toggle-login-or-register-ui-button" /> </ui:VisualElement> <ui:Button text="Logout" display-tooltip-when-elided="true" name="logout-button" class="logout-button hide" focusable="false" /> </ui:UXML>
You'll need to refactor your AuthenticationManager's Start()
method to contain code that does the following:
- Defines the
passInput
variable as a password TextField. - Defines the
toggleLoginOrRegisterUIButton
variable as a button. - Handles the toggle register/login button's click event and toggles between a register mode and login mode
In AuthenticationManager.cs
, add the following code to your Start()
method, replacing the existing startButton.clicked
event handler with the one below:
logoutButton.clicked += RealmController.LogOutBackend; passInput = root.Q<TextField>("password-input"); passInput.isPasswordField = true; // when the start button is clicked, toggle between registration modes startButton.clicked += () => { if (isInRegistrationMode == true) { OnPressRegister(); } else { OnPressLoginWithBackend(); } }; toggleLoginOrRegisterUIButton = root.Q<Button>("toggle-login-or-register-ui-button"); toggleLoginOrRegisterUIButton.clicked += () => { // if in registration mode, swap to the login mode if (isInRegistrationMode == true) { SwitchToLoginUI(); isInRegistrationMode = false; } else { SwitchToRegisterUI(); isInRegistrationMode = true; } };
Next, create a AuthenticationManager.SwitchToLoginUI()
and AuthenticationManager.SwitchToRegisterUI()
method to toggle between authentication UI modes:
// SwitchToLoginUI() switches the UI to the Login UI mode private static void SwitchToLoginUI() { subtitle.text = "Login"; startButton.text = "Login & Start Game"; toggleLoginOrRegisterUIButton.text = "Don't have an account yet? Register"; } // SwitchToRegisterUI() switches the UI to the Register UI mode private static void SwitchToRegisterUI() { subtitle.text = "Register"; startButton.text = "Signup & Start Game"; toggleLoginOrRegisterUIButton.text = "Have an account already? Login"; }
Replace the existing AuthenticationManager.OnPressLogin()
method with the one below, called
OnPressLoginWithBackend
that uses Email/Password Authentication:
// OnPressLoginWithBackend() is an asynchronous method that calls // RealmController.SetLoggedInUser to login and passes the currentPlayer to // ScoreCardManager and LeaderboardManager; once logged in the login screen // is hidden and the logout button is shown private static async void OnPressLoginWithBackend() { try { var currentPlayer = await RealmController.SetLoggedInUser(userInput.value, passInput.value); if (currentPlayer != null) { HideAuthenticationUI(); } ScoreCardManager.SetLoggedInUser(currentPlayer.Name); LeaderboardManager.Instance.SetLoggedInUser(currentPlayer.Name); } catch (Exception ex) { Debug.Log("an exception was thrown:" + ex.Message); } }
Notice that there is now a password parameter for the RealmController.SetLoggedInUser()
method. You will update that method in the next step.
Finally, create an AuthenticationManager.OnPressRegister()
method that calls a RealmController.OnPressRegister()
method that you will create in the next step:
// OnPressRegister() passes RealmController.OnPressRegister() the values of // the userInput and passInput TextFields in order to register a user private static async void OnPressRegister() { try { var currentPlayer = await RealmController.OnPressRegister(userInput.value, passInput.value); if (currentPlayer != null) { HideAuthenticationUI(); } ScoreCardManager.SetLoggedInUser(currentPlayer.Name); LeaderboardManager.Instance.SetLoggedInUser(currentPlayer.Name); } catch (Exception ex) { Debug.Log("an exception was thrown:" + ex.Message); } }
Setup Authentication in your Game
Currently, the project's only form of authentication is a username input. Let's replace that in the code with realm Email/Password Authentication
In the RealmController.cs
, replace the SetLoggedInUser()
with an
asynchronous method that logs in using the LogInAsync()
method to authenticate and obtain a User instance:
// SetLoggedInUser() is an asynchronous method that logs in as a Realms.Sync.User, creates a new Stat object for the current playthrough // and returns the Player object that corresponds to the logged in Realms.Sync.User // SetLoggedInUser() takes a userInput and passInput, representing a username/password, as a parameter public static async Task<Player> SetLoggedInUser(string userInput, string passInput) { syncUser = await realmApp.LogInAsync(Credentials.EmailPassword(userInput, passInput)); if (syncUser != null) { realm = await GetRealm(syncUser); currentPlayer = realm.Find<Player>(syncUser.Id); if (currentPlayer != null) { var stat = new Stat(); stat.StatOwner = currentPlayer; realm.Write(() => { currentStat = realm.Add(stat); currentPlayer.Stats.Add(currentStat); }); StartGame(); } else { Debug.Log("This player exists a MongoDB Realm User but not as a Realm Object, please delete the MongoDB Realm User and create one using the Game rather than MongoDB Atlas or Realm Studio"); } } return currentPlayer; }
Next, in the RealmController.cs
file, create an asynchronous method that
registers a new user by passing a user-provided email and password to the
RegisterUserAsync()
method:
// OnPressRegister() is an asynchronous method that registers a user, // creates a new Player and Stat object OnPressRegister takes a userInput // and passInput, representing a username/password, as a parameter public static async Task<Player> OnPressRegister(string userInput, string passInput) { await realmApp.EmailPasswordAuth.RegisterUserAsync(userInput, passInput); syncUser = await realmApp.LogInAsync(Credentials.EmailPassword(userInput, passInput)); realm = await GetRealm(syncUser); var player = new Player(); player.Id = syncUser.Id; player.Name = userInput; var stat = new Stat(); stat.StatOwner = player; realm.Write(() => { currentPlayer = realm.Add(player); currentStat = realm.Add(stat); currentPlayer.Stats.Add(currentStat); }); StartGame(); return currentPlayer; }
Finally, replace the RealmController.LogOut()
method with the
RealmController.LogOutBackend()
method below that calls
User.LogOutAsync() to log out
the realm user when log out button is clicked.
// LogOutBackend() is an asynchronous method that logs out // the current MongoDB Realm User public static async void LogOutBackend() { await syncUser.LogOutAsync(); SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex); }
Create a Real-Time Leaderboard with Realm Sync
The current leaderboard shows the top Stat
objects when the game first loads.
However, if another Player
gets a new high score after the game loads on your
device, the leaderboard on your device will not be updated.
To fix this, you will update the code in the LeaderboardManager.cs
file to do the following:
- Open a synced realm
- Listen to changes on all
Stat
objects - Update the Leaderboard GameObject when there is a new high score
Navigate to LeaderboardManager.cs
and add the following function that opens a synced realm using the RealmController.syncUser
variable that you created earlier:
// GetRealm() is an asynchronous method that returns a synced realm private static async Task<Realm> GetRealm() { var syncConfiguration = new SyncConfiguration("UnityTutorialPartition", RealmController.syncUser); return await Realm.GetInstanceAsync(syncConfiguration); }
In LeaderboardManager.cs
make the SetLoggedInUser()
an
asynchronous function and replace the existing Realm.GetInstance()
call
with a call to the new GetRealm()
method. Your code should look something like the following snippet:
// SetLoggedInUser() is an asynchronous method that opens a realm, calls the CreateLeaderboardUI() method to create the LeaderboardUI and adds it to the Root Component // and calls SetStatListener() to start listening for changes to all Stat objects in order to update the global leaderboard // SetLoggedInUser() takes a userInput, representing a username, as a parameter public async void SetLoggedInUser(string userInput) { username = userInput; realm = await GetRealm();
Next, create a Change Listener method:
// SetStatListener sets a listener on all Stat objects, and calls // SetNewlyInsertedScores if one has been inserted private void SetStatListener() { // Observe collection notifications. Retain the token to keep observing. listenerToken = realm.All<Stat>() .SubscribeForNotifications((sender, changes, error) => { if (error != null) { // Show error message Debug.Log("an error occurred while listening for score changes :" + error); return; } if (changes != null) { SetNewlyInsertedScores(changes.InsertedIndices); } }); }
Create a method, SetNewlyInsertedScores()
that does the following:
- Loops through a list of indices of inserted elements to find the newly created
Stat
objects. - Loops through the current top scores to determine if the new
Stat
object'sscore
is higher than the current score. - Updates the list of current top scores if there is a higher one and updates the UI to display the new list of top scores.
// SetNewlyInsertedScores() determines if a new Stat is // greater than any existing topStats, and if it is, inserts it into the // topStats list in descending order // SetNewlyInsertedScores() takes an array of insertedIndices private void SetNewlyInsertedScores(int[] insertedIndices) { foreach (var i in insertedIndices) { var newStat = realm.All<Stat>().ElementAt(i); for (var scoreIndex = 0; scoreIndex < topStats.Count; scoreIndex++) { if (topStats.ElementAt(scoreIndex).IsValid == true && topStats.ElementAt(scoreIndex).Score < newStat.Score) { if (topStats.Count > 4) { // An item shouldn't be removed if the leaderboard has less than 5 items topStats.RemoveAt(topStats.Count - 1); } topStats.Insert(scoreIndex, newStat); root.Remove(listView); // remove the old listView CreateTopStatListView(); // create a new listView root.Add(listView); // add the new listView to the UI break; } } } }
Call the SetStatListener()
after the user is logged-in, at the
end of the LeaderboardManager's SetLoggedInUser()
method:
SetStatListener();
Finally, dispose of the listener token once the Leaderboard GameObject is disabled in the OnDisable()
method:
if (listenerToken != null) { listenerToken.Dispose(); }
Since Unity Hub does not allow opening multiple instances of the same
project by default, we recommend simulating a new top score by creating a
new Stat
object through Realm Studio or
MongoDB Atlas. When you create a new Stat
object with a high score,
your leaderboard updates automatically and displays the new high score.
Alternatively, you can use the Unity symbolic link workaround
to open a second instance of the project and log in with a different user,
and get a new high score.
Run and Test
Once you have completed the code, you can run the game and check its functionality. Click the play button on the top of the screen to enter play mode and play the game. Once the Unity Editor opens the GameView, you should see something like the following images.

After you register an account or log in to an existing account, you can play the complete game

Here are some things you can try out:
- Authenticating a new user.
- Getting a new high score and seeing the leaderboard update in real-time.
- Creating a new
Stat
object with a high score in Realm Studio or MongoDB Atlas and seeing the leaderboard update in real-time.
What's Next?
- Read our .NET SDK documentation.
- Read additional information about using realm in your Unity project.
- To learn more about other functionality of MongoDB Realm, such as serverless functions and database triggers, try out the MongoDB Realm Backend tutorial.
- Find developer-oriented blog posts and integration tutorials on the MongoDB Developer Hub.
- Join the MongoDB Community forum to learn from other MongoDB developers and technical experts.
How did it go? Use the Give Feedback tab at the bottom right of the page to let us know if this tutorial was helpful or if you had any issues.