Skip to content

Phaser WebSockets — Real-Time Multiplayer Games

DodaTech Updated 2026-06-28 3 min read

In this tutorial, you will learn about Phaser WebSockets. We cover key concepts, practical examples, and best practices to help you master this topic.

Phaser Websocket integration enables real-time multiplayer by connecting to a server for position syncing, event broadcasting, and state management.

What You'll Learn

By the end of this guide, you will connect to a WebSocket server, send player position data, receive and interpolate other player positions, handle connection and disconnection, and broadcast game events.

WebSocket Connection

var socket = new WebSocket('wss://example.com/game');

socket.onopen = function() {
    console.log('Connected');
    socket.send(JSON.stringify({
        type: 'join',
        playerId: playerId
    }));
};

socket.onmessage = function(event) {
    var data = JSON.parse(event.data);
    handleServerMessage(data);
};

Sending Position

function sendPosition() {
    socket.send(JSON.stringify({
        type: 'position',
        x: player.x,
        y: player.y,
        timestamp: Date.now()
    }));
}

// In update, send every 50ms
this.time.addEvent({
    delay: 50,
    callback: sendPosition,
    loop: true
});

Interpolation

var otherPlayers = {};

function handleServerMessage(data) {
    if (data.type === 'playerMove') {
        if (!otherPlayers[data.id]) {
            otherPlayers[data.id] = createOtherPlayer(data);
        }
        otherPlayers[data.id].targetX = data.x;
        otherPlayers[data.id].targetY = data.y;
        otherPlayers[data.id].time = Date.now();
    }
}

// In update
function interpolatePlayers() {
    for (var id in otherPlayers) {
        var p = otherPlayers[id];
        var t = Math.min(1, (Date.now() - p.time) / 100);
        p.sprite.x += (p.targetX - p.sprite.x) * t;
        p.sprite.y += (p.targetY - p.sprite.y) * t;
    }
}

Common Mistakes

1. Sending Too Frequently

Sending on every frame (60fps) floods the server. Limit to 20-30 updates per second.

2. No Reconnection Logic

WebSocket connections drop. Implement auto-reconnect with exponential backoff.

3. Client-Side Authority

Players can cheat by sending false positions. Use server-side validation.

4. Position Packet Loss

UDP-like packet loss causes jumps. Use interpolation and extrapolation for smooth movement.

5. Not Handling Disconnect

When a player disconnects, remove their sprite. Listen to the 'close' event.

Practice Questions

Q1: How do you send data to the server? A: Call socket.send(JSON.stringify(data)).

Q2: How often should you send position updates? A: 20-30 times per second (every 33-50ms).

Q3: How do you handle other player movement? A: Store target position and interpolate toward it each frame.

Q4: How do you detect disconnection? A: Listen to the 'close' event on the WebSocket.

Q5: How do you implement auto-reconnect? A: In the 'close' handler, setTimeout to reconnect with increasing delays.

Challenge: Build a 2-player shared canvas where both players see the same objects. Each player can move a circle and draw on the canvas. Lines drawn appear for both players in real-time.

FAQ

Can I use Socket.IO with Phaser?

Yes. Socket.IO wraps WebSocket with rooms, namespaces, and auto-reconnect.

How do I handle latency?

Use client-side prediction (move immediately) and server reconciliation (correct if wrong).

What server should I use?

Node.js with ws or Socket.IO is common. Also Colyseus (game server framework).

How do I sync game state?

Send authoritative state from the server at 10-20fps. Clients interpolate between states.

Can I use UDP instead of WebSocket?

No. Browsers only support TCP via WebSocket. Use compression for large data.

Try It Yourself

Simulate a multiplayer connection (local).

<!DOCTYPE html>
<html>
<head>
    <title>Phaser WebSocket</title>
    <script src="https://cdn.jsdelivr.net/npm/phaser@3/dist/phaser.min.js"></script>
</head>
<body style="font-family:sans-serif;padding:20px;">
<h2>Multiplayer Simulation</h2>
<script>
var config = {
    type: Phaser.AUTO,
    width: 600,
    height: 400,
    backgroundColor: '#1a1a2e',
    scene: {
        create: function() {
            // Simulated remote players via local tweens
            var remotePlayer = this.add.circle(100, 100, 15, 0xff6b35);
            remotePlayer.alpha = 0.7;

            this.tweens.add({
                targets: remotePlayer,
                x: 500,
                duration: 2000,
                yoyo: true,
                repeat: -1,
                ease: 'Sine.easeInOut'
            });

            this.tweens.add({
                targets: remotePlayer,
                y: 300,
                duration: 1500,
                yoyo: true,
                repeat: -1,
                ease: 'Sine.easeInOut'
            });

            // Local player
            var localPlayer = this.add.circle(100, 100, 15, 0x4ecdc4);
            this.player = localPlayer;
            this.cursors = this.input.keyboard.createCursorKeys();

            this.add.text(300, 30, 'Green: Local | Orange: Remote', {
                fill: '#ffffff', fontSize: '14px'
            }).setOrigin(0.5);

            this.add.text(300, 370, 'Arrow keys to move local player', {
                fill: '#666', fontSize: '12px'
            }).setOrigin(0.5);
        },
        update: function() {
            var speed = 3;
            if (this.cursors.left.isDown) this.player.x -= speed;
            if (this.cursors.right.isDown) this.player.x += speed;
            if (this.cursors.up.isDown) this.player.y -= speed;
            if (this.cursors.down.isDown) this.player.y += speed;

            this.player.x = Phaser.Math.Clamp(this.player.x, 15, 585);
            this.player.y = Phaser.Math.Clamp(this.player.y, 15, 385);
        }
    }
};

var game = new Phaser.Game(config);
</script>
</body>
</html>

What's Next

Master tween animations.

Tweens — Tween animations. Tilemaps Advanced — Advanced tilemaps.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro