Создаем мультиплеер в Скретч пошагово

Как сделать мультиплеер в скретч

Содержание статьи

Как сделать мультиплеер в скретч

Мультиплеер в Скретч – это не просто возможность играть вдвоем на одном устройстве. Речь идет о синхронизации действий между несколькими пользователями через облачные переменные или локальную сеть. В этой статье разберем два подхода: облачный мультиплеер (для онлайн-игр) и локальный (для совместной игры на одном компьютере). Первый требует аккаунта Scratch с подтвержденным email, второй работает без интернета.

Облачные переменные в Скретч имеют ограничения: максимум 10 переменных на проект, каждая хранит до 128 символов, а обновление происходит раз в 0,1–0,2 секунды. Это критично для динамичных игр – учитывайте задержки при проектировании механики. Локальный мультиплеер лишен этих ограничений, но требует ручной синхронизации через сообщения между спрайтами.

Начнем с облачного варианта. Создайте переменную с префиксом (например, ☁ player1_x) и настройте ее в блоке «Когда флаг нажат». Для синхронизации используйте блоки «Передать [сообщение]» и «Когда я получу [сообщение]». Пример: если игрок нажимает клавишу «вправо», отправляйте сообщение move_right и обновляйте облачную переменную. Другой игрок должен слушать это сообщение и двигать спрайт на основе полученных данных.

Для локального мультиплеера понадобятся два спрайта-игрока. Первый управляется клавишами WASD, второй – стрелками. Используйте переменные player1_x и player2_x для хранения позиций. Синхронизируйте их через сообщения: при движении первого игрока передавайте его координаты второму спрайту, и наоборот. Избегайте конфликтов, добавляя проверку «Если [игрок] = [мой номер]» перед обработкой ввода.

Оптимизируйте производительность: не обновляйте облачные переменные чаще 5 раз в секунду, а локальные – используйте блок «Ждать 0.1 секунд» между итерациями цикла. Для тестирования мультиплеера откройте проект в двух браузерах или на разных устройствах. Если игра тормозит, сократите количество одновременных обновлений или упростите логику столкновений.

Настраиваем облачные переменные для синхронизации данных

В Scratch облачные переменные работают только в проектах, опубликованных на сайте, и требуют активации режима «Облачные данные» в настройках проекта. Перейдите в раздел «Настройки» (значок шестеренки) и включите опцию «Облачные переменные (бета)». Создайте переменную с префиксом `☁` – например, `☁playerX` или `☁score`. Эти переменные синхронизируются между всеми игроками с задержкой ~1-2 секунды, поэтому избегайте частых обновлений (не чаще 1 раза в 0.5 секунды), чтобы не перегружать сервер.

Для записи данных используйте блок задать [☁переменная v] значение [], а для чтения – [☁переменная v]. Пример: если игрок перемещается вправо, обновляйте `☁playerX` с шагом 10, но только при изменении позиции. Чтобы избежать конфликтов, добавляйте уникальный идентификатор игрока (например, `☁player1_X`) или используйте списки с индексами. Облачные переменные поддерживают только числа – для текста применяйте кодирование (например, ASCII).

Создаем игровой персонаж с поддержкой сетевого управления

Начнем с создания спрайта персонажа. В Скретче используйте костюмы для анимации движения: добавьте минимум 4 костюма (стоя, шаг левой, шаг правой, прыжок). Назовите их последовательно: *player_stand*, *player_walk1*, *player_walk2*, *player_jump*. Это упростит переключение анимаций через блоки следующий костюм и костюм [имя]. Для сетевой синхронизации присвойте каждому костюму уникальный числовой идентификатор (0–3), который будет передаваться по сети.

Реализуйте локальное управление через клавиши WASD или стрелки. Используйте блоки если клавиша [стрелка вправо] нажата для перемещения и изменить x на 5. Для прыжка добавьте переменную *y_velocity* и гравитацию: изменить y на y_velocity, затем изменить y_velocity на -1 при нажатии пробела. Ограничьте скорость падения значением 10, чтобы избежать «провалов» через платформы.

Для сетевой синхронизации создайте облачные переменные *playerX*, *playerY*, *playerCostume* и *playerDirection*. Обновляйте их каждые 0.1 секунды через блок повторять всегда с задержкой ждать 0.1 секунд. При изменении позиции или костюма отправляйте данные: задать [playerX v] значение (x позиция). Для других игроков используйте блоки когда я получу [updatePlayer] и перейти в x: (playerX) y: (playerY).

Добавьте проверку коллизий с платформами. Используйте блок касается цвета [#00FF00]? для зеленых платформ. При касании сбрасывайте *y_velocity* в 0 и корректируйте позицию: изменить y на (1), чтобы персонаж не «проваливался». Для сетевых игроков дублируйте эту логику, но вместо локальных переменных используйте облачные данные.

Оптимизируйте сетевой трафик. Вместо постоянной отправки координат передавайте только изменения: создайте переменную *lastX* и сравнивайте текущую позицию с предыдущей. Если разница превышает 3 пикселя, отправляйте обновление. Это снизит нагрузку на облачные переменные и уменьшит лаги. Для плавности движения сетевых игроков используйте линейную интерполяцию: перейти в x: ((playerX) + (x позиция)) / 2 y: ((playerY) + (y позиция)) / 2.

Реализуйте механику взаимодействия. При нажатии клавиши E отправляйте сообщение broadcast [use] и облачную переменную *playerAction* со значением 1. Другие игроки получат это через когда я получу [use] и проверят расстояние: если расстояние до (playerX) (playerY) < 50, выполните действие (например, открытие двери). Для визуальной обратной связи используйте эффект изменить [цвет v] эффект на 25 на 0.2 секунды.

Реализуем систему передачи координат между игроками

Реализуем систему передачи координат между игроками

В Scratch передача координат строится на облачных переменных. Создайте две облачные переменные: cloud_x и cloud_y. Они должны быть доступны всем игрокам в проекте. Убедитесь, что переменные помечены флажком "Облачная переменная" при создании. Для тестирования используйте два аккаунта Scratch – один для отправки, другой для приёма данных.

Для отправки координат добавьте в спрайт игрока блоки:

когда ⚑ нажат
повторять всегда
задать [cloud_x v] значение (x-координата)
задать [cloud_y v] значение (y-координата)
ждать (0.1) секунд

Задержка в 0.1 секунды снижает нагрузку на серверы Scratch, но сохраняет плавность синхронизации. Без паузы облачные переменные обновляются слишком часто, что приводит к лагам.

На стороне принимающего игрока используйте блоки:

когда ⚑ нажат
повторять всегда
перейти в x: (cloud_x) y: (cloud_y)
ждать (0.1) секунд

Этот код заставит спрайт повторять движения другого игрока. Если координаты обновляются рывками, уменьшите задержку до 0.05 секунд, но следите за стабильностью соединения.

Для предотвращения десинхронизации добавьте проверку на изменение координат. Сравнивайте текущие значения облачных переменных с предыдущими:

если <(cloud_x) ≠ (prev_x)> или <(cloud_y) ≠ (prev_y)> то
перейти в x: (cloud_x) y: (cloud_y)
задать [prev_x v] значение (cloud_x)
задать [prev_y v] значение (cloud_y)

Это исключит ненужные перемещения спрайта, если данные не изменились.

Оптимизируйте передачу, отправляя координаты только при движении. Добавьте условие:

если <(x-координата) ≠ (prev_x)> или <(y-координата) ≠ (prev_y)> то
задать [cloud_x v] значение (x-координата)
задать [cloud_y v] значение (y-координата)
задать [prev_x v] значение (x-координата)
задать [prev_y v] значение (y-координата)

Так облачные переменные обновляются только при реальном перемещении, а не в простое.

Для мультиплеера с несколькими игроками добавьте идентификатор. Создайте облачную переменную player_id и присваивайте каждому игроку уникальное число (1, 2, 3...). Координаты передавайте в формате:

задать [cloud_data v] значение (соединить (player_id) (соединить ":" (соединить (x-координата) (соединить ":" (y-координата)))))

На принимающей стороне разделяйте строку по символу ":" с помощью блока элемент (1 v) из (cloud_data) для извлечения ID и координат.

Добавляем проверку соединения и обработку задержек

В Скретче мультиплеер строится на облачных переменных, но их обновление не мгновенно – задержка может достигать 0.5–2 секунд в зависимости от нагрузки на серверы. Чтобы избежать рассинхрона, добавьте переменную последний_пинг, которую клиент будет обновлять каждые 0.3 секунды. Сервер (или хост-игрок) должен проверять эту переменную у всех участников: если значение не менялось дольше 3 секунд, помечайте игрока как отключившегося.

Для обработки задержек используйте буферизацию действий. Например, при движении персонажа сохраняйте координаты в списке ожидаемые_позиции с временными метками. Когда данные от другого игрока приходят с задержкой, сравнивайте их с буфером и корректируйте текущую позицию линейной интерполяцией: (новая_позиция - старая_позиция) * (прошедшее_время / задержка). Это сгладит рывки.

Реализуйте механизм подтверждения действий. При отправке критичных команд (например, атаки) добавляйте уникальный идентификатор в облачную переменную ожидание_подтверждения. Сервер должен дублировать это значение в подтвержденные_действия после обработки. Клиент проверяет совпадение ID – если через 1.5 секунды подтверждения нет, повторяет отправку или отменяет действие.

Для диагностики задержек создайте облачную переменную серверное_время, которую хост обновляет каждые 0.1 секунды. Клиенты сравнивают её с локальным временем и вычисляют разницу. Если отклонение превышает 0.5 секунды, корректируйте внутренние таймеры: локальное_время = серверное_время + средняя_задержка. Это синхронизирует игровые события.

Обрабатывайте потерю пакетов через тайм-ауты. При отправке данных (например, позиции) запускайте таймер на 2 секунды. Если за это время не пришло подтверждение от сервера, повторяйте отправку, но не более 3 раз. После третьей неудачи помечайте соединение как нестабильное и снижайте частоту обновлений до 1 раза в секунду, чтобы уменьшить нагрузку.

Для визуальной обратной связи добавьте индикатор задержки. Используйте переменную текущая_задержка, которую обновляйте при каждом успешном обмене данными. Отображайте её цветом: зелёный (<0.5 с), жёлтый (0.5–1 с), красный (>1 с). Это позволит игрокам адаптироваться к условиям соединения, например, избегать быстрых манёвров при высокой задержке.

Тестируйте систему на искусственных задержках. В Скретче добавьте блок ждать (случайное от 0.1 до 1.5) секунд перед обработкой входящих данных. Проверяйте, как игра ведёт себя при разных сценариях: 30% потерянных пакетов, задержка 1 секунда, внезапные разрывы соединения. Корректируйте тайм-ауты и буферы на основе результатов.

Организуем лобби для подключения нескольких участников

Для добавления игрока используйте блоки:

когда щёлкнут по зелёному флагу
задать [мой_ID v] значение (значение переменной [ID игрока v])
задать [лобби v] значение (соединить (лобби) (соединить (мой_ID) (соединить ":" (имя игрока))))
если <(длина (лобби)) > [250]> то
задать [лобби v] значение (первые [250] букв (лобби))
конец

Обновляйте список игроков каждые 2 секунды. Используйте таймер и блок повторять каждые (2) секунд. При каждом обновлении парсите строку лобби в список с помощью блока разбить (лобби) по [|]. Удаляйте дубликаты ID, чтобы избежать фантомных подключений.

Для выхода игрока из лобби реализуйте механизм очистки. При получении сообщения выход от игрока удалите его запись из переменной:

когда я получу [выход v]
задать [временный_список v] значение (разбить (лобби) по [|])
удалить (пункт (найти (соединить (мой_ID) ":") в [временный_список v]) из [временный_список v])
задать [лобби v] значение (соединить элементы (временный_список) разделитель [|])

Оптимизируйте нагрузку на облачные переменные. Если в лобби больше 10 игроков, переключитесь на обновление каждые 5 секунд. Используйте блок:

если <(длина (разбить (лобби) по [|])) > [10]> то
изменить таймер на (5)
иначе
изменить таймер на (2)
конец

Отображайте список игроков в интерфейсе. Создайте спрайт "Список игроков" с костюмом, содержащим 10 слотов для имён. При обновлении списка динамически меняйте текст костюма:

Слот Блоки Скретч
1 заменить пункт (1 v) в [список_игроков v] на (пункт (1 v) из [временный_список v])
2–10 повторять (10) раз
заменить пункт (значение переменной [i v]) в [список_игроков v] на (пункт (значение переменной [i v]) из [временный_список v])
конец

Добавьте проверку на активность игроков. Если игрок не отправляет обновления дольше 15 секунд, удаляйте его из лобби. Используйте отдельный список последний_пинг, где храните время последнего обновления для каждого ID. При парсинге лобби сравнивайте текущее время с записанным:

если <(текущее [минуты v]) > ((пункт (найти (ID) в [ID_игроков v]) из [последний_пинг v]) + (0.25))> то
удалить (пункт (найти (соединить (ID) ":") в [временный_список v]) из [временный_список v])
конец

Реализуйте защиту от спама. Ограничьте частоту отправки обновлений до 1 раза в секунду. Используйте переменную последнее_обновление и блок:

если <(таймер) > ((последнее_обновление) + (1))> то
задать [последнее_обновление v] значение (таймер)
передать [обновить_лобби v]
конец

Для запуска игры создайте облачную переменную статус_игры со значениями: ожидание, запуск, игра. При достижении минимального количества игроков (например, 2) отправляйте сообщение начать_игру всем участникам лобби. Перед запуском очищайте лобби, чтобы новые игроки не подключались к уже начатой сессии.

Вопрос-ответ:

Ссылка на основную публикацию