На этот раз я буду улучшать игровой процесс, а ещё немного залезу в алгоритм трассировки лучей (не то, чтобы он мне был сильно нужен, но кое-что из него может быть полезным).
В прошлой части я подчищал хвосты (закрывал техдолг) и в этом несколько преуспел. На карте появились маски с индикацией возможных действий, персонажи стали более эффективно перемещаться и всё такое. Теперь настало время сделать игру приятней для пользователя. Ну, приступим.
Разрушаемая карта
Некоторые объекты на карте просто просятся быть разрушенными. В принципе, это очень интересный подход, когда маршрут можно буквально пробивать. Потенциально уничтожаемые объекты должны:
- иметь некоторый запас прочности, а не складываться после случайного попадания;
- разрушаемый объект должен иметь некоторую соответствующую индикацию при наведении оружия;
- их внешний вид должен зависеть от этого запаса прочности (т.е. чем его меньше, тем хуже выглядит объект);
- при завершении запаса прочности - анимация разрушения (притом, если разрушились несколько объектов - они должны разрушаться одновременно, а не последовательно);
- разрушенный объект замещается новым, который как-то иначе обрабатывается в рамках игрового процесса.
В общем, вроде всё просто, а по факту работы немало. Приступим.
Для начала я ввёл описание разрушаемых объектов: то есть какой объект может разрушиться, в какой превратиться и какой запас прочности у него будет. Тут есть некоторая ловушка: надо учесть два фактора сразу. Во-первых, у каждого возможного объекта может быть разный запас прочности. Во-вторых, это надо как-то легко применить ко всей карте, а не указывать для для каждого объекта значение отдельно.
Я пошёл таким путём: создал параллельную структуру, в которой хранится информация о разрушаемых блоках, усовершенствовал код и, в конечном итоге, неплохо так оптимизировал его, что позволило улучшить управляемость как отрисовкой, так и прочими процессами.
Чтобы отличать блоки - добавил дополнительную маркировку и установил запас прочности в процентах в правом нижнем углу. Для начала - сойдёт.
Тут, кстати, я не остановился и предусмотрел возможность цепочек уничтожения: это когда здание сперва превращается в руины, а потом - просто в открытое пространство. На мой взгляд, вышло неплохо.
Улучшенная индикация
Следующим шагом я решил усовершенствовать индикацию оружия. Дело в том, что существующая - не объясняет, почему то или иное оружие нельзя применить: только период восстановления показан. А ещё непонятна цена вопроса: есть оружие, которое "стоит" больше очков активности, а есть такое, которое стоит меньше. Ну и эти буковки - вообще непонятно, что они значат. Куда лучше иконки. Этим и займусь!
Теперь индикация стала более предсказуемой (хотя иконки, коль скоро я рисовал их сам, оставляют желать лучшего). Да и количество требуемых очков действий делает невозможность выстрелить более предсказуемой.
Заодно немного поправил траекторию стрельбы. А то финальная точка упиралась в последнюю возможную для прохождения зону, а вовсе не в преграду. Вроде пустячок, но очень важно!
Взрывы
Случаются взрывы на карте довольно часто, а вот анимации на них нет никакой. Ещё недавно я считал, что это мелочь - в любой момент добавить можно. Но теперь понимаю: если об анимации заранее не позаботится - потом встраивать будет её то ещё веселье. Да и вражеские роботы, после уничтожения, должны взрываться и повреждать вокруг всё. Чем больше запас здоровья, тем шире должен быть взрыв. Но на 1 клетку минимум. Сила взрыва, полагаю, должна быть связана с запасом его оружия и причинять ущерб вокруг, соответствующий повреждению от самого сильного оружия.
С анимацией я не сильно старался, однако теперь всё вокруг разрушается. Хотя мне не нравится, что взрыв появляется одномоментно. Хочется как-то сэмитировать взрывную волну, что она шла от центра к краям. Это потребует немного пересмотреть алгоритм формирования окружности, но это, думается мне, дело не слишком сложное.
Использовал я старый, как компьютерные игры, приём - всплывающие очки повреждения при подрыве вражеского робота. Получилось довольно эффектно, хотя по времени, отчасти, слишком быстро. Можно поднастроить потом ещё.
Продвинутое ограничение видимости
Этот вопрос я обдумывал некоторое время. В настоящее время видимость не ограничивается исключительно радиусом взора, но это не совсем правильно, т.к. могут быть некоторые зоны, внутри которых можно было бы укрыться от обзора. Например, за высокими зданиями противника не должно быть видно, а вот просторы, напротив, должны просматриваться без ограничений. Тут, как нельзя кстати, подойдёт трассировка лучей. Упрощённо говоря, мы будем проводить "лучи" до всех самых дальних точек карты до тех пор, пока луч во что-то не упрётся. То, во что луч упрётся - видно, то, что за ним (если объект, в который упёрся луч, не слишком большой) - в полутени и луч движется дальше; если объект средних размеров - позиция сразу за ним - не видно, следующая позиция - полутень, а потом - тень. Если же объект большой - то он просто перекрывает область, которая идёт за ним.
Для начала я проверил охват трасировкой. Важно было, чтобы каждая точка попадала бы в зону видимости хотя бы один раз. В принципе, все точки оказались посещены минимум один раз. Думаю, для больших карт суть будет примерно такая же, так что пока оставлю простую версию алгоритма.
Теперь буду останавливать трассировку, если она встретилась с большим объектом.
В общем, я пошёл дальше, изменив подход. Теперь всё то, что не видно - обозначается значком #, а всё, что видно - это счётчик, сколько раз зона поучаствовала в трассировке. Как можно заметить, точка отправления - всегда выходит из видимости, но это я позже поправлю. Теперь надо разделить видимость на тень и полутень: полутень - это тип тени, которая идёт за тенью, образованную высоким строением; она позволяет увидеть, какая ячейка карты там видна, но не позволяет видеть спрятавшиеся туда объекты. Но это немного позже. А пока разделю тень на тона.
Тут я пошёл дальше - теперь те объекты, которые отбрасывают тень и полутень получили градацию: 0 - прозрачно, 1 - полутень, 2 - тень и # - точка, до которой не дошло внимание луча (по сути, тоже тень). Всё, что осталось сделать - это наложить маску, в которой будет три типа полей: видно, частично скрыто и скрыто.
Теперь область видимости меняется по мере перемещения героя по карте. Противники, по-прежнему, видят лишь то, что попадает в радиус обзора.
По хорошему, это всё можно и нужно оптимизировать: не стоит прямо всю карту трассировать, достаточно лишь видимой части. Но это уже потом.
А пока что попытать счастья в борьбе с противником можно тут.