Глобальное состояние
Глобальное состояние содержит общие игровые сущности и значения, которыми управляет только хост:
- враги и NPC;
- предметы на карте;
- состояние и таймеры раунда;
- общий счёт и цели.
Глобальное состояние синхронизируется отдельно от состояния игроков.
Список методов
Действия:
gp.multiplayer.defineGlobalSchema()- определить синхронизируемые общие поля. FREEgp.multiplayer.setGlobalState()- установить глобальное состояние под управлением хоста. FREEgp.multiplayer.onTick()иoffTick()- управлять циклом логики общего мира. FREE
Свойства:
gp.multiplayer.globalState- получить последнее глобальное состояние. FREE
События:
globalStateUpdated- отслеживать обновления глобального состояния на пирах.becameHostиbecamePeer- запускать и останавливать логику хоста.
Определение глобальной схемы
Глобальное состояние использует те же настройки схемы, что и состояние игрока:
- JavaScript
- Construct 3
- Unity
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 },
},
});
Легенда
System
System›Системный объект Construct 3
GP_Multiplayer.defineGlobalSchema(new GP_Data(@"{
""enemies"": {
""id"": { ""readonly"": true },
""type"": { ""readonly"": true },
""x"": { ""interpolate"": true },
""y"": { ""interpolate"": true },
""hp"": { ""interpolate"": false }
},
""round"": {
""number"": { ""interpolate"": false },
""timeLeft"": { ""interpolate"": true },
""status"": { ""interpolate"": false }
}
}"));
Включайте интерполяцию для значений, которые должны изменяться плавно, например координат. Отключайте её для значений, которые должны применяться сразу, например здоровья, состояния анимации или идентификатора предмета.
Создание состояния на хосте
Вызывать setGlobalState() может только хост:
- JavaScript
- Construct 3
- Unity
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);
Легенда
GP_Channels
GP_Channels›Плагин GamePush Channels
GP_Data hostState;
void StartHostLogic()
{
hostState = GP_Multiplayer.globalState ?? new GP_Data(@"{
""enemies"": [],
""items"": [],
""round"": {
""number"": 1,
""timeLeft"": 60,
""status"": ""playing""
}
}");
GP_Multiplayer.setGlobalState(hostState);
}
void StopHostLogic() => hostState = null;
GP_Multiplayer.on("becameHost", StartHostLogic);
GP_Multiplayer.on("becamePeer", StopHostLogic);
В JavaScript setGlobalState() сохраняет ссылку на переданный объект, поэтому хост может изменять этот объект напрямую. В Unity после изменения C#-модели вызовите setGlobalState(), чтобы передать SDK её последнее сериализованное значение.
- JavaScript
- Construct 3
- Unity
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);
}
}
Легенда
GP_Channels
GP_Channels›Плагин GamePush Channels
void SpawnEnemy()
{
if (!GP_Multiplayer.isHost)
return;
worldState.enemies.Add(new EnemyState
{
id = Guid.NewGuid().ToString(),
type = "slime",
x = 100,
y = 200,
hp = 50
});
GP_Multiplayer.setGlobalState(
new GP_Data(JsonUtility.ToJson(worldState))
);
}
В JavaScript повторно вызывать setGlobalState() после каждого push, splice или изменения поля не требуется. Хост отправляет содержимое объекта с частотой выбранного режима. В Unity после изменения C#-модели снова передайте её сериализованное состояние.
Обновление общих сущностей
Выполняйте авторитетную логику общего мира только на хосте:
- JavaScript
- Construct 3
- Unity
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);
Легенда
System
GP_Channels
System›Системный объект Construct 3
GP_Channels›Плагин GamePush Channels
void UpdateGlobalState(float delta)
{
if (!GP_Multiplayer.isHost)
return;
float seconds = delta / 1000f;
foreach (EnemyState enemy in worldState.enemies)
enemy.x += 40f * seconds;
worldState.round.timeLeft = Mathf.Max(
0,
worldState.round.timeLeft - seconds
);
GP_Multiplayer.setGlobalState(
new GP_Data(JsonUtility.ToJson(worldState))
);
}
GP_Multiplayer.onTick(UpdateGlobalState);
Пиры не должны изменять gp.multiplayer.globalState. Они получают интерполированный снимок для отрисовки.
Чтение глобального состояния
Последнее глобальное состояние доступно хосту и пирам:
- JavaScript
- Construct 3
- Unity
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);
}
}
Легенда
System
System›Системный объект Construct 3
GP_Data globalState = GP_Multiplayer.globalState;
if (globalState != null)
Debug.Log(globalState.Data);
Пиры могут реагировать на изменения через globalStateUpdated:
- JavaScript
- Construct 3
- Unity
function onGlobalStateUpdated(globalState) {
updateRoundInterface(globalState.round);
}
gp.multiplayer.on('globalStateUpdated', onGlobalStateUpdated);
Легенда
System
System›Системный объект Construct 3
void OnGlobalStateUpdated(GP_Data globalState)
{
Debug.Log(globalState.Data);
}
GP_Multiplayer.on("globalStateUpdated", OnGlobalStateUpdated);
Обработчик события получает непосредственно объект глобального состояния. Событие вызывается на пирах после интерполяции; хост уже владеет актуальной ссылкой на состояние.
Миграция хоста
Когда пир становится новым хостом, gp.multiplayer.globalState содержит последний полученный им снимок. Передайте этот объект в setGlobalState(), чтобы сделать его новой живой ссылкой хоста:
- JavaScript
- Construct 3
- Unity
function startHostLogic() {
const latestState = gp.multiplayer.globalState;
hostState = latestState ?? {
enemies: [],
items: [],
round: {
number: 1,
timeLeft: 60,
status: 'playing',
},
};
gp.multiplayer.setGlobalState(hostState);
}
Легенда
GP_Channels
GP_Channels›Плагин GamePush Channels
void StartHostLogic()
{
GP_Data latestState = GP_Multiplayer.globalState;
hostState = latestState ?? CreateInitialGlobalState();
GP_Multiplayer.setGlobalState(hostState);
}
Так общий мир продолжит работу с последнего известного состояния, а не перезапустится после миграции хоста.
После подключения также обработайте случай, когда роль уже выбрана:
- JavaScript
- Construct 3
- Unity
await gp.multiplayer.connect({ channelId });
if (gp.multiplayer.isHost) {
startHostLogic();
}
Легенда
System
GP_Channels
GamePush
System›Системный объект Construct 3
GP_Channels›Плагин GamePush Channels
GamePush›Плагин GamePush
await GP_Multiplayer.connect(new MultiplayerChannelQuery { channelId = channelId });
if (GP_Multiplayer.isHost)
StartHostLogic();
Сохраняйте подписку на becameHost, поскольку миграция хоста может произойти позднее.
Очистка
- JavaScript
- Construct 3
- Unity
gp.multiplayer.offTick(updateGlobalState);
gp.multiplayer.off('globalStateUpdated', onGlobalStateUpdated);
gp.multiplayer.off('becameHost', startHostLogic);
gp.multiplayer.off('becamePeer', stopHostLogic);
hostState = null;
Легенда
System
GP_Channels
System›Системный объект Construct 3
GP_Channels›Плагин GamePush Channels
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
Желаем вам успехов!