Какой-то остров
Какой-то остров

«Йо-хо-хо!» - невольно приходит на ум при любом взаимодействии с морем, передвигаешься ли на речном трамвайчике или же сидишь в баре круизного корабля. В последнем случае еще можно приобрести бутылку рому. Море привлекает своими волнами, закатами и рассветами. А особенно прикольно, когда на море завелись злые пираты. Ну... если это мы, конечно же.

Возьмем шейдер неба и шейдер воды - атмосфера готова! Что может быть проще. И да, я буду писать игру под браузер на Javascript с использованием библиотек Three.js и Cannon.js. Первую я использую для отображения 3D графики, а вторую - в качестве легковесного скриптового физического движка.

Я заставил небесную сферу и плоскость воды двигаться вместе с кораблем. Это обеспечивает практически бесконечный мир - только по мере движения будут подгружаться разные острова. Волны привязаны к началу координат, а сама плоскость воды передвигается. В этом примере уменьшен размер плоскости, чтобы было видно, как это работает.

Ладно. Небо и землю, а точнее, небо и море, мы создали. А теперь нужен корабль! Надо его где-то реквизировать... Я взял за основу бесплатную модель и практически полностью ее переделал, попутно существенно убавив количество полигонов. От исходника остался только корпус, и то не без трансформаций. Игровой мир включает 13 островов, на каждом из которых игрок проходит миссию. Вообще, игра называется «13 черепов». Как не сложно догадаться, на каждом острове после прохождения миссии вы получаете один череп. В игре присутствует карта, причем, в масштабе и по ней движется ваш кораблик.

Карта
Карта

Анимации

Теперь - о том, как я программировал анимации. Я не вижу смысла приводить здесь большое количество кода. Думаю, достаточно объяснить принцип, а код ведь можно написать на любом языке.

Основной момент состоит в том, что в игре одновременно работают 4 анимации: небосвод (движение солнца, смена дня и ночи), волны, движение кораблей и полет ядер при стрельбе. Последняя анимация ставится на паузу, когда никто не стреляет. Движение всех кораблей осуществляется посредством одной анимации, просто в начале своего движения каждый корабль добавляется в некий кэш (массив). И в анимации они все перебираются в цикле, где изменяются их координаты в соответствии с таймингом и углами поворота. Аналогично для ядер: общий кэш с привязкой каждого ядра к кораблю.

Технически в моей игре анимацию можно осуществить двумя способами. Первый - это, как я его назвал, глобальный таймер (globalTimer), а второй - мой движок анимации. С точки зрения результата, это одно и тоже, только в движке можно задать больше параметров. В первом варианте, то есть, в глобальном таймере, используется стандартная функция Javascript setInterval, но с моей надстройкой, которая засовывает все добавляемые события в один интервал и задает единый тайминг как общий знаменатель. Такую схему я реализовал причине того, что слишком много одновременно работающих setInterval (буквально от пяти и более) сильно просаживают производительность и делают фреймрейт рваным. А так работает только один setInterval. Движок же анимации основан на requestAnimationFrame, который умеет выравнивать фреймрейт и делать движение более плавным. На глобальный таймер есть смысл повесить редкие периодические события типа движения солнца - его позиция обновляется раз в пять секунд. А на движок анимации лучше повесить полет ядер, чтобы они двигались плавно и с максимально возможной частотой кадров.

На самом деле, на глобальный таймер я повесил и обновление шейдера небосвода, и волн, и движение кораблей. А на движок анимации - только стрельбу. Параметр ti - это периодичность срабатывания события в миллисекундах. Браузер подстраивает обновление графики под 60 кадр/сек - это чуть больше 16 мс на кадр. Я задал для движения кораблей интервал 15 мс, чтобы очередная итерация обновления позиций кораблей гарантированно срабатывала бы в момент отрисовки и не выпадали бы кадры. Остальные события я сделал кратными пятнадцати. Я не вижу смысла обновлять шейдер воды чаще 30 кадров в секунду (ti=30), а покачивание корабля - оно слишком медленное и его достаточно обновлять всего 15 раз в секунду (ti=60). Ради эксперимента я ставил и более высокие частоты, но никакой разницы не заметил.

//движение кораблей
m3d.lib.globalTimerSoft.addEvent({name: 'shipmove', ti: 15, d0: Date.now(), sign: 1, f: function() {
        ...
}});

//вода
m3d.lib.globalTimerSoft.addEvent({name: 'water', ti: 30, d0: Date.now(), f: function() {
        ...
}});

//покачивание кораблей на волнах
m3d.lib.globalTimerSoft.addEvent({name: 'shipshake', ti: 60, d0: Date.now(), sign: 1, f: function() {
        ...
}});

Джаваскриптовый setInterval устанавливается здесь в 15, то есть, в самое маленькое кратное значение. Ну а события с таймингом 30 просто срабатывают каждую вторую итерацию, а с таймингом 60 - каждую четвертую.

В этой системе можно принудительно менять setInterval, если, например, окно неактивно - пользователь свернул браузер или переключился на что-то другое. Тогда нет смысла молотить 60 кадров в секунду и можно сбросить частоту раз в шесть:

m3d.lib.addListner(window, "blur", function(event) {
    m3d.lib.globalTimerSoft.interval = 90;
});

m3d.lib.addListner(window, "focus", function(event) {
    m3d.lib.globalTimerSoft.interval = 15;
});
Сообщение при потере фокуса окна
Сообщение при потере фокуса окна

При снижении частоты кадров игра превращается в слайд-шоу. Но, когда на нее не смотришь, то это и хорошо. Нагрузка на CPU и GPU существенно падает, почти до нуля, а все события в игре все равно выполняются, то есть, игра не ставится на паузу. И еще одна анимация - небосвод (движение солнца, смена времени суток) обновляется раз в 5 секунд. Но там у меня поверх самого события есть еще надстройка, которая позволяет задать параметры заполняющего, прямого, атмосферного освещения и плотности тумана в зависимости от высоты солнца. Поэтому данная анимация добавляется через ту надстройку.

Полет же ядер я повесил на движок анимации. Частота его работы не снижается даже при снижении частоты глобального таймера. То есть, эти системы работают независимо друг от друга. Все-таки ядра должны всегда лететь плавно, с частотой 60 fps, чтобы они не проходили сквозь цели. А то может получиться так, что в предыдущей итерации ядро еще не долетело, а в следующей уже перелетело за цель. Поэтому при движении ядра частота отрисовки кадров временно поднимается до 60 fps за счет того, что начинает работать анимация. В мой движок анимации событие добавляется так:

m3d.lib.anim.add(
      'moveCannon', 1, animT, 'and', userpar, 
      [
            {lim1: x0, lim2: x,  sstart: x0, sfin: x, t: 9*1000},
      ], 
      function(){
            var self = this;
            var state = self.par[0].state;
            ...
      }
);

m3d.lib.anim.play();
m3d.lib.anim.apause(1,0);

Смысл тут в том, что за некоторое время (9 секунд, это максимальное время полета ядра в игре) изменяется параметр state от lim1 до lim2. И текущий state доступен в callback-функции. Ну а в последней уже можно двигать координаты ядер, в зависимости от прошедшего времени. По сути, в данной анимации state не важен, достаточно только обновлять координаты каждого ядра в зависимости от шага времени между итерациями. Параметр animT - это общее время работы анимации. В данном случае я задал там огромное число, равное длительности нескольких суток, так как анимация не должна прекращаться: ведь стрелять могут на протяжении всей игры. В начале анимация запускается и сразу же ставится на паузу. А когда происходит выстрел, то она возобновляется: m3d.lib.anim.acontinue(1,0). Внутри функции перебирается массив ballCache - это летящие ядра. Если он пуст, то анимация снова ставится на паузу. Также в теле функции работает физический движок Cannon.js. Вычисленная им позиция ядра (ball.phy.position) копируется в визуальную модель ядра Three.js (ball.geo.position). Это специфика работы Cannon.js.

var t = Date.now();
var dt = t - self.userpar.t0;
self.userpar.t0 = t;
apscene.canworld.step(dt / 1000, dt / 1000, 3);
for (var i = 0; i < ap.game.state.ballCache.length; i++) {
    if (ap.game.state.ballCache[i].finished == false) {
        //новая позиция каждого ядра
        ap.game.state.ballCache[i].ball.geo.position.copy(ap.game.state.ballCache[i].ball.phy.position);
    };
};
Стрельба из пушек
Стрельба из пушек

Горы

Я долго искал средство для того, чтобы создать более-менее красивые горы для некоторых островов. И в итоге остановил свой выбор на маленькой программке 2005-го года Nem's Mega 3D Terrain Generator, дистрибутив которой весит всего 522 Кб. Так я создал геометрическую сетку скал. Ну а потом в редакторе натянул текстуру и слегка оптимизировал. Получилось довольно симпатично, на мой взгляд.

Скалистый остров
Скалистый остров

Боты

В данной версии игры пока нет движущихся кораблей противника, но есть пушки, стреляющие с берега. Если ваш корабль находится в квадрате действия одной из пушек, то она открывает по вам огонь. Я сначала не мог придумать способ наведения пушек на корабль игрока. Точнее, само наведение задается легко. Если cannon - это 3D модель пушки, а target - это наш корабль, то достаточно выполнить:

cannon.lookAt (target.position.x, cannon.position.y, target.position.z);

И пушка повернется в сторону корабля. По оси «y» используется позиция не корабля, а пушки. Это для того, чтобы пушка не отклонялась от своей вертикали. Наклонять мы будем ее ствол. Проблема в том, что для каждого бота (пушки) задается дуга в радианах, в границах которой этот бот может стрелять. Это для того, чтобы она не стреляла в горы, если мы скрылись за ними, например. Однако, углы Эйлера, которые использует Three.js, не дают понять, в какую сторону повернута пушка по одной из осей.

В итоге я нашел решение, заключающееся в том, что мы создаем вектор, затем при помощи метода getWorldDirection определяем направление пушки и копируем его в вектор, а затем через арктангенс узнаем угол поворота (r) вектора по вертикальной оси (y). Затем сравниваем, входит ли этот угол в диапазон, заданный для поворота пушки. И если да, то тогда она в нас стреляет.

var vec = new THREE.Vector3(0, 0, 0);
var dir = cannon.getWorldDirection(vec);
var r = Math.atan2(dir.x, dir.z);
Пушка с берега стреляет по кораблю
Пушка с берега стреляет по кораблю

Примечательно, что я долго искал это решение, а когда нашел, то в этот момент за окном раздались звуки фейерверка.

Коллайдеры

Коллайдеры я расставлял в редакторе поверх модели локации, а затем сохранил их отдельным объектом. В игре они загружаются с opacity=0, то есть, невидимыми. И эти меши перебираются в цикле во время движения корабля.

Коллайдеры
Коллайдеры

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

var originPoint = player.position.clone();
var ray = new THREE.Raycaster(originPoint, directionVector.clone().normalize());
var collisionResults = ray.intersectObjects(meshList, false);

Для корабля и препятствий это работает. Правда, я пока еще не реализовал отталкивание от препятствия. Пока корабль при встрече с коллайдером просто перестает двигаться. Но можно вырулить, если покрутить штурвал. Однако, периодически можно застревать намертво, поэтому сталкиваться со скалами пока не рекомендуется.

А вот с пушечными ядрами посложнее. С корабля их можно выпустить сразу пять. Плюс - могут стрелять боты. То есть, в кэше ядер может находиться 6 и более объектов. И для каждого ядра нужно просчитывать столкновение с коллайдерами каждого из кораблей (или пушек ботов), имеющихся в локации, то есть, всех со всеми, что приводило к заметному падению производительности. 6x6 = 36 одновременных обсчетов столкновений. Рейкаст начинал тормозить. Налицо необходимость оптимизации. О ней - ниже.

Скалы с коллайдерами
Скалы с коллайдерами

Оптимизация

1. Коллайдеры.

Первый очевидный шаг - убрать просчет столкновения ядра с коллайдером своего же корабля. Мы ведь не в себя стреляем. То есть, уже - минус шесть из тридцати шести. Итого: все еще 6x5 = 30 просчетов столкновений.

А потом я подумал, что нет необходимости проверять столкновения ядер со всеми объектами. Достаточно проверять только с ближайшими. Но поиск расстояния от летящего ядра до каждого объекта на сцене - это дорогое удовольствие, так как оно связано с интенсивными вычислениями квадратных корней. Однако в Three.js можно вычислить для 3D объекта (меша) обрамляющий его бокс, ориентированный по осям координат. Для всех статичных объектов его можно предрассчитать при загрузке локации.

var helper = new THREE.BoxHelper(mesh);
helper.geometry.computeBoundingBox();
var box = helper.geometry.boundingBox;

Результат выглядит так:

box: {
    "min": {
        "x": -788.352,
        "y": -499.999,
        "z": 2858.697
    },
    "max": {
        "x": 113.252,
        "y": 500,
        "z": 3000.322
    }
}

Но как понять, что этот объект нужно включать в расчет коллизий, если ядро подлетает к нему практически в момент столкновения? Ведь бокс обрамляет непосредственно объект. Тут уже и само столкновение надо обрабатывать... Очевидно, можно просто расширить бокс.

var d = 450;
box.min.x -= d; box.max.x += d;
box.min.y -= d; box.max.y += d;
box.min.z -= d; box.max.z += d;

И тогда при полете ядра можно проверять, вошло ли ядро в этот «подлетный бокс» или нет, и на основании этого включать или не включать объект, находящийся в этом боксе, в список коллизий для обработки. А как проверить, вошло ли ядро в «подлетный бокс»? Тупо по координатам: x, y и z ядра должны быть больше минимальных и меньше максимальных значений координат вершин бокса. И никаких квадратных корней. Конечно, перестраивать список коллизий для каждого ядра слишком часто тоже не стоит. Можно делать это с каким-то шагом.

if ((Math.abs(position.x - old.x) > step.x) || (Math.abs(position.y - old.y) > step.y) || (Math.abs(position.z - old.z) > step.z)) {
    old.x = position.x;
    old.y = position.y;
    old.z = position.z;
    collisionsListUpdate(position, baselist, bounds);
};

baselist здесь - общий список коллайдеров всех объектов локации, а bounds - общий список предрассчитанных боксов для всех этих объектов. И да, для движущихся объектов (типа кораблей) соответствующие записи в bounds придется обновлять, так как границы и положение их в пространстве меняются. Но таких объектов очень малое количество. И этот подход имеет свой эффект. Теперь в кэше коллизий для каждого ядра болтается не по 5-6 объектов, а максимум - 1-2. А большую часть времени и вообще ничего.

Если рассчитанные боксы добавить на сцену, то получится примерно следующее. В игре же эти боксы никуда не добавляются, используются только данные по ним (координаты). И да, здесь визуализированы только сами боксы (границы объектов), еще не расширенные на дельту, то есть, это не «подлетные боксы». Но смысл, думаю, понятен. «Подлетные» просто чуть больше. Бокс корабля здесь такой низкий, потому что он создается не вокруг самого объекта, а вокруг коллайдера, а коллайдер для корабля я сделал низким.

Границы 3D-моделей по осям координат, основа для расчета «подлетных боксов»
Границы 3D-моделей по осям координат, основа для расчета «подлетных боксов»

Таким образом, в итоге проверяются столкновения ядер не со всем объектами, а только с теми, в «подлетных боксах» которых ядра оказываются.

2. Графика.

Ну с оптимизацией графики все и так понятно. Делаем как можно меньше полигонов и упаковываем текстуры по возможности в текстурные атласы. Еще я убрал все прозрачные объекты, так как они «отжирают» производительность, и использовал вместо этого текстуры alpha map.

Миссия «Сундук мертвеца»
Миссия «Сундук мертвеца»

3. Физика.

Физику движения ядер берет на себя Cannon.js. Для каждого ядра создается физическая модель, которая добавляется в кэш движка, где находится, пока ядро летит. На данном этапе здесь нечего оптимизировать. Но я как-то писал игру, в которой один физический объект летел над другими физическими объектами с вероятностью на них упасть и вызвать взаимодействие отталкивания. Так вот, я добавлял в физический движок только те объекты, которые оказывались под летящим объектом в определенном квадрате. А остальные, отдаленные, удалял, поскольку вероятности упасть на них не было. То есть, я точно так же перестраивал кэш физического движка с некоторым шагом. И это давало колоссальный прирост производительности. Когда в игре появятся разрушаемые береговые форты, то я воспользуюсь этой схемой и буду добавлять в физический движок только то, что находится вблизи (каждого) ядра в каком-то квадрате.

Итоги оптимизации

Думаю, достаточно упомянуть, что игра работает в браузерах на, мягко говоря, не самом мощном телефоне стоимостью 13 000 рублей. Играть вполне комфортно.

Chrome, Android
Chrome, Android

Миссии

В данный момент в игре всего две миссии - обучающая и «Сундук мертвеца». Задумка такова, что на каждом из тринадцати островов будет предложено свое задание, за выполнение которого игрок получает череп. Технически это позволяет разбить игровой мир на 13 локаций, каждая из которых загружается при приближении к ней, а та, что осталась позади, удаляется из памяти вместе со своими 3D-моделями, коллайдерами, «подлетными боксами» и т.д., прекращая оказывать нагрузку на вычисления. И мир может быть практически бескрайним. В данный момент локации без миссий заменены на стандартный островок с пальмой. У одной из локаций находится сундук, который восполняет здоровье на 100%.

В путь!
В путь!

Планы

В дальнейших планах - создание миссий с кораблями противников и боем против них. Техническая база для этого есть. Также, требует доработки графика и нужно добавить визуальных эффектов. Сетевую игру тоже планирую, но это будет не королевская битва, а некий кооператив: один игрок выполняет одну миссию, другой - другую. А на то, что уже сделано, ушло чуть больше месяца свободного времени.

Комментарии (34)


  1. Sander80
    16.07.2022 19:27
    +5

    Но поиск расстояния от летящего ядра до каждого объекта на сцене - это дорогое удовольствие, так как оно связано с интенсивными вычислениями квадратных корней.

    Зачем брать корни, если можно сравнивать квадраты расстояний?


    1. Kempston Автор
      16.07.2022 19:30
      +2

      Да. Была и такая мысль. Мне показалось, что сравнивать просто координаты (x2-x1) лучше, чем квадраты ( (x2-x1)*(x2-x1) ). Но главное - что схема с "подлетными боксами" будет полезна для сценариев с разрушаемыми объектами при использовании физического движка. Т.е., это такой задел на будущее.


  1. ziblis
    16.07.2022 20:36

     Не сочтите навязчивым, но подскажите: как вернуть такую тему оформления в гугл хром (я с 2010 года пытаюсь понять за кой хрен платят дизайнерам за UI, если вот прям в большинстве продуктов они гонят такую лютую дичь...)


    1. Kempston Автор
      16.07.2022 20:49

      А вот, к сожалению, не подскажу. Просто у меня это и есть старый хром, 62 или 65. Я его использую для разработки игр. Чтобы чистить кэш, не боясь "грохнуть" данные сайтов из свежей версии браузера. А WebGl везде работает одинаково.


  1. k12th
    16.07.2022 22:43

    А потыкать пока негде, да? Не нашел в статье ссылки.


    1. Kempston Автор
      16.07.2022 23:03
      +3

      Можно, вот здесь: https://m3d.me/game/sb/h/


      1. developer7
        17.07.2022 15:06

        Потыкал. Попался баг. Если корабль плывёт и стрельнуть из пушки и жать влево. То вылетаешь из корабля и остаёшься на месте. Я так понял баг связан с привязкой к полёту снаряда.


        1. Kempston Автор
          17.07.2022 15:14

          Это не баг, а фича) После выстрела камера привязывается к ядру, чтобы видеть, куда оно попало. Но, да, реализовано кривовато. И наверно надо по нажатию любой кнопки возвращать камеру на корабль.


          1. developer7
            17.07.2022 15:19
            +1

            Это я потом понял. Она привязывается если не жать влево. Если жать то просто вываливаешься из корабля. Остаёшься на месте. Корабль уплывает. На него можно посмотреть. При этом ядро вообще не видно. Я попался на этот эффект сразу несколько раз — и даже не знал что к ядру привязка идёт.


            1. Kempston Автор
              17.07.2022 15:25

              По-моему, это не зависит от нажатия влево. Кажется, это зависит от угла стрельбы. Если он большой, то камера следует за ядром. А если маленький (стрелять вниз), то она остается на месте. Просто она следует за ядром до его падения на определенную высоту. И там и остается до окончания перезарядки. Что-нибудь с этим сделаю, конечно.


    1. Kempston Автор
      16.07.2022 23:44
      +1

      Русскоязычная версия:

      https://m3d.me/game/sb/h/?lang=ru


  1. Radisto
    17.07.2022 05:23
    +1

    Решили назвать Черной жемчужиной? Не набегут переводчики с криками, что вы нарушили какие-либо их права? Может, что-нибудь из классики: Warlus, Месть Королевы Анны?

    PS чувствовал себя Израэлем Хэндсом - попал не с первого раза, и это в меня еще не стреляли всякие Трелони)))


    1. Kempston Автор
      17.07.2022 08:00

      Не думаю, что что-то нарушаю. Но могу и переименовать, если придумаю название получше. Тогда уж надо придумать что-то похожее, но новое.


      1. developer7
        17.07.2022 15:08
        +2

        Белая жемчужина ))


        1. Kempston Автор
          17.07.2022 15:15

          Ну, кстати, вариант... Спасибо.


  1. Bronx
    17.07.2022 09:53
    +3

    Что-то Солнце у вас встаёт на западе и проходит через север :)


    1. Kempston Автор
      17.07.2022 10:23
      +1

      Ну... это же сказочный мир... Это же игра... А ведь и правда! Спасибо за такое дельное замечание! Я как-то не ассоциировал солнце с картой. Пожалуй, проще будет развернуть небесную сферу на 180 градусов. Так и сделаю в следующем обновлении.


  1. Areso
    17.07.2022 11:44

    Выглядит довольно круто, хоть и бедновато на детали.

    Ваша игра чем-то напомнила браузеру Sky2Fly, правда там все на флеше было.


    1. Kempston Автор
      17.07.2022 12:06

      Спасибо. Если речь о графических деталях, то, да, у меня есть с этим проблема, я такой себе 3D моделер. Но постараюсь усовершенствовать графику. В миссиях тоже будут побочные квесты и моменты.


  1. Mingun
    17.07.2022 12:45
    +2

    Вам бы поработать над понятностью интерфейса и над обучающей миссией в частности. Многие кнопки в интерфейсе не работают, а предназначение тех, что работают, с первого взгляда непонятно:


    1. Кнопка в левом верхнем углу открывает меню, в котором работают только кнопка с крестиком (очевидно, закрывает меню) и самая левая кнопка (не очевидно, что она делает, по факту там несколько кнопок в одной, стрелки меняют размер интерфейса, пустой чекбокс выходит из полноэкранного режима, заполненный чекбокс ничего не делает).
    2. Кнопка в правом верхнем углу открывает элементы управления для мобилок. Со стрелками понятно — вперёд/назад и повороты. Остальные непонятно, что делают и, похоже, не работают. При нажатии на «крестик прицела» ещё что-то в визуальном плане меняется, но и только.
    3. Не нашёл способа вернуться в меню выбора миссий, только закрыть вкладку браузера и открыть заново.
    4. Аналогично, не нашёл способа просмотреть брифинг текущей миссии, похоже, после закрытия его уже не открыть.
    5. Карта открывается на «M», но об этом можно только догадаться.
    6. Аналогично, управление кораблём WASD, но об этом можно только догадаться.
    7. Режимы просмотра переключаются по клавишам 1–6, есть слабая подсказка в виде цифр на нижней панели (причём 6 там не продублирована — оказалось, это свободная камера, не привязанная к кораблю).
    8. Не очень понятно назначение режима 4 — почему-то только в нём есть кнопка открытия карты, хотя по горячей клавише она открывается из любого режима. Управлять кораблём в этом режиме невозможно — клавиши движения крутят камеру (хотя для этого уже есть мышка).
    9. Почему-то стрельба только по кнопкам в интерфейсе, горячей клавиши для стрельбы нет.
    10. Непонятно время перезарядки — нужен визуальный индикатор, когда она закончится.
    11. Заметность маркера цели очень низкая — отплывёшь далеко и уже хрен найдёшь.
    12. Карта не помогает: она показывает только положение корабля и цели, но не показывает направление движения.
    13. Кстати, сама карта очень неудобная: нет масштабирования, из-за чего на близких расстояниях маркеры сливаются и вообще ничего не поймёшь, где что.

    По обучающей миссии: всё просто — это не обучение :) Обучение должно рассказывать, что надо нажать, чтобы достичь поставленной задачи. У вас же просто даётся цель, а там вертись, как хочешь.


    1. Kempston Автор
      17.07.2022 13:35

      Спасибо за подробный отзыв!

      1. Меню по левой верхней кнопке пока толком не работает. По сути, я его задумал для изменения параметров графики. Те кнопки не просто увеличивают интерфейс, а меняют разрешение окна. Это может быть полезно для девайсов с низкой производительностью.

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

      3. Меню появляется после прохождения миссии. Но, пожалуй, вы правы, нужна возможность отказа от текущей миссии в любой момент.

      4. Да, недоработка. Сделаю кнопу вызова книги. Хотя, текущее задание отображается вверху.

      5. Карта открывается на М - это вроде бы стандарт для игр? Еще она открывается через меню с подзорной трубой и картой. Или это не так очевидно?

      6. WASD - тоже стандарт. Или вы имеет в виду, что нужна подсказка по всем кнопкам управления в игре. Вероятно, нужно отдельное меню Справка.

      7. Режим 6 - для разработки/тестирования. Позже я его вообще уберу.

      8. Режим 4 - это обзор с мачты, с высоты. Иногда полезно для того, чтобы посмотреть, куда плыть дальше. Я подумал, что управлять кораблем с мачты должно быть нельзя, это нелогично.

      9. Так там на кнопках интерфейса есть подсказка. 0 - стрелять одной пушкой, Shift+0 - залп из всех орудий.

      10. Согласен насчет индикатора времени зарядки.

      11. Думаю, интереснее ориентироваться по стрелке вверху. Я вообще хочу убрать маркер цели, если локация еще не загружена, то есть, на отдалении. По идее, по морю надо плыть по компасу)

      12. Согласен, добавлю.

      13. Согласен.

      По поводу обучения тоже соглашусь. Но, вместе с тем, не хочется тоже разжевывать каждую кнопочку. Меня, например, в играх это раздражает, когда тебе говорят - чтобы двигаться вперед, нажмите W и т.п.


      1. Mingun
        17.07.2022 14:45

        Еще она открывается через меню с подзорной трубой и картой.

        Только вот то меню не открывает карту :) А просто в том режиме есть кнопка для открытия карты. Я не понимаю, почему она есть только в том режиме.


        Понятно, что многие кнопки стандарт (хотя насчёт карты — зачастую и «Tab» для неё используется), но упомянуть их назначение надо. В идеале должна быть справка в меню по всем горячим клавишам управления.


        0 — стрелять одной пушкой, Shift+0 — залп из всех орудий.

        Стрельба на «0» — это очень неудобно, потому что «0» расположена совершенно в другой части клавиатуры, нежели кнопки движения. Лучше повесить на пробел, «Q» или «E».


        Я подумал, что управлять кораблем с мачты должно быть нельзя, это нелогично.

        Ну, если вы хотите на ровном месте добавить проблем игроку, то, наверное, этот подход оправдан… Но лично я думаю, что это лишнее. У вас же не симулятор сурового морского волка, в одиночку рулящего кораблём, а весёлые пострелушки «Йо-хо-хо и бутылка рому» (насколько я понял задумку игры). Зато за постоянные метания между мачтой и штурвалом игроки точно не скажут вам «спасибо».


        Думаю, интереснее ориентироваться по стрелке вверху.

        Честно говоря, я так и не понял, что показывает стрелка наверху :( Соответственно, и как по ней ориентироваться, тоже непонятно. А ещё в темноте я елё нашёл эту несчастную лодку из обучения, которую надо было потопить.


        По обучению: вообще-то здесь управление отличается от привычного «шутерного». Потому что «W» — это не «плывём вперёд», а «поднять паруса», а «S» — это не «плывём назад», а «спустить паруса» (а заплыв назад вообще невозможен). И «A» и «D» — не стрейф, а поворот влево/вправо (и работает он, сктати, только когда корабль движется). То есть, управление нетипичное. Это надо объяснить.


        Ещё обнаружил баг: спустя некоторое время после выстрела камера переходит в режим свободного полёта. Соответственно, если корабль движется, через некоторое время он начинает «убегать» от тебя.


        1. Kempston Автор
          17.07.2022 15:09

          Стрельба на «0» — это очень неудобно, потому что «0» расположена совершенно в другой части клавиатуры, нежели кнопки движения. Лучше повесить на пробел, «Q» или «E».

          Для движения еще можно использовать курсорные стрелки, тогда 0 - рядом на цифровой клавиатуре. Для прицеливания можно использовать стрелки с шифтом. И тогда можно управлять игрой одной рукой... Но понимаю, что этот вариант на любителя . Я просто продублирую стрельбу где-то в левой части клавиатуры.

          Честно говоря, я так и не понял, что показывает стрелка наверху 

          Она всегда указывает направление на цель.

          поворот влево/вправо (и работает он, сктати, только когда корабль движется)

          Так удобнее, когда нужно быстро остановиться и прицелиться для стрельбы - чтобы еще и поворот штурвала не выравнивать.


  1. Krasnoarmeec
    17.07.2022 12:50
    +4

    Классная игрушка!

    Выскажу своё мнение. Детали интерьера (скалы, прорисовка лодок и т. д.) в играх про пиратов играют не такую уж важную роль. Главное это всё же это сюжет. Для меня "золотым стандартом" является "Pirates! Gold" 1993 года с его миссиями по поиску пиратов, союзами/войнами между государствами, различными типами судов, возможностью захватить город и конечно же губернаторскими дочками. ????

    В принципе, пиратская тема вполне востребована: барочные интерьеры в противовес нищему населению, "романтика с большой дороги", "историчность" персонажей - всё это ещё ждёт своего воплощения.


    1. Kempston Автор
      17.07.2022 13:40
      +2

      Вот, про захват города под свою, так сказать, юрисдикцию я уже думаю. Но без выхода на сушу. Либо будет выход только на причал от первого лица. Это будет одна из следующих миссий.

      Мне бы не хотелось добавлять торговлю, различные стратегии. Игра будет больше с упором на экшен и квесты - поиск тайников и т.д. Это довольно простая игра. Что-то эпичное я вот так сходу не потяну) Иначе у меня на это уйдет много лет. Начнем пока с простого...


      1. Krasnoarmeec
        17.07.2022 16:04
        +1

        Игра будет больше с упором на экшен и квесты - поиск тайников и т.д. Это довольно простая игра.

        Самое простое - это добавить "историчности" в карты и миссии. Добавьте старые карты:

        • Не ограничивайтесь только крибским регионом, малайские и сомалийские пираты существуют и по сей день.

        • Кроме того были ещё контрабандисты, шотландские борцы за независимость (см. "Похищенный" Стивенсона).

        • Да и вообще, по Стивенсону можно целый набор квестов организовать.

        Разбросайте по карте квесты в виде реальных городов, вроде Картахены, Тортуги и прочих, назовите противников именами реальных персонажей.

        И игра просто засверкает совсем другими красками!


        1. Kempston Автор
          17.07.2022 16:35
          +1

          Да. Мысль, конечно, отличная. Исторические названия добавить на карту можно. Но не получится ли так, что содержание будет недотягивать до формы. Мои способности 3d-моделера почти никакие. И я что-то сомневаюсь, что пара сараев на острове сможет сойти за Тортугу... Хотя, с другой стороны, сделать коробки домов и натянуть на них текстуры не так уж сложно. Это - не персонажа моделировать...


        1. Alexey2005
          17.07.2022 16:37
          +2

          А наиболее чудовищных масштабов пиратство достигло во времена Римской республики. Во времена расцвета средиземноморского пиратства под полным пиратским контролем находилось около 400 городов, пиратские флотилии насчитывали суммарно около 10 тыс. кораблей и не менее 30 тыс. собственно моряков.

          особенно возмущала людей их бесстыдная роскошь. Пираты, совершенно не похожие на оборванных головорезов, занимались своим промыслом на кораблях с позолоченными парусами, пурпурными навесами на верхней палубе и посеребрёнными вёслами.
          Как особенность пиратов Плутарх отмечает, что они были первыми известными людьми, кто поклонялся Митре. Сообщалось, что они совершали странные церемонии в Олимпосе, приморском городе в заливе Памфилии, но в честь Митры или другого божества — неизвестно. Неподалёку от того места находилась гора Химера, культовое место, известное постоянным подземным пожаром; во времена Зеникета из него били видимые издалека языки пламени
          Наглость пиратов была столь велика, что от них регулярно страдали многие знатные роды, однажды пираты захватили в плен даже самого Юлия Цезаря (и получили за него выкуп).
          Пиратство особенно усилилось во время Митридатовых войн. Согласно Аппиану, сам Митридат VI вывел пиратство на новый уровень и был настолько тесно связан с пиратами, что, когда он однажды потерпел кораблекрушение, он без сомнений пересел на пиратский корабль и добрался на нём домой.


  1. Daddy_Cool
    17.07.2022 17:49
    +1

    Занятно. Я постарался выбросить корабль на берег, кажется сел на мель и каким-то чудом с неё слез. Скрип дерева заставляет вспомнить капитана... нет, не Джека Воробья, а Блада.


  1. Radisto
    17.07.2022 18:51
    +1

    Играть с мобилы конечно нереально (карту я так и не нашел, без нее ничего не вышло, пару раз разбился о скалы и всё). В своё оправдание скажу, что опыт игр нулевой (ну не играю я), а для нулевого опыта непонятно всё управление. Обучение фактически отсутствует. Хотя смотрю, геймеры со стажем интуитивно поняли всё. Наверное на такую целевую аудиторию надо рассчитывать.

    Но, отпинай меня Деви Джонс, атмосферненько! Семь футов вам под килем


    1. Kempston Автор
      17.07.2022 20:13
      +1

      Спасибо! Карту можно вызывать из нижнего меню - кнопка с картой и подзорной трубой. Но вообще, можно просто двигаться по стрелке вверху, она указывает направление. Да, согласен, управление для мобилок еще не доработано.


      1. Radisto
        18.07.2022 13:44

        Точно! Теперь увидел. Там просто включался вид глазами марсового на салингах, и я не понимал куда жать.


  1. Tutanhomon
    17.07.2022 23:24
    +1

    управление надо инвертировать. Если вы делаете движение камеры через клик+драг, то должно быть все наоборот, будто вы тянете за экран. Если бы вы спрятали курсор и кликать не нужно было - тогда да, все верно


  1. khusamov
    19.07.2022 16:17

    Круто получилось! А сайт игры будет? А исходники на гитхабе доступны?