Делаю браузерную 2D Quake-like арену. Часть 2
Иногда мне кажется, что начать писать браузерный мультиплеер было не самой умной идеей. Потому что каждая новая механика сначала работает, потом ломается, потом ломает что-то ещё, а потом ты три часа смотришь в логи и пытаешься понять, почему соединение с сервером рвётся сразу после захода в игру.
И самое неприятное - этот баг обычно написал ты сам. Но в целом процесс идёт, и прототип уже начинает напоминать игру.
Напомню, что вообще за проект.
Rattharia — это браузерная top-down 2D арена, вдохновлённая классическими аренами вроде Quake 3 Arena. Вид сверху, небольшие карты с оружием, аптечками и броней, быстрые бои и бесконечный респавн.
Почему я вообще решил делать арену - понятно. Мне нравился quake 3 да и к 2d я хорошо отношусь. Почему мультиплеер - уже менее понятно. А почему мультиплеер в браузере - иногда и сам не могу объяснить. Мне в комментах под прошлым постом советовали взять godot и не страдать фигней. Возможно так и сделаю, если мой ноут полетит в окно после еще сотни багов на этом дурацком java script.
Немного боли из разработки
Самый жопосжигательный баг на этой неделе выглядел примерно так.
Игрок заходит в игру → соединение устанавливается → игрок появляется на карте → и через секунду игра просто замирает.
Никаких ошибок. Вообще.
Первой мыслью было, что отваливается WebSocket. Но соединение при этом продолжало жить - клиент спокойно отправлял события на сервер.
Начал копать дальше.
В мультиплеерных играх обычно есть механизм проверки, жив ли клиент. Раз в несколько секунд сервер отправляет ping, клиент отвечает pong, и если ответа нет - соединение считается мёртвым и игрок удаляется.
У меня тоже была такая проверка. Только работала она немного не так, как я думал.
Соединение с сервером я создавал сразу при заходе на сайт, а вот сигналы проверки жизни клиента начинал отправлять только после входа в игру.
Интервал проверки был 10 секунд.
И получалось следующее:
игрок открывает сайт → соединение создаётся → проходит 10 секунд → игрок успевает зайти в игру, но сервер еще не получает ответа → и просто удаляет игрока из комнаты.
Клиент при этом всё ещё думает, что он в игре.
В итоге персонаж стоит на карте, но ни двигаться, ни стрелять уже не может, потому что для сервера его просто не существует.
Самое классическое: баг создал → баг расследовал → баг победил.
Напомню что я фронтенд разработчик. Я кнопочки верстал до этого. Кто хочет написать что это не мое будет абсолютно прав) Но что делать - труд, как говорится, сделает из фронтенд разработчика человека.
Но давайте ближе к тому на каком этапе уже игра.
Что уже работает
Несмотря на все приключения, базовый прототип уже можно пощупать.
Игрок может зайти в игру, создать свою комнату или подключиться к существующей, после чего начинается сама арена. Пока что ограничил систему десятью комнатами по десять игроков.
Из механик уже работают передвижение, рывки, стрельба, подбор оружия, патронов, аптечек и брони. Есть переключение оружия и простой лидерборд.
Игроки видят друг друга и могут нормально сражаться. Работают коллизии со стенами, можно упасть в обрыв (синяя область на карте), есть смерть и респавн.
То есть базовая игровая петля уже существует.
Выглядит это пока максимально аскетично - игроки, оружие и патроны просто квадраты.
Архитектура мультиплеера
Я решил сразу пойти по классической схеме, где сервер является точкой истины.
Клиент по сути ничего не решает. Он отправляет только ввод игрока — нажатия кнопок, направление движения и стрельбу. А сервер уже вычисляет положение игроков, движение пуль, попадания и урон.
Это важно, потому что любые споры вроде того, кто подобрал предмет или кто получил урон, должен решать именно сервер.
После этого сервер рассылает всем клиентам текущее состояние мира. Сейчас обновления отправляются примерно 20 раз в секунду.
Почему всё пока дёргается
Пока что клиент просто рисует координаты, которые присылает сервер, без какого-либо сглаживания.
Поэтому движения выглядят довольно рваными - объекты буквально перескакивают по карте.
Сделано это специально, чтобы не утонуть в коде. Логика мультиплеера и так достаточно сложная, а если сразу добавить prediction, interpolation, reconciliation и lag compensation (спасибо комментариям под прошлым постом — накидали полезных статей), то можно очень быстро запутаться.
Поэтому я решил двигаться поэтапно: сначала стабильная серверная логика, потом сглаживание движения, а уже сильно позже - графика. И, упаси боже, звук.
Следующий шаг
Следующим этапом хочу добавить client-side prediction.
То есть игрок будет начинать движение сразу, не дожидаясь ответа от сервера.
Когда игрок нажимает кнопку, клиент сразу двигает персонажа локально, а сервер в это время рассчитывает истинное положение и отправляет его обратно. Если координаты расходятся, клиент просто плавно корректирует позицию.
Это должно убрать ощущение задержки управления.
Попробовать прототип
Ниже оставлю ссылку на текущую версию. Надеюсь, вам будет интересно следить за тем, как вообще может развиваться игра.
И заодно вопрос к тем, кто делал 2D игры.
Кто-нибудь рисовал карты и спрайты сам? Какими инструментами пользовались? Пока не знаю с какой стороны подойти к этой теме.