Клиент полностью тонкий, он как бы джойстик. На сервер отправляются только команды в духе - нажато влево. Качну уровень. Качну стат.
Проверки есть, но ничто не абсолютно, поэтому где-то просто может быть косяк. К примеру элементарно можно попробовать зайти инвейдом на врага, который при этом отключается от игры, при этом быстро сделать инвейд еще раз, уже будучи главным на локе, в общем всячески пытаться поломать консистентность данных на сервере.
Статы персонажа, как и двери, убитые боссы и поднятые предметы хранятся в mongodb на сервере.
Как раз A* противоположен этому алгоритму. Их в целом то всего два и есть - первый, когда мы пускаем волну от цели, и много "парней" могут найти цель, притом что цель не двигается а сетка строилась один раз. Второй, как раз A* - это когда мы на ходу пускаем волну до любого парня и находим его. Приходится пускать волну каждый раз, но зато теперь цель может двигаться, и волну пускает не цель а преследователь. А еще выгода A* в том, что преследователь на самом деле не сколько находит 1 цель, сколько получает карту весов, в которых например слева на 2 шага склянка, справа на 4 шага деньги, и они перевешивают.
Простите, постойте, я не рассказал как у меня в игре так легко красятся мобы в разные цвета. Программисты знают что на видеокарте очень легко умножить цвет, это фактически одна из стандартных операций смешивания. А вот подвигать HSL - это нет. Даже шейдер будет тормозить, если вот так применять его на каждом объекте. С этим я поступаю вот так.
Клиент берет картинку, в котором моб красный. (еще у него могут быть зеленые пятна и синие глаза, это отдельные каналы и в контексте это просто еще две картинки. Непосредственно для магии нам нужен только красный канал и его разница с серым на картинке).
Весь красный целиком вычитается из картинки. Остается светотень объекта. Эту светотень тоже можно умножать на цвет, если хотим еще больше радуг, но в принципе она остается какой есть. Белый объекта остается белым, а черный черным. Красный канал полностью перегоняется в белый, не просто чернобелый фильтр, а где красный был 255 при синем и зеленом 0, там будет белый, где красный был одинаков с другими (серый), там черный. Это получается цветовая компонента картинки. В итоге каждый HSL объект на сцене рисуется двумя картинками. Нижний слой - чернобелая светотень, сверху - умноженная на любой цвет, хоть розовый или черный, цветовая компонента. Практически бесплатный реалтайм сдвиг HSL.
Код увы не дам.
Но распишу все что внутри.
Клиент - пока что Phaser JS. Если честно, лучше бы я сразу взял Three js. Буду переписывать на Three JS так или иначе.
Сервер - node js, io, mongo.
Я так рассудил, игра рассчитана на много серверных расчетов и совсем немного сохранения загрузки из бд, поэтому монго пока сойдет, а производительность я нагоняю через node-gyp в C++.
Когда-нибудь я вынесу движок в отдельную часть и открою. Там есть пара интересных вещей. Существует shared папка кода, в которой пишется логика объектов, вот так запросто, их update, реакция на сообщения, в отрыве от сети и графики. Сервер использует эти объекты, обвешивая их общий предок MixGameObject контролем за синхронизацией с клиентом. Клиент использует эти объекты для отображения, и полностью подчиняется серверу. Сервер может создавать и удалять любые объекты на карте, толкать, наносить урон и т.п. Клиент по сути удаленный джойстик, тонкий. Также сервер дублирует _все_ update объектов в C++ (я был вынужден так поступить) ради производительности. На клиенте увы, C++ нет, компиляцию C++ в js я еще не курил, поэтому код дублируется, да. Важно другое - сервер отправляет исключительно состояние объекта при создании, команду на удаление когда надо, и контрольные точки изменения. Например - ударились о стену - надо отправить новую скорость и позицию. В остальное время, все анимации, удары, полеты стрел и движение по инерции - существует параллельно на клиенте и сервере. Если въехать, это довольно простой принцип, и воспроизвести его можно на любом проекте, если сразу так закладывать архитектуру.
Немного о клиенте.
Phaser JS я знаю поверхностно, так как просто вот взял и стал сразу пилить на нем игру. До этого я пилил игры на C++ с шейдерами и всякими сложными оптимизациями с кешированием в рендер текстуры. Здесь, по привычке запилив карту на 160х160 ячеек, я по привычке стал запекать куски карты в текстуры, и тут вышел косяк. Web GL еще довольно сырой в браузерах, чтобы вот так брать и делать на шейдерах многопроходное рисование, та же реализация на CANVAS просто быстрее. Тем не менее CANVAS очень слоупочный, если упирается в CPU, а именно это у меня и происходит. Каждый момент времени карта видит 7 слоев, каждый по 60 клеток, и я пока вынужден рисовать это просто через Phaser.Image каждый квадрат. (О, и как ни странно, Phaser.TileImage намного тормознее чем Image, хотя по идее именно он должен просто брать текстурный атлас и красиво текстурные координаты двигать, что дало бы мне возможность хотя бы рисовать куски стен за один раз). В итоге я пока остановился на том что есть - CANVAS, и соответственно много на процессоре, и когда на карте под 200 не статичных объектов глобально, начинает сказываться нехватка тактов. Видеокарта успевает, а фпс 40-50. Очень надеюсь что с Three JS получится все заоптимизировать. А еще надеюсь что десктопные камни разжуют игру лучше чем мой ноутбучный i7 (был бы рад вашим фпс и конфам чтобы понять на что ориентироваться)
Что еще рассказать.. мобы ходят по алгоритму поиска пути C, тот, который строится из точки цели, и расползается волной по карте, один раз за все время. В последствии мы можем из любой точки понять куда идти к цели. Но игрок двигается, а моб обычно стоит, поэтому это как раз игрок знает как найти моба, а не моб игрока. И вот что делает моб - идет от игрока до своего респа мысленно, запоминает маршрут, ищет себя в нем и бежит. В игре это можно обнаружить так. Убегает от моба, а потом даем в сторону. Естественно, наш путь до дома моба сдвинется в бок и моб потеряется. Он тупо пойдет к дому, пока снова не наткнется на маршрут до игрока. Этим их можно отлично кайтить, а еще благодаря этому они забавно бегают к тебе и назад, что не дает тебе выбрать момент для атаки. Все в духе DS, только благодаря оптимизациям а не специальной заточке.
Из интересного скажу, что Phaser JS _не_умеет_ 3д трансформации, а игра выглядит как бы как 3д потому что:
Используется массив из слоев, каждый из которых просто масштабируется в соответствии с своим z, а еще делает параллакс смещение координат относительно камеры, все это считается просто в главном цикле, без 3д проекции. Благодаря размытым краям текстур, горы и кажутся такими облачными и объемными, но на мобах и игроках видно, что это просто плоские картинки, на которые мы смотрим в изопроекции строго сверху. Дополнительный эффект добавляет смещение точки параллакса вниз экрана - возникает легкий эффект 3-его лица. Я подумываю даже с вводом 3д моделей оставить что-то из этой модели рендера, т.к. по моему выглядит клево.
Это все подкапотные фишки, если что- то еще интересно, welcome.
Когда после DS я перепрошел раз цать Соли, я и решил делать такую игру. Соли вид сбоку, моя сверху. Все логично.
Небольшой FAQ
---
Если при запуске игра тормозит до 3-4 фпс, это что-то не так, и надо обновить страницу, скорее всего заработает.
Чтобы играть в команде или делать пвп, нужна зеленая и красная краски. Зеленая на втором уровне, а Красная на третьем.
Серая краска - одновременно возвращает хост (игрок, кто приглашал других) на его чекпоинт, а всех кто был в его мире - разгоняет по своим мирам.
Переходы между уровнями - когда хост переходит на другой уровень, все призывы автоматически разгоняются. Надо снова собраться через знаки на другом уровне.
Кач командой веселей - люба смерть врага дает его опыт всем участникам, причем полный. Если моб стоит 100 пустоты, а призвалось 10 друзей, каждый получит по 100, даже если враг упадет в пропасть сам.
Двери, предметы - все это может открывать и собирать только хост. Вы помогаете хосту пройти _его_ уровень ну и попутно фармите пустоты и весело проводите время.
Если хотите убить боссов несколько раз - вам придется искать других игроков и помогать им, т.к. у себя босс не воскрешает.
Есть еще синяя краска - работает наоборот как зеленая. Если зеленая забирает игроков к вам, то синяя наоборот - тащит вас туда, куда вас вызывают на той стороне.
Что еще добавить.. не забывайте искать предметы, среди десятков мелочей по 10-200 душ попадаются вещи в духе Меч Синего Пламени, который двуручный и махает вжух вжух. Это важно, потому что без правильного оружия прохождение затрудняется.
Поднимите щит после ворот на 1 уровне, оденьте. Он не мешает. Когда он сбоку, он не работает, а оружие бьет как будто щита нет. Кнопка R включает щит, мувсет оружия может измениться, стамина юзается сильнее при перекатах и прыжках.
Еще часто задаваемый вопрос - как блин, одеть оружие?
Этот интерфейс еще просто не проработан, на самом деле вы просто нажимаете на слот щита или правой руки в разделе Персонаж, открывается список предметов, там надо выбрать правильно что хотите одеть. А если кликните в пустоту, то предмет снимется.
Пример: нажал на Щит, потом нажал на Меч, и Щит пропал! Правильно, ведь Меч нельзя одеть в левую руку, и попытка защиталась за снятие. Нужно нажать на левую руку и выбрать щит, а когда нажимаете на правую, выбираете только оружие, не щит.
С предметами внизу также.
Welcome!