S.T.A.L.K.E.R. на движке Doom. Оружие

Прошло не так много времени с момента публикации прошлой статьи, но медлить нельзя, ведь неизвестно, что будет завтра. В этой серии статей мы создаем свой S.T.A.L.K.E.R. с маслинами и монолитовцами на движке idTech1.

S.T.A.L.K.E.R. на движке Doom. Оружие

В этот раз мы поговорим с вами об оружии, ведь ни один шутер не может без него обойтись.

В S.T.A.L.K.E.R. очень много видов оружия: пистолеты, автоматические винтовки и даже гранатометы, но остановиться я решил на обрезе ружья. Во-первых, я всегда любил дробовики и ружья из-за брутальности, внешнего вида и убойной силы. Во-вторых, переносить обрез на движок Doom намного интереснее и сложнее, чем банальный автомат Калашникова. И вскоре я расскажу, почему.

В предыдущей статье я поведал, как переносить модели из S.T.A.L.K.E.R. в Blender. Открываем Blender и из папки gamedata/meshes/weapons/bm_16 импортируем файл wpn_bm-16_hud.ogf. Это модель оружия, которую игрок видит перед своими глазами. В той же папке лежит файл wpn_bm-16.ogf. Это модель оружия, которое будет валяться на земле. Этот файл нам понадобится чуть позже.

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

S.T.A.L.K.E.R. на движке Doom. Оружие

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

Как я уже говорил, наименования спрайтов в Doom содержат 6 символов, из которых первые 4 — название спрайта, пятый — название кадра анимации, а шестой — номер, который определяет ракурс спрайта. В данном случае мы будем работать с пятым символом. Название кадра — это один символ от A до Z. Кроме того можно использовать левый слеш (\). Таким образом, для одного названия можно создать не более 27 кадров анимации. Конечно, если этого количества не хватит, всегда можно придумать новое название для недостающих спрайтов.

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

Если вывести на экран изображение с камеры, то мы увидим примерно следующее:

S.T.A.L.K.E.R. на движке Doom. Оружие

Так как обрез стреляет поочередно из двух стволов, нам потребуется три изображения для состояния покоя: два курка подняты; один курок поднят; оба курка опущены, и довольно много кадров для анимации перезарядки: Меченый перезаряжает правый ствол; Меченый перезаряжает оба ствола. Для анимации стрельбы сгодится всего один кадр: оружие приподнято из-за отдачи.

Результат:

S.T.A.L.K.E.R. на движке Doom. Оружие

Итого: 3 изображения для состояния покоя, одно — для стрельбы, 13 — для анимации перезарядки. Названия кадров начинаются с A и кончаются на Q. В процессе написания статьи я понял, что последний кадр назван неверно — вместо BSTKQ0 я назвал его BSTKPQ.

В названии спрайтов присутствует отсылка к Зловещим Мертвецам.

S.T.A.L.K.E.R. на движке Doom. Оружие

Спрайты вроде бы готовы, но не все так просто — не хватает вспышки от выстрела.

Идем в папку textures/pfx и ищем вот эти две текстуры:

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

S.T.A.L.K.E.R. на движке Doom. Оружие

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

S.T.A.L.K.E.R. на движке Doom. Оружие

После этого нужно знакомым нам образом отрендерить в Blender модели патронов и ружья, которое игрок будет подбирать. Вышло 24 спрайта для одного только обреза. Но я не совсем честен, ведь спрайт картечи можно будет использовать и для других дробовиков, потому что объект патронов, который мы создадим, можно будет применить к любому оружию.

S.T.A.L.K.E.R. на движке Doom. Оружие

В Slade3 в папке sprites создаем папку weapons, а внутри нее папку obrez и помещаем туда все спрайты. Добавляем их в ламп textures и открываем редактор текстур. Методом проб и ошибок я уменьшил все изображения оружия в четыре с половиной раза, а изображения патронов и ружья на земле — в 14 раз. Не надо забывать менять тип спрайтов с texture на sprite!

В редакторе текстур присутствует возможность выставить оружие в руках по сетке, но эта сетка рассчитана на соотношение экрана 4:3. Если вы будете играть в соотношении 16:9, то оружие нужно передвинуть чуть правее или левее сетки. Я решил все оставить как есть, тем более, что в настройках GZDoom можно поменять соотношение экрана.

S.T.A.L.K.E.R. на движке Doom. Оружие

Приступаем к написанию кода. В прошлой статье мы добавили в игру автобус двумя разными способами. Обрез мы будем создавать таким-же образом.

В корне архива создаем файл weapons.dec, а в файле decorate пишем:

#include "WEAPONS.dec"

Это позволит разделить разные объекты во избежание путаницы. Все, что я буду писать в дальнейшем, я буду писать именно в файле weapons.dec.

Первым делом нужно создать два типа патронов для нашего обреза. Почему два?

Первый класс — это патроны в стволе:

Actor BoomStickAmmoClip : Ammo { Inventory.MaxAmount 2 }

Здесь ничего придумывать не надо. Наследуем новый класс от имеющегося класса Ammo и определяем, что в инвентаре может быть не более двух патронов (по количеству стволов).

Второй класс — это патроны в рюкзаке:

Actor BoomStickAmmo : Ammo 30200 { Inventory.Amount 10 Inventory.MaxAmount 200 Inventory.PickupMessage "Picked up 20 Buck shells" Inventory.Icon "ADRBA0" States { Spawn: ADRB A -1 Stop } }

Amount — количество подбираемых патронов. MaxAmount — максимальное количество патронов в инвентаре. Далее следует сообщение, которое появляется, когда игрок эти патроны подбирает. Icon отвечает за изображение на экране, когда игрок держит оружие с таким типов патронов.

Кроме того этому классу требуется состояние Spawn, так как игрок должен видеть коробку, лежащую на земле.

S.T.A.L.K.E.R. на движке Doom. Оружие

Патроны созданы, приступаем к созданию оружия. Сперва определяем параметры обреза.

Actor BoomStickStalker : DoomWeapon 3100 { Weapon.SelectionOrder 400 Inventory.PickupMessage "Picked up Obrez" Weapon.SlotNumber 3 Weapon.AmmoUse 1 Weapon.AmmoGive 0 Weapon.AmmoType "BoomStickAmmoClip" Weapon.AmmoUse2 0 Weapon.AmmoGive2 8 Weapon.AmmoType2 "BoomStickAmmo" +AMMO_OPTIONAL

Итак, по порядку. SelectionOrder — это параметр, который отвечает за автоматическое переключение оружия при нехватке патронов. Чем меньше значение этого параметра, тем выше вероятность, что игра переключится на это оружие при нехватке патронов у текущего.

Далее мы придумываем сообщение при поднятии и определяем, в каком слоте оружие будет находиться (под какой кнопкой).

Потом надо присвоить обрезу новые патроны. AmmoUse определяет, сколько патронов оружие использует при обычном выстреле. AmmoGive — сколько патронов выдает игра, когда игрок обрез поднимает (в данном случае стволы будут пустыми). AmmoUse2 и AmmoGive2 отвечает за второй тип патронов: в рюкзаке. В данном случае, при альтернативном выстреле (альтернативный выстрел будет отвечать исключительно за перезарядку ружья) мы вообще не будем их использовать, а коробка картечи будет давать 8 патронов.

Чтобы игра не сломалась, когда мы пытаемся выстрелить альтернативной атакой, нужно присвоить флаг Ammo_Optional.

Теперь нужно прописать состояния обреза. Любое оружие в Doom должно обязательно иметь состояния Select, Deselect, Ready и Fire.

Select: BSTK A 1 A_Raise Loop

Любое состояние содержит последовательность кадров в формате XXXX Z N Function, где XXXX — это название спрайта, Z — название кадра этого спрайта, N — длительность кадра в тиках (тик — 1/35 секунды), Function - необязательная функция. В состоянии Select обязательно должна присутствовать функция A_Raise. Эта функция поднимает оружие из-за границ экрана до боевой позиции. При этом состояние Select должно быть зациклено. Когда оружие окажется в боевом положении, то оно сразу же перейдет в состояние Ready.

Ready: TNT1 A 0 A_JumpIfInventory("BoomStickAmmoClip", 2, 3) TNT1 A 0 A_JumpIfNoAmmo(3) BSTK B 1 A_WeaponReady GoTo Ready BSTK C 1 A_WeaponReady GoTo Ready BSTK A 1 A_WeaponReady GoTo Ready

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

Первый кадр с помощью функции A_JumpIfInventory проверяет, присутствует ли в инвентаре (стволе) не менее двух патронов. Если функция возвращает истину, то состояние перепрыгивает на три кадра вперед (при этом, игнорируются ключевые слова GoTo. Если в стволе менее двух патронов, то исполнение кода продолжается.

Следует отметить, что первые два кадра состояния используют спрайты TNT1A0. Это технические прозрачные спрайты, которые можно использовать, когда программа производит вычисления и/или не требует отрисовки чего-либо на экране.

Второй кадр состояния c помощью функции A_JumpIfNoAmmo проверяет обрез на отсутствие патронов. В случае положительного результата программа прыгает на 3 кадра вперед.

Далее мы прописываем кадры, которые будут отображаться в игре. После каждого кадра обязательно следует функция A_WeaponReady, которая сообщает игре, что оружие готово к стрельбе. Кроме того, после каждого кадра следует совершить безусловный переход к началу состояния для зацикливания состояния во избежание краха игры.

DeSelect: BSTK A 1 A_Lower Loop

Состояние Deselect аналогично состоянию Select, но вместо функции A_Raise нужно использовать функцию A_Lower, которая опускает оружие, пока весь спрайт не окажется за пределами экрана.

За стрельбу отвечает состояние Fire:

Fire: TNT1 A 0 { if (CountInv("BoomStickAmmoClip") == 0) { return state ("AltFire"); } else { return state ("FireBoomStick"); } return state ("Ready"); }

Так как обрез, в противовес стандартному оружию в Doom, умеет перезаряжаться, воспользуется еще одной возможностью Decorate — анонимными функциями. В состоянии Fire будет всего один кадр, а под ним функция, которая выглядит стандартно для обычного языка программирования. Если в стволах нет патронов, то мы перемещаемся в состояние AltFire, которое будет отвечать за перезарядку. Иначе перемещаемся в состояние FireBoomStick, которое мы сейчас создадим.

В Decorate можно создать любое количество уникальных пользовательских состояний (помимо встроенных) и перемещаться между ними с помощью оператора безусловного перехода GoTo или с помощью анонимных функций.

FireBoomStick: BSTF B 4 BSTF C 4 { A_FireBullets(15,15,25,2,"BulletPuff"); } BSTF DE 4 BSTK B 4 TNT1 A 0 A_Refire GoTo Ready

В новом состоянии все стандартно. Все спрайты стрельбы меняются покадрово с шагом в 4 тика. При этом под вторым кадром необходимо добавить выстрел. За это отвечает функция A_FireBullets, которая принимает в качестве аргументов разброс пуль по ширине и высоте, количество пуль и урон от каждой пули. BulletPuff — это стандартный класс, который отображает следы от выстрела.

В конце состояния игра проверяет, зажата ли кнопка выстрела (A_Refire). Если зажата, то состояние возвращается в начало, иначе прыгает в состояние Ready.

Переходим к перезарядке. Сперва нужно прописать необходимые условия в состоянии AltFire. По умолчанию это состояние вызывается нажатием правой кнопки мыши.

AltFire: TNT1 A 0 { if (CountInv("BoomStickAmmoClip") == 2){ return state ("Ready"); } else if (CountInv("BoomStickAmmoClip") == 1){ if (CountInv("BoomStickAmmo") >= 1){ return state ("LeftBarrelReload"); } } else if (CountInv("BoomStickAmmoClip") == 0){ if (CountInv("BoomStickAmmo") >= 2){ return state ("BothBarrelsReload"); } else if(CountInv("BoomStickAmmo") == 1){ return state ("LeftBarrelReload"); } } return state ("Ready"); }

Если в стволах два патрона, то возвращаемся в Ready. Если всего один, а в рюкзаке есть как минимум один патрон картечи, то перемещаемся в состояние перезарядки левого ствола (LeftBarrelReload).

Если в стволе нет патронов, а в рюкзаке есть как минимум два патрона картечи, то перемещаемся в состояние перезарядки обоих стволов (BothBarrelsReload). Но, если патрон в рюкзаке всего один, то опять прыгаем в LeftBarrelReload.

LeftBarrelReload: BSTK EFGHIJ 4 TNT1 A 0 A_TakeInventory("BoomStickAmmo",1) TNT1 A 0 A_GiveInventory("BoomStickAmmoClip",1) GoTo Ready

Перезарядка левого ствола до безобразия проста. Сперва запускаем последовательность кадров с шагом в 4 тика, а потом забираем из инвентаря один патрон картечи и выдаем один патрон в ствол.

В Decorate можно записать последовательность кадров одной строкой, если они не подразумевают разную длительность или наличие функций.

BothBarrelsReload: BSTK KLMNOPQ 4 TNT1 A 0 A_TakeInventory("BoomStickAmmo",2) TNT1 A 0 A_GiveInventory("BoomStickAmmoClip",2) GoTo Ready

При перезарядке двух стволов одновременно происходят аналогичные действия. Нужно только поменять количество патронов и названия кадров.

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

Spawn: BSTZ A -1 Stop

Для полноты картины можно создать еще одно состояние Flash.

Flash: TNT1 A 2 Bright A_Light1 TNT1 A 2 Bright A_Light2 Goto LightDone

Раньше это состояние использовалось для отображения на экране спрайта вспышки от выстрела в целях экономии ресурсов. Сейчас это не актуально — вспышку мы добавили еще на стадии создания изображений. Состояние Flash в таком виде лишь освещает пространство вокруг игрока и само оружие. Чтобы игра переходила в это состояние при выстреле, в состоянии FireBoomStick под вторым кадром мы прописываем:

BSTF C 4 { A_FireBullets(15,15,25,2,"BulletPuff"); A_GunFlash; }

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

3…2…1… Звуков выстрела и перезарядки!

Все звуки из S.T.A.L.K.E.R. хранятся в папке gamedata/sounds. Находим в ней звук выстрела обреза и звук его перезарядки. Они довольно длинные, поэтому я порезал их на 4 файла: выстрел, перелом стволов, помещение патрона в ствол и взвод курка. Doom принимает и файлы формата WAV, и файлы формата OGG. Полный список форматов. Наименования файлов должны содержать не более 8 символов, иначе игра откажется их проигрывать. Все звуки в нашем архиве должны храниться в папке sounds.

Поместить файлы в папку — половина дела. Все дефиниции звуков должны храниться в специальном лампе Sndinfo.

ObrezShot OBRZSHOT ObrezReload1 OBRZOPEN ObrezReload2 OBRZBLLT ObrezReload3 OBRZCLOS

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

Теперь нужно присоединить звуки к оружию в Decorate.

В состоянии FireBoomStick снова дополняем многострадальный кадр выстрела:

BSTF C 4 { A_StartSound("ObrezShot"); A_FireBullets(15,15,25,2,"BulletPuff"); A_GunFlash; }

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

Перезарядка левого ствола:

LeftBarrelReload: BSTK E 4 A_StartSound("ObrezReload1", 0, CHANF_OVERLAP) BSTK FG 4 BSTK H 4 A_StartSound("ObrezReload2", 0, CHANF_OVERLAP) BSTK I 4 BSTK J 4 A_StartSound("ObrezReload3", 0, CHANF_OVERLAP) TNT1 A 0 A_TakeInventory("BoomStickAmmo",1) TNT1 A 0 A_GiveInventory("BoomStickAmmoClip",1) GoTo Ready

Перезарядка обоих стволов:

BothBarrelsReload: BSTK K 4 A_StartSound("ObrezReload1", 0, CHANF_OVERLAP) BSTK LM 4 BSTK N 4 A_StartSound("ObrezReload2", 0, CHANF_OVERLAP) BSTK O 4 A_StartSound("ObrezReload2", 0, CHANF_OVERLAP) BSTK P 4 A_StartSound("ObrezReload3", 0, CHANF_OVERLAP) BSTK Q 4 A_StartSound("ObrezReload3", 0, CHANF_OVERLAP) TNT1 A 0 A_TakeInventory("BoomStickAmmo",2) TNT1 A 0 A_GiveInventory("BoomStickAmmoClip",2) GoTo Ready

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

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

That’s all Folks!

8181
16 комментариев

вот так из простой буханки ...

12
Ответить

...получить сталкер на движке дума!

17
Ответить

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

3
Ответить

Если я правильно понимаю, то там под каждое соотношение экрана нужно просто спрайты выставлять по координатам. Если вот это запустить в 16:9, то получится вот так...

Ответить

Комментарий недоступен

3
Ответить

Я пробовал скормить официальному ре-релизу DOOM от Bethesda кастомный wad (Doom 2016 wad https://www.doomworld.com/forum/topic/108725-doom-4-vanilla-v32/ ) по инструкции: https://doomwiki.org/wiki/Official_add-ons
Но видимо гранаты не той системы или я что-то напортачил, а жаль, столько вкусных wad'ов сделано.

1
Ответить

Скорее всего порты переизданий не поддерживают какие-то штуки, которые в это ваднике есть. Как правило для всего этого есть GZDoom)

Ответить