Skip to content

Using Excalibur.js with MassiveRealm ​

Excalibur.js is a friendly TypeScript 2D game engine for the web.

You can use MassiveRealm with Excalibur.js to create multiplayer games.

Getting started ​

Check out our Quick Start Guide to create a new MassiveRealm project and get your API key.

Prerequisites:

  • Create a new MassiveRealm project.
  • Your project's URL and Public Key will be sent to your email.
  • Create Logic entry.
  • Create Room entry with alias room.

MassiveRealm Server Setup ​

In this demo, player synchronization occurs every 100 ms, batching updates for all players who have changed their position during that interval.

Client-side source code:
https://github.com/MassiveRealm/demo-excalibur

Server-side:
https://console.massiverealm.com/account/project/e50f-8a0e-74c9

Step 1: Create Model ​

Navigate to the Communication > Models section in your project's logic and create a new model called Player with the following fields:

  • id - String
  • x - Int16
  • y - Int16

Model: Player

Step 2: Create Server Command ​

Navigate to the Communication > Server section in your project's logic.

Create a new command called Update with the following input parameters:

  • x - Int16
  • y - Int16

This command will be called by the client to update the player's position.

Server: Update

Add the following code to update the player's position in the players collection.

Later we will create a timer to broadcast the players' positions to all clients every 100 ms.

javascript
if (!$room.players) $room.players = {};

$room.players[$session.id] = {
    id: $session.id,
    x: $params.x,
    y: $params.y
};

Server: Update

Step 3: Create Client Commands ​

Navigate to the Communication > Client section in your project's logic. Here we will create 3 commands:

Command 1: MyInfo ​

Input Parameters:

  • id - String

Client: MyInfo

Command 2: UpdatePlayers ​

Input Parameters:

  • players - Array Of, Item Type: "Player"

Client: UpdatePlayers

Command 3: DeletePlayer ​

Input Parameters:

  • id - String

Client: DeletePlayer

Step 4: Hooks ​

Navigate to the Communication > Hooks section in your project's logic. Here we will create 2 hooks:

Hook 1: OnRoomJoin ​

Notify the client of its own player ID by emitting the MyInfo command.

javascript
$session.emit('MyInfo', {
    id: $session.id
});

Hooks: OnRoomJoin

Hook 2: OnRoomLeave ​

Remove the player from the players collection when they leave the room and broadcast the DeletePlayer command to all other players.

javascript
if ($room.players && $room.players[$session.id]) {
    delete $room.players[$session.id];
}

$room.broadcast('DeletePlayer', {
    id: $session.id
});

Hooks: OnRoomLeave

Step 5: Create Timer ​

Navigate to the Timers > Instance section in your project's logic.

Create a new timer called UpdatePlayersTimer, set the interval to 100 ms.

Create batches of 30 players per message to avoid network congestion.

javascript
if (!$room.players) return;

let players = Object.values($room.players);

if (!players.length) return;

$room.players = {};

for (let i = 0; i < players.length; i += 30) {
    const chunk = players.slice(i, i + 30);

    $room.broadcast('UpdatePlayers', {
        players: chunk
    });
}

Timer

Excalibur.js Client Setup ​

Step 1: Add MassiveRealm Client ​

bash
npm i massiverealm-client

Step 2: Add Network Class ​

Define your commands in the onCommand method.

typescript
this.client = new MassiveRealmClient({
    ...
    onCommand: (command, data) => {
        console.log('Command received', command, data);

        // Set current player ID
        if (command === 'MyInfo') {
            this.playerId = data.id;
        }
        // Remove player from the scene
        else if (command === 'DeletePlayer') {
            this.level.events.emit('playerDelete', data.id);
        }
        // Update all players' positions
        else if (command === 'UpdatePlayers') {
            for (let i = 0; i < data.players.length; i++) {
                // Skip the current player
                if (data.players[i].id === this.playerId) continue;

                this.level.events.emit('playerMove', {
                    id: data.players[i].id,
                    x: data.players[i].x,
                    y: data.players[i].y
                });
            }
        }
    },
    ...
});

Check out more details in the source code: https://github.com/MassiveRealm/demo-excalibur/blob/main/src/network.ts

Optimization Tip ​

Storing room settings on the client side may significantly reduce network traffic. This way, the client will not need to request the room settings each time it joins a room.

Navigate to the Rooms section and select the room you want to optimize. Then click on Export on the left side and copy the code.

Optimization Code JSON

Paste that JSON into the client-side code, and you're done!

Optimization Paste JSON

More Performance Tips.