Как я делаю РПГ
29 июля 2015 13:42
Интро
Когда-то давно начал я играть в ночные городские игры aka Дозор, Энкаунтер и т.п. Суть игры - разгадать загадку, понять куда приехать (всякие там забросы, недострои и т.п.) и найти на локации все спрятанные там авторами игры коды. И так несколько уровней. Штука знаете ли заразная и можно уйти в неё с головой. И как-то однажды родилась у меня мысль портировать эту игровую реальность в браузер. Со временем в этой идее от ночных игр ничего практически не осталось и превратилось это дело в РПГ
Суть
Легенда не нова. Как обычно постапокалипсис, анархия и прочие прелести Fallout и подобных ему. В игре ходим человечком, встречаем других человечков, получаем и выполняем миссии, открываем новые локации, находим всякие плюшки, строим домики, воюем, торгуем и все остальные прелести реальной жизни. Виртуальный мир игры тесно связан с нашим. Локации вполне реальны, т.е. есть возможность в игре попасть в свой родной двор или даже квартиру и посмотреть что с ней стало спустя N лет.
Платформа
BackEnd nodejs+socket.io, neo4j
FrontEnd blend4web, Google Maps
Резюме
Надеюсь, что на этом проекте я познаю все тонкости замечательного blend4web, ибо искренне считаю что будущее интернета - трёхмерный интернет. Судя по всему в игре будут задействованы все возможности движка.
Буду тут писать что сделал, как сделал и как это работает/не работает, вдруг кто подскажет советом, а кто-то может и сам чему научится. А если уж кто и присоединиться захочет, то это прям вообще праздник. Делается это все пока на локальной машине. Как только разверну в сети обязательно выложу ссыль. Вот
Когда-то давно начал я играть в ночные городские игры aka Дозор, Энкаунтер и т.п. Суть игры - разгадать загадку, понять куда приехать (всякие там забросы, недострои и т.п.) и найти на локации все спрятанные там авторами игры коды. И так несколько уровней. Штука знаете ли заразная и можно уйти в неё с головой. И как-то однажды родилась у меня мысль портировать эту игровую реальность в браузер. Со временем в этой идее от ночных игр ничего практически не осталось и превратилось это дело в РПГ
Суть
Легенда не нова. Как обычно постапокалипсис, анархия и прочие прелести Fallout и подобных ему. В игре ходим человечком, встречаем других человечков, получаем и выполняем миссии, открываем новые локации, находим всякие плюшки, строим домики, воюем, торгуем и все остальные прелести реальной жизни. Виртуальный мир игры тесно связан с нашим. Локации вполне реальны, т.е. есть возможность в игре попасть в свой родной двор или даже квартиру и посмотреть что с ней стало спустя N лет.
Платформа
BackEnd nodejs+socket.io, neo4j
FrontEnd blend4web, Google Maps
Резюме
Надеюсь, что на этом проекте я познаю все тонкости замечательного blend4web, ибо искренне считаю что будущее интернета - трёхмерный интернет. Судя по всему в игре будут задействованы все возможности движка.
Буду тут писать что сделал, как сделал и как это работает/не работает, вдруг кто подскажет советом, а кто-то может и сам чему научится. А если уж кто и присоединиться захочет, то это прям вообще праздник. Делается это все пока на локальной машине. Как только разверну в сети обязательно выложу ссыль. Вот
Гале подарили мяч, Гале подарили торт, Галю поздравляют все - Галя сделала аборт
29 июля 2015 14:09
29 июля 2015 14:17
Да, в идеале весь мир. Сейчас на данный момент подгружается локация и все объекты на ней. При переходе на другую локацию, текущая локация выгружается и подгружается новая. Но я думаю, что такой подход будет использоваться только на этапе разработки, чтобы проще было учиться и тестировать.
Но на продакшне у игрока скорее всего будет "радар" - некий круг, который перемещается вместе с игроком. А так расположение абсолютно всех объектов можно выразить как в географических координатах, так и в координатах сцены, то фактически на сцене будет присутствовать только точ, что игрок "видит", то есть то, что попало в область радара
Но на продакшне у игрока скорее всего будет "радар" - некий круг, который перемещается вместе с игроком. А так расположение абсолютно всех объектов можно выразить как в географических координатах, так и в координатах сцены, то фактически на сцене будет присутствовать только точ, что игрок "видит", то есть то, что попало в область радара
Гале подарили мяч, Гале подарили торт, Галю поздравляют все - Галя сделала аборт
29 июля 2015 14:54
29 июля 2015 15:39
Итак, первое о чем хочу рассказать, это о лошадках, на которых едет серверная часть. Простите, за оффтоп. Этот момент не сильно касается движка, но считаю, что рассказать об этом всё же стоит.
БД
Сначала выбор базы данных был для меня очевиден - MySQL. Очевиден потому, что я уже много лет ей пользуюсь и чувствую себя в ней достаточно свободно. Но когда началась разработка, я столкнулся с некоторыми моментами, которые мне не понравились. Благодаря этому я открыл для себя замечательную вещь - Neo4j
Представим ситуацию. Наш игрок\пользователь\персонаж знает о существовании 5 локаций, имеет в рюкзаке 4 бутерброда с колбасой, не очень сильно дружит с другим игроком и в данный момент выполняет 4 миссии. Для того, чтобы отобразить всё это дело, при использовании MySQL (или иной реляционной БД) нам потребуется 4 запроса с джойнами. Не так много, но я параноик. Neo4j же позволяет выбрать все эти данные за один запрос. А всё потому, что Neo4j - графовая база данных.
Второй аспект - при написании кода, мы не знаем из каких таблиц нам нужно будет на этапе выполнения программы выбирать данные. Я говорю об отношениях. Допустим, мы на локации встречаем человечка, который даёт нам задание и обещает, что если мы это сделаем, то он нам подарит какую-нибудь плюшку. А эта плюшка может быть как новой локацией, новым пистолетом или новым навыком. А может быть так, что наградой буду все эти плюшки сразу. Что локации, что пистолеты, что навыки - сущности с абсолютно разным набором свойств и абсолютно разным набором действий, которые с ними можно произвести. И хранить экземпляры этих сущностей по фен-шую надо бы в разных таблицах. И где-то бы пришлось писать из какой таблицы (или таблиц) нам нужно достать плюшку и подарить её игроку. Опять не комильфо, опять лишние запросы. В Neo4j эта задача решается вытаскиванием всех узлов, связанных ребром с определённой меткой. Всё красиво, элегантно и в один запрос.
И в процессе разработки этой игры, я всё больше и больше влюбляюсь в эту бд.
Сервер приложения
В качестве сервера приложения выступает nodejs с подключенным модулем soсket.io. Выбор на него пал по нескольким причинам
Во-первых - многозадачность и один программный поток.
Во-вторых - событийная модель
В-третьих - javascript. Последнее время я очень сильно полюбил js и полючаю эстетическое наслаждение когда пишу на нём. Даже jquery уже не так сильно хочется использовать. И наверное процентов на 80 это благодаря вам
И наверное самая основная причина, по которой я выбрал nodejs - realtime. Игра предполагается как многопользовательская. Я не хочу по интервалу слать ajax-запросы на пхп-скрипт и проверять что изменилось. Да и всё равно временная погрешность будет. Да и если это не realtime< то это всего лишь еще одна браузерная игра, а не полноценная десктопная игра в браузере.
Вот как-то так. В следующем посте расскажу как готовлю локации в соответствии с нашей реальностью
БД
Сначала выбор базы данных был для меня очевиден - MySQL. Очевиден потому, что я уже много лет ей пользуюсь и чувствую себя в ней достаточно свободно. Но когда началась разработка, я столкнулся с некоторыми моментами, которые мне не понравились. Благодаря этому я открыл для себя замечательную вещь - Neo4j
Представим ситуацию. Наш игрок\пользователь\персонаж знает о существовании 5 локаций, имеет в рюкзаке 4 бутерброда с колбасой, не очень сильно дружит с другим игроком и в данный момент выполняет 4 миссии. Для того, чтобы отобразить всё это дело, при использовании MySQL (или иной реляционной БД) нам потребуется 4 запроса с джойнами. Не так много, но я параноик. Neo4j же позволяет выбрать все эти данные за один запрос. А всё потому, что Neo4j - графовая база данных.
Второй аспект - при написании кода, мы не знаем из каких таблиц нам нужно будет на этапе выполнения программы выбирать данные. Я говорю об отношениях. Допустим, мы на локации встречаем человечка, который даёт нам задание и обещает, что если мы это сделаем, то он нам подарит какую-нибудь плюшку. А эта плюшка может быть как новой локацией, новым пистолетом или новым навыком. А может быть так, что наградой буду все эти плюшки сразу. Что локации, что пистолеты, что навыки - сущности с абсолютно разным набором свойств и абсолютно разным набором действий, которые с ними можно произвести. И хранить экземпляры этих сущностей по фен-шую надо бы в разных таблицах. И где-то бы пришлось писать из какой таблицы (или таблиц) нам нужно достать плюшку и подарить её игроку. Опять не комильфо, опять лишние запросы. В Neo4j эта задача решается вытаскиванием всех узлов, связанных ребром с определённой меткой. Всё красиво, элегантно и в один запрос.
И в процессе разработки этой игры, я всё больше и больше влюбляюсь в эту бд.
Сервер приложения
В качестве сервера приложения выступает nodejs с подключенным модулем soсket.io. Выбор на него пал по нескольким причинам
Во-первых - многозадачность и один программный поток.
Во-вторых - событийная модель
В-третьих - javascript. Последнее время я очень сильно полюбил js и полючаю эстетическое наслаждение когда пишу на нём. Даже jquery уже не так сильно хочется использовать. И наверное процентов на 80 это благодаря вам
И наверное самая основная причина, по которой я выбрал nodejs - realtime. Игра предполагается как многопользовательская. Я не хочу по интервалу слать ajax-запросы на пхп-скрипт и проверять что изменилось. Да и всё равно временная погрешность будет. Да и если это не realtime< то это всего лишь еще одна браузерная игра, а не полноценная десктопная игра в браузере.
Вот как-то так. В следующем посте расскажу как готовлю локации в соответствии с нашей реальностью
Гале подарили мяч, Гале подарили торт, Галю поздравляют все - Галя сделала аборт
30 июля 2015 20:18
Да, в выборе JavaScript есть очевидный плюс, поскольку никогда не знаешь заранее, где будет выполняться тот или иной код, на клиенте или на сервере (или одновременно и там и там). Про Neo4j слышу впервые, надо будет ознакомиться. Вообще, будет интересно посмотреть, сможет ли его использование обеспечить realtime в игре.
Команда Blend4Web
https://twitter.com/AlexKowel
https://twitter.com/AlexKowel
31 июля 2015 02:54
Про Neo4j слышу впервые, надо будет ознакомитьсяОбязательно ознакомьтесь!!!! Язык запросов Cypher практически не отличается от SQL. Есть REST, есть транзакции, есть индекс и еще много всяких наворотов прям из коробки… Ощем всё как у взрослых =)) Разработчики обещают, что она неимоверно шустрая (не смотря на то, что крутится всё это дело на яве). Реальных цифр пока привести не могу, не анализировал. Но самое главное это графы! Что может быть прекрасней графа?.Вот кратенький экскурс, наслаждайтесь, а я пока перейду к рассказу о подготовке локаций
Гале подарили мяч, Гале подарили торт, Галю поздравляют все - Галя сделала аборт
31 июля 2015 04:29
Как уже упоминалось выше, все локации игры существуют в реальном мире. И в игровом мире, локации располагаются относительно друг друга абсолютно так же как и тут. Ну а где же еще стырить цифровую копию нашей планеты, как не в гугломапсах?
Для того, чтобы это реализовать, я написал простенький скрипт, который умеет:
1. указывать центр локации. Это точка, которая на сцене будет являться началом системы координат. В БД сохраняются географические координаты точки
2. указывать границы локации. Это полигон абсолютно произвольной формы. Ну скучно же делать все локации одинаково-квадратными. В БД сохраняются границы полигона в формате JSON (массив географических координат)
После того, как центр и границы локации указаны на карте, хорошо бы создать и её 3D-модель. Начинаю я конечно же с ландшафта. Для этого я делаю скриншот полигона границ локации и кладу его в блендере как бэкграунд рабочей области. Вещь полезная для наглядности, но не решающая, ибо как ты ручками не растягивай вершины плоскости в соответствии с этим бэкграундом, идеально повторить его всё равно не получится. И в этом моменте на помощь нам приходят те самые географические координаты границ полигона и центра локации. Используя несложную функцию, код которой приведён ниже, мы можем получить смещение "ключевых" точек полигона относительно центра локации в метрической системе. Вот код
Эта функция принимает координаты двух точек и возвращает расстояние в метрах между ними. Таким образом мы можем включить в блендере метрическую систему координат, просабдивайдить плоскость и растащить нужные вершины по нужным нам местам, придав тем самым этой плоскости форму нашего полигона.
Примечание: граничащие локации должны иметь либо общие точки либо идти внахлёст. Иначе наши человечки рискуют провалиться под землю.
Теперь о модели локации
Так как все домики, машинки и прочие интерактивные объекты будут подгружаться на локацию динамически, всё что нам сейчас нужно сделать - это только создать окружающую среду. Для этого я добавляю на сцену:
1. несколько спикеров с шумами окружающей среды: птички там всякие, шум дождя, ветер и т.п
2. солнышко с dynamic intensity т.к. темнеть в игре должно тогда, когда и за окном
3. насколько источников ветра. Имя каждого из них соответствует направлению (S, SE, NW и т.д.). В последствии хотелось бы спрашивать у информера погоду и программно изменять силу ветра по каждому из направлений.
4. меш-эмиттер дождя/снега.
5. сферу с системой частиц для звёздного неба
6. портал. Это меш, который будет служить для перехода из одной локации на другую. Подробнее ниже.
Единственное с чем у меня сейчас возникают серьёзные проблемы, это с ландшафтом. Я хоть убейте не пойму, как сделать так, чтоб мои человечки ходили по земле а не по collision bounds меша, вися в воздухе или проваливаясь по пояс. Ну не моделер я от бога. Для того, чтобы придать ландшафту неровности, я использую модификатор displace,который изменяет геометрию плоскости. Всё круто и даже похоже на правду, но в результате этого collision bounds растягиваются по высоте в соответствии с верхней и нижней точкой новой геометрии меша. И увы
Перемещение между локациями
Сейчас у меня есть аж целых три способа попасть с одной локации на другую.
1.Клик по карте. Всё просто. Жмакнул - локация загрузилась
2. Портал. Порталы это области на локации, войдя в соприкосновение с которыми, игрок может перейти на локацию, с которой связан портал. В базе данных у каждой локации создано отношение с граничащими с ней локациями. В свойствах этого отношения (или ребра, раз уж мы используем графы) указываются координаты точки на сцене в которую необходимо этот портал поместить. После загрузки сцены мы находим все локации, на которые мы можем попасть с текущей, копируем меш портала, помещаем его в нужное место и вешаем на него сенсоры соприкосновения с персонажем
3. Третий способ пока только в проекте. Это автоматическая подгрузка/выгрузка локаций в зависимости от текущего расположения персонажа. То есть если мы подошли на 50 метров к западной границе текуще локации, то загрузить локацию, граничащую с запада. Штука классная, пока думаю
Есть еще оч классная штука, которая может очень сильно усложнить мне жизнь при написании сценария игры, но и одновременно с этим придать игре крутизны, кмк. Благодаря тому, что графы бывают ориентированные (а именно такой граф используется в игре), можно сделать так, что из локации А в локацию Б попасть можно, а из Б в А - нет. Хвала дискретной математике.
Вот такой вот рассказ на много букв получился. Спасибо за внимание, буду рад критике и идеям. В следующем посте расскажу о структуре клиентской части приложения и почему инкапсуляция - наше всё. Обещаю код
Для того, чтобы это реализовать, я написал простенький скрипт, который умеет:
1. указывать центр локации. Это точка, которая на сцене будет являться началом системы координат. В БД сохраняются географические координаты точки
2. указывать границы локации. Это полигон абсолютно произвольной формы. Ну скучно же делать все локации одинаково-квадратными. В БД сохраняются границы полигона в формате JSON (массив географических координат)
После того, как центр и границы локации указаны на карте, хорошо бы создать и её 3D-модель. Начинаю я конечно же с ландшафта. Для этого я делаю скриншот полигона границ локации и кладу его в блендере как бэкграунд рабочей области. Вещь полезная для наглядности, но не решающая, ибо как ты ручками не растягивай вершины плоскости в соответствии с этим бэкграундом, идеально повторить его всё равно не получится. И в этом моменте на помощь нам приходят те самые географические координаты границ полигона и центра локации. Используя несложную функцию, код которой приведён ниже, мы можем получить смещение "ключевых" точек полигона относительно центра локации в метрической системе. Вот код
var coords2distance = function(lat1, long1, lat2, long2) {
//радиус Земли
var R = 6372795;
//перевод коордитат в радианы
lat1 *= Math.PI / 180;
lat2 *= Math.PI / 180;
long1 *= Math.PI / 180;
long2 *= Math.PI / 180;
//вычисление косинусов и синусов широт и разницы долгот
var cl1 = Math.cos(lat1);
var cl2 = Math.cos(lat2);
var sl1 = Math.sin(lat1);
var sl2 = Math.sin(lat2);
var delta = long2 - long1;
var cdelta = Math.cos(delta);
var sdelta = Math.sin(delta);
//вычисления длины большого круга
var y = Math.sqrt(Math.pow(cl2 * sdelta, 2) + Math.pow(cl1 * sl2 - sl1 * cl2 * cdelta, 2));
var x = sl1 * sl2 + cl1 * cl2 * cdelta;
var ad = Math.atan2(y, x);
var dist = ad * R; //расстояние между двумя координатами в метрах
return dist;
}
Эта функция принимает координаты двух точек и возвращает расстояние в метрах между ними. Таким образом мы можем включить в блендере метрическую систему координат, просабдивайдить плоскость и растащить нужные вершины по нужным нам местам, придав тем самым этой плоскости форму нашего полигона.
Примечание: граничащие локации должны иметь либо общие точки либо идти внахлёст. Иначе наши человечки рискуют провалиться под землю.
Теперь о модели локации
Так как все домики, машинки и прочие интерактивные объекты будут подгружаться на локацию динамически, всё что нам сейчас нужно сделать - это только создать окружающую среду. Для этого я добавляю на сцену:
1. несколько спикеров с шумами окружающей среды: птички там всякие, шум дождя, ветер и т.п
2. солнышко с dynamic intensity т.к. темнеть в игре должно тогда, когда и за окном
3. насколько источников ветра. Имя каждого из них соответствует направлению (S, SE, NW и т.д.). В последствии хотелось бы спрашивать у информера погоду и программно изменять силу ветра по каждому из направлений.
4. меш-эмиттер дождя/снега.
5. сферу с системой частиц для звёздного неба
6. портал. Это меш, который будет служить для перехода из одной локации на другую. Подробнее ниже.
Единственное с чем у меня сейчас возникают серьёзные проблемы, это с ландшафтом. Я хоть убейте не пойму, как сделать так, чтоб мои человечки ходили по земле а не по collision bounds меша, вися в воздухе или проваливаясь по пояс. Ну не моделер я от бога. Для того, чтобы придать ландшафту неровности, я использую модификатор displace,который изменяет геометрию плоскости. Всё круто и даже похоже на правду, но в результате этого collision bounds растягиваются по высоте в соответствии с верхней и нижней точкой новой геометрии меша. И увы
Перемещение между локациями
Сейчас у меня есть аж целых три способа попасть с одной локации на другую.
1.Клик по карте. Всё просто. Жмакнул - локация загрузилась
2. Портал. Порталы это области на локации, войдя в соприкосновение с которыми, игрок может перейти на локацию, с которой связан портал. В базе данных у каждой локации создано отношение с граничащими с ней локациями. В свойствах этого отношения (или ребра, раз уж мы используем графы) указываются координаты точки на сцене в которую необходимо этот портал поместить. После загрузки сцены мы находим все локации, на которые мы можем попасть с текущей, копируем меш портала, помещаем его в нужное место и вешаем на него сенсоры соприкосновения с персонажем
3. Третий способ пока только в проекте. Это автоматическая подгрузка/выгрузка локаций в зависимости от текущего расположения персонажа. То есть если мы подошли на 50 метров к западной границе текуще локации, то загрузить локацию, граничащую с запада. Штука классная, пока думаю
Есть еще оч классная штука, которая может очень сильно усложнить мне жизнь при написании сценария игры, но и одновременно с этим придать игре крутизны, кмк. Благодаря тому, что графы бывают ориентированные (а именно такой граф используется в игре), можно сделать так, что из локации А в локацию Б попасть можно, а из Б в А - нет. Хвала дискретной математике.
Вот такой вот рассказ на много букв получился. Спасибо за внимание, буду рад критике и идеям. В следующем посте расскажу о структуре клиентской части приложения и почему инкапсуляция - наше всё. Обещаю код
Гале подарили мяч, Гале подарили торт, Галю поздравляют все - Галя сделала аборт
31 июля 2015 18:12
Проект и правда очень серьезный. Хотя, если посмотреть, то при аккуратном подходе, тут всё может получиться довольно автоматизированно
Единственное с чем у меня сейчас возникают серьёзные проблемы, это с ландшафтом. Я хоть убейте не пойму, как сделать так, чтоб мои человечки ходили по земле а не по collision bounds меша, вися в воздухе или проваливаясь по пояс. Ну не моделер я от бога.Так ведь есть же Статическая физика. Важно только помнить, что её переопределяет физика объекта, если включена опция Object Physics.
02 августа 2015 03:53
Так ведь есть же Статическая физика. Важно только помнить, что её переопределяет физика объекта, если включена опция Object Physics.Ухты… а я думал, что эта галочка активирует всю физику. Спасибо, попробую.
Проект и правда очень серьезный. Хотя, если посмотреть, то при аккуратном подходе, тут всё может получиться довольно автоматизированноМожет =) Но пока еще четкой картины у меня нет. Тыкаюсь в попытках хоть как-то изучить блендер и изучаю движок. Нехватка знаний\опыта в моделировании ощущается остро. Так что всё получается через пробы и ошибки… Но я пытаюсь систематизировать как-то всё то, что у меня там в голове крутится. Отчасти этот "блог" веду из-за этого - чтоб хоть самому понять что я делаю и зачем
Вот пожалуй и продолжу это дело прям ща
Гале подарили мяч, Гале подарили торт, Галю поздравляют все - Галя сделала аборт