Перейти к основному содержимому
🎉 GP CONF 2026: Конференция о рынке WEB-игр 👾 23 сентября | Подробнее

Глобальное состояние

Глобальное состояние содержит общие игровые сущности и значения, которыми управляет только хост:

  • враги и NPC;
  • предметы на карте;
  • состояние и таймеры раунда;
  • общий счёт и цели.

Глобальное состояние синхронизируется отдельно от состояния игроков.

Список методов

Действия:

Свойства:

События:

  • globalStateUpdated - отслеживать обновления глобального состояния на пирах.
  • becameHost и becamePeer - запускать и останавливать логику хоста.

Определение глобальной схемы

Глобальное состояние использует те же настройки схемы, что и состояние игрока:

gp.multiplayer.defineGlobalSchema({
enemies: {
id: { readonly: true },
type: { readonly: true },
x: { interpolate: true },
y: { interpolate: true },
hp: { interpolate: false },
},
items: {
id: { readonly: true },
type: { readonly: true },
x: { interpolate: false },
y: { interpolate: false },
},
round: {
number: { interpolate: false },
timeLeft: { interpolate: true },
status: { interpolate: false },
},
});

Включайте интерполяцию для значений, которые должны изменяться плавно, например координат. Отключайте её для значений, которые должны применяться сразу, например здоровья, состояния анимации или идентификатора предмета.

Создание состояния на хосте

Вызывать setGlobalState() может только хост:

let hostState = null;

function startHostLogic() {
hostState = gp.multiplayer.globalState ?? {
enemies: [],
items: [],
round: {
number: 1,
timeLeft: 60,
status: 'playing',
},
};

gp.multiplayer.setGlobalState(hostState);
}

function stopHostLogic() {
hostState = null;
}

gp.multiplayer.on('becameHost', startHostLogic);
gp.multiplayer.on('becamePeer', stopHostLogic);

В JavaScript setGlobalState() сохраняет ссылку на переданный объект, поэтому хост может изменять этот объект напрямую. В Unity после изменения C#-модели вызовите setGlobalState(), чтобы передать SDK её последнее сериализованное значение.

function spawnEnemy() {
if (!gp.multiplayer.isHost || !hostState) {
return;
}

hostState.enemies.push({
id: crypto.randomUUID(),
type: 'slime',
x: 100,
y: 200,
hp: 50,
});
}

function damageEnemy(enemyId, damage) {
if (!gp.multiplayer.isHost || !hostState) {
return;
}

const enemy = hostState.enemies.find((item) => item.id === enemyId);

if (enemy) {
enemy.hp = Math.max(0, enemy.hp - damage);
}
}

В JavaScript повторно вызывать setGlobalState() после каждого push, splice или изменения поля не требуется. Хост отправляет содержимое объекта с частотой выбранного режима. В Unity после изменения C#-модели снова передайте её сериализованное состояние.

Обновление общих сущностей

Выполняйте авторитетную логику общего мира только на хосте:

function updateGlobalState(delta) {
if (!gp.multiplayer.isHost || !hostState) {
return;
}

const seconds = delta / 1000;

for (const enemy of hostState.enemies) {
enemy.x += 40 * seconds;
}

hostState.round.timeLeft = Math.max(
0,
hostState.round.timeLeft - seconds,
);
}

gp.multiplayer.onTick(updateGlobalState);

Пиры не должны изменять gp.multiplayer.globalState. Они получают интерполированный снимок для отрисовки.

Чтение глобального состояния

Последнее глобальное состояние доступно хосту и пирам:

function renderWorld() {
const globalState = gp.multiplayer.globalState;

if (!globalState) {
return;
}

for (const enemy of globalState.enemies) {
drawEnemy(enemy);
}

for (const item of globalState.items) {
drawItem(item);
}
}

Пиры могут реагировать на изменения через globalStateUpdated:

function onGlobalStateUpdated(globalState) {
updateRoundInterface(globalState.round);
}

gp.multiplayer.on('globalStateUpdated', onGlobalStateUpdated);

Обработчик события получает непосредственно объект глобального состояния. Событие вызывается на пирах после интерполяции; хост уже владеет актуальной ссылкой на состояние.

Миграция хоста

Когда пир становится новым хостом, gp.multiplayer.globalState содержит последний полученный им снимок. Передайте этот объект в setGlobalState(), чтобы сделать его новой живой ссылкой хоста:

function startHostLogic() {
const latestState = gp.multiplayer.globalState;

hostState = latestState ?? {
enemies: [],
items: [],
round: {
number: 1,
timeLeft: 60,
status: 'playing',
},
};

gp.multiplayer.setGlobalState(hostState);
}

Так общий мир продолжит работу с последнего известного состояния, а не перезапустится после миграции хоста.

После подключения также обработайте случай, когда роль уже выбрана:

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

if (gp.multiplayer.isHost) {
startHostLogic();
}

Сохраняйте подписку на becameHost, поскольку миграция хоста может произойти позднее.

Очистка

gp.multiplayer.offTick(updateGlobalState);
gp.multiplayer.off('globalStateUpdated', onGlobalStateUpdated);
gp.multiplayer.off('becameHost', startHostLogic);
gp.multiplayer.off('becamePeer', stopHostLogic);

hostState = null;

Оставайтесь на связи

С другими документами раздела вы можете ознакомиться здесь. Для начала работы с GamePush ознакомьтесь с нашими туториалами.

Сообщество GamePush в Telegram: @gs_community.

Для ваших обращений e-mail: official@gamepush.com

Желаем вам успехов!