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.

Try the demo:
https://demo-excalibur-js.mrfiles.net/

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.