Skip to main content
πŸŽ‰ GP CONF 2026: WEB Games Market Conference πŸ‘Ύ September 23 | Details

Player State

Player state contains data controlled by an individual player. Each player sends their own updates to the host, and the host distributes the resulting state map to the room.

Typical player state fields include position, direction, animation, health, and score.

Method List​

Actions:

Properties:

Events:

Define a Player Schema​

Define the schema before starting the game:

gp.multiplayer.definePlayerSchema({
x: { interpolate: true },
y: { interpolate: true },
direction: { interpolate: false },
hp: { interpolate: false },
color: { readonly: true },
});

Interpolation smoothly transitions a numeric value between received updates. For example, if the coordinate changes from x: 100 to x: 150, the SDK displays the intermediate positions instead of moving the object instantly.

Enable interpolation for values that should change smoothly, such as coordinates. Disable it for values that should be applied immediately, such as health, animation state, or an item identifier.

Initialize Players on the Host​

The player initializer runs on the host and returns the initial state for each player:

function getPlayerColor(playerId) {
const colors = ['#ff6b6b', '#4ecdc4', '#45b7d1', '#f7dc6f'];
return colors[playerId % colors.length];
}

function initializePlayer(playerId, playerInfo) {
return {
x: 100 + (playerId % 5) * 60,
y: 200,
direction: 1,
hp: 100,
color: getPlayerColor(playerId),
};
}

async function configurePlayerInitialization() {
if (!gp.multiplayer.isHost) {
return;
}

await gp.multiplayer.setPlayerInitializer(initializePlayer);
}

gp.multiplayer.on('becameHost', configurePlayerInitialization);

Host selection is asynchronous. Calling setPlayerInitializer() after becoming the host also initializes players who are already connected but do not have state yet.

After connecting, handle the case where the role has already been selected:

await gp.multiplayer.connect({ channelId });
await configurePlayerInitialization();

Keep the becameHost subscription because the current player may become the host later.

The initializer itself may also return a promise:

async function initializePlayer(playerId) {
const spawn = await loadSpawnPoint(playerId);

return {
x: spawn.x,
y: spawn.y,
hp: 100,
color: getPlayerColor(playerId),
};
}

Update the Current Player​

Use the SDK tick loop for gameplay. The following example waits for the initial state, applies local movement, and sends only the fields controlled by the player:

const keys = new Set();

window.addEventListener('keydown', (event) => keys.add(event.code));
window.addEventListener('keyup', (event) => keys.delete(event.code));

let localX = null;
let localY = null;
let direction = 1;

function updateLocalPlayer(delta) {
const myState = gp.multiplayer.myState;

if (localX === null || localY === null) {
if (!myState) {
return;
}

localX = myState.x;
localY = myState.y;
}

const speed = 200;
const distance = speed * (delta / 1000);

if (keys.has('ArrowLeft')) {
localX -= distance;
direction = -1;
}

if (keys.has('ArrowRight')) {
localX += distance;
direction = 1;
}

gp.multiplayer.setPlayerState({
x: localX,
y: localY,
direction,
});
}

gp.multiplayer.onTick(updateLocalPlayer);

setPlayerState() accepts partial state. The SDK merges it with the existing state and does not send an update when the supplied values have not changed.

The current player's local state is available through:

const myState = gp.multiplayer.myState;

Render All Players​

playersState is a Map where the key is playerId and the value is the player's latest state:

function renderPlayers() {
for (const [playerId, state] of gp.multiplayer.playersState) {
drawPlayer({
id: playerId,
x: state.x,
y: state.y,
color: state.color,
hp: state.hp,
});
}

requestAnimationFrame(renderPlayers);
}

requestAnimationFrame(renderPlayers);

Remote player coordinates have already passed through the SDK interpolation buffer. The current player uses their local state and is not delayed by interpolation.

Use playersUpdated when the game needs to react to a state-map change outside the render loop:

function onPlayersUpdated(players) {
updatePlayersPanel(players);
}

gp.multiplayer.on('playersUpdated', onPlayersUpdated);

It is not necessary to subscribe to playersUpdated only to render players. Reading playersState during rendering is sufficient.

Select a Synchronization Mode​

Choose a mode before starting the game loop:

gp.multiplayer.setMode('smooth');

See Synchronization Modes for the difference between fast and smooth.

Stop the Player Loop​

Pass the same function reference to offTick():

gp.multiplayer.offTick(updateLocalPlayer);
gp.multiplayer.off('playersUpdated', onPlayersUpdated);
gp.multiplayer.off('becameHost', configurePlayerInitialization);

Stay in Touch​

Other documents of this chapter are available here. To get started with GamePush, see the Tutorials chapter.

GamePush Community Telegram: @gs_community.

For your suggestions e-mail: official@gamepush.com

We Wish you Success!