Создание своей RPG на движке Source
44К открытий46К показов
Если вы хотите научиться разрабатывать игры, моддинг существующих игр — отличное начало для изучения дизайна и создания прототипов без необходимости изобретать велосипед. В этой статье мы будем использовать Source Engine от Valve (на этом движке созданы Portal, Left 4 Dead, Half-Life и Team Fortress 2) для создания RPG-подобных квестов в Half-Life 2: Episode 2.
Обратите внимание, что эта статья подразумевает, что у вас есть базовые знания по Source SDK Hammer Editor и Face Poser, так что это проект не для начинающих, а скорее для программистов среднего уровня.
Если у вас нет этих навыков, вы может изучить другие руководства по разработке игр на нашем сайте: например, созданию игр с использованием Unity или социальных игр.
Для освоения этого материала вы должны знать, как создавать и компилировать карты, размещать сущности и настраивать триггеры, прежде чем повторять действия, описанные здесь. Если вы захотите добавить свои диалоги, вам нужно знать ещё и как создавать и сохранять сцены в Face Poser. Ничего страшного, если вы никогда не работали с Source SDK раньше — в интернете полно статей, описывающих, как им пользоваться. Начните с Valve Developer Wiki, которая содержит множество полезных статей по теме, затем сходите на design3 (кстати, я один из участников проекта) за пошаговыми видеоинструкциями по Source Engine. Минимальные системные требования для использования инструментов, описанных выше, такие же, как для запуска Half Life 2: Episode 2: процессор на 1.7 ГГц, 512 Мб RAM, DirectX 8.1 и Windows не ниже XP. Ещё вам понадобится микрофон.
Подготовка
Прежде чем мы начнём, убедитесь, что у вас есть всё необходимое. Во-первых, вам нужна установленная копия Half-Life 2: Episode 2. Мы будем использовать эту игру, потому что это самая новая одиночная игра на движке Source, к которой можно написать мод. Если у вас нет второго эпизода, скачайте его с то простой Half-Life 2 тоже должен подойти.
Если вы хотите добавить свой диалог в эту RPG, вам понадобится приложение для обработки аудио. Мы будем использовать Audacity — оно свободное, имеет открытый исходный код и отлично подходит для наших задач.
Нам также понадобится патч Phoneme Extractor, который поможет Face Poser лучше работать с Windows 7/Vista. Скачайте его и следуйте инструкциям по установке. Без него не будет работать соединение текста диалога со звуковой подложкой.
Дальше ставьте GCFScape. Он даст нам возможность открывать файлы кеша от игр Steam, так что мы сможем достать оттуда необходимые нам файлы. С его помощью мы будем вынимать аудио для нашего мода.
Если вы ещё этого не сделали, установите Source SDK. Для этого откройте Steam и переключитесь на вкладку «Инструменты». Вам понадобится своя карта, с которой мы будем работать (я буду называть её «основная карта»). Это может быть что угодно: от нескольких простых комнат до обширного ландшафта. Иллюстрация 1 — скриншот уровня, который я использовал для этой статьи, вы можете скачать его здесь.
Сейчас наш уровень — просто грубый прототип, который полностью не текстурирован и не детализирован. Лучше всего именно с этого и начинать, а деталями заниматься уже в самом конце. Итак, давайте уже начинать делать нашу RPG. Не забывайте вовремя сохраняться! Некоторые нововведения в Hammer’е не полностью поддерживаются в Episode 2 и могут вызвать аварийное завершение редактора.
Создаём структуру квеста
В этой статье мы сосредоточимся на получении и выполнении заданий, построение системы развития персонажа с очками опыта — тема для отдельной статьи. На нашем уровне будут три неигровых персонажа (NPC), каждый будет давать нам по два задания. Мы можем их использовать также для предоставления игроку информации, атак на него или просто для того, чтоб добавить немного жизни уровню.
Для того, чтобы уровни были организованы, давайте использовать следующую конфенцию имён:
Это поможет нам гораздо проще находить наши сущности, особенно во время работы над заданиями. Например, добавление префикса Level к сущностям, которые затрагивают только определённый уровень, автоматически разместит их в одном месте в списке, и они не будут путаться с сущностями какого-либо задания.
Прежде чем мы всё-таки начнём делать квесты, нам нужно разбить их на меньшие компоненты, а именно:
- Trigger Start: запускает задание;
- Sprite: показывает, где квест может быть начат;
- Giver: NPC, который даёт это задание;
- Scene Start: диалог, описывающий задание;
- Sound Start: звук, который уведомляет игрока о получении задания;
- Text Start: текст, описывающий задание;
- Relay Content: прослойка, которая запускает необходимые для квеста процессы (например, спаунер NPC);
- Quest Components: основное содержимое квеста — после выполнения оно должно запустить Relay Complete;
- Relay Complete: прослойка, которая настраивает уровень для последующего задания;
- Text End: текст, который описывает, как выполнить задание;
- Sprite: снова появляется, чтобы указать, с каким NPC нужно поговорить;
- Trigger End: триггер, инициирующий окончание задания;
- Scene End: заключительный диалог;
- Sound End: звук, знаменующий окончание задания;
- Next Quest Activation: если есть следующее задание, оно активируется здесь.
Если вы что-то из этого не поняли, не переживайте — пока мы просто составляем список всего необходимого. Это список лишь для одного задания, так что нам понадобится создать действительно много всяких сущностей. Чтобы не засорять мозг лишним, мы будем использовать VisGroups для разделения заданий и сокрытия того, что сейчас не нужно. VisGroups позволяет вам обозначить группы кистей и сущностей и быстро скрывать или показывать их. Если группа скрыта во время компиляции, всё, что содержится в этой группе, будет пропущено и не появится в игре. Это очень удобно, ведь вы можете избирательно просматривать отедльные группы объектов, сосредоточившись на них, а ничто другое вам мешать не будет.
Создание шаблона задания
Мы будем использовать шаблоны (instancing) — отличный инструмент Hammer Editor’а. Это позволит ссылаться нашей основной карте на другие. Мы создадим экземпляр задания, который в дальнейшем будем использовать как шаблон. После того, как мы его закончим, мы сможем просто раскопировать его и немного отредактировать настройки копий так, чтобы каждое задание стало уникальным. Таким образом, нам не придётся делать одну и ту же нудную работу много раз. К сожалению, Episode 2 не полностью поддерживает эту технологию, поэтому нам придётся конвертировать экземпляры в уровни перед компиляцией (мы коснёмся этого позже).
Для того, чтобы настроить наш шаблон задания, нам нужен новый файл карты. В Hammer’е выбирайте File, затем New, карту сохраните как «quest_instance» в папке «instances» в том же месте, где лежит ваша основная карта.
Лучше всего размещать сущности как можно ближе к координатам (0,0,0). Также стоит размещать их выше плоскости XY, чтобы не потерять при переносе. Для правильного размещения вы можете воспользоваться Selection Tool. Наш шаблон будет автоматически добавлять выбранный нами префикс ко всем сущностям внутри него. Триггеры и выставление некоторых значений буду описаны позднее, так что не переживайте, если вам показалось, что мы что-то упустили.
Нам понадобятся все сущности, упомянутые в списке выше. Давайте начнём с добавления NPC. Выберите Entity Tool, найдите npc_citizen
в выпадающем списке и разместите его у начала координат. Этот парень будет давать нам задание. Нажмите Alt+Enter, чтобы открыть его настройки, и дайте ему имя «giver». Выставьте параметр Prevent picking up weapons?
на Yes
. Примените настройки нажатием на Apply и перейдите на панель Flags. Выставьте флаг Not Commandable
, иначе наш работодатель будет всюду таскаться за игроком по карте. Выставьте ещё Don't drop weapons
и Ignore player push
(чтобы он не уступал дорогу игроку).
Теперь нам понадобится триггер, который будет отслеживать, подошёл ли игрок к… Давайте называть его Гриша, потому что «этот парень» или «quest giver» звучат не очень хорошо. Так вот, чтобы отслеживать, подошёл ли игрок к Грише, создайте кисть со следующими размерами: 64 юнита в высоту, 32 юнита в ширину, 4 юнита в длину — и разместите объект прямо перед Гришей. Назначьте этому объекту текстуру nodraw
, чтобы она не рендерилась. Чтобы изменить текстуру, выделите объект, переключитесь на Toggle texture, нажмите кнопку Browse, используйте фильтр по nodraw
, двойным кликом выберите его и примените параметры (кнопка Apply). Затем назначьте этой сущности триггер, нажав Ctrl+T и выбрав func_button из списка. Назовите его «trigger_start» и измените скорость (speed
) до нуля. Снова сохраните изменения.
Теперь давайте добавим спрайт, который будет уведомлять игрока, что у этого NPC есть задание. Поместите сущность env_sprite
сверху от головы Гриши и откройте окно Object Propeties, нажав Alt+Enter. Назовите его «Sprite». Теперь нам нужно изменить режим ренедринга, чтобы спрайт отображался в игре корректно. В том же окне найдите опцию Render Mode
и выберите World Space Glow
из выпадающего меню. Вы можете изменить текстуру этого спрайта, используя это меню, если хотите. Убедитесь, что во кладке Flags стоит галочка напротив Start on
.
Займёмся диалогом. Найдите в списке сущностей logic_choreographed_scene
и поместите его за Гришей. Нам понадобится минимум две таких на каждый квест — одна для начального диалога, вторая для заключительного — так что скопируйте её и вставьте вторую поверх первой. Дайте им имена «scene_start» и «scene_end» соответственно. Добавление собственно диалога мы рассмотрим несколько позже.
Кроме всего этого, нам ещё нужны звуковые уведомления о том, что игрок получил задание и о том, что он его выполнил. Создайте две сущности ambient_generic
, поместите их рядом с NPC и назовите «sound_start» и «sound_end». Если у вас нет своих подходящих звуков, используйте plats\elevbell1.wav
(вводить нужно в поле Sound Name
). На вкладке флагов все три опции должны быть отмечены галочкой.
После этого нам нужно добавить текст, который будет описывать задание. Создайте две сущности game_text
и назовите их «text_start» и «text_end». Выставьте для обеих достаточно высокий параметр Hold Time
(порядка 99999), чтобы текст не исчез, пока мы сами его не уничтожим. Нам нужно, чтобы текст был сбоку экрана и не мешал игроку, так что выставьте у обеих сущностей поля X
и Y
на 0.1.
Нам понадобится несколько прослоек, чтобы систематизировать триггеры. Прослойка (relay) — сущность, которая при активации запускает другие сущности. Одна прослойка обычно запускает действия, которые должны выполняться в одно время и в одном месте, чтобы ими было удобнее управлять. Создайте две сущности logic_relay
и разместите их рядом с Гришей. Назовие их «relay_content» и «relay_complete». Эти две прослойки будут запускать все сущности в задании. Особенности конкретного задания придумайте сами — вам нужно установить для игрока цель вроде «собрать столько-то таких-то предметов» или «добраться до такого-то места». Для проверки выполнения этих условий вы можете использовать такие сущности, как math_counter
или сущности областей вроде trigger_once
. Когда эти сущности выяснят, что задание пройдено, они должны будут запустить «relay_complete», который, в свою очередь, запустит всё необходимое для ознаменования конца задания.
Добавим ещё один триггер напротив Гриши. Он будет практически идентичным стартовому триггеру, поэтому просто скопируйте «trigger_start» и переименуйте его в «trigger_end». Убедитесь, что флаг Starts locked
включен. Убедитесь, что эти сущности не перекрывают друг друга и что стартовый триггер находится перед хитбоксом NPC (иначе игра будет путаться, выбираете ли вы триггер или «кнопку»), используя виды сверху и сбоку. Чтобы определить местонахождение хитбокса, выберите Гришу — вокруг него появится жёлтая рамка.
Теперь настроим триггеры, как показано на Иллюстрации 5. Вам пока не стоит переживать за триггеры в квадратных скобках, их мы добавим позже. Выберите перечисленные сущности, откройте их Object Properties, зайдите во кладку Outputs и настройте всё в соответствии с таблице ниже. Убедитесь, что вы сохраняете все изменения (кнопка Apply)!
Размещаем шаблоны
Наш шаблон готов, теперь мы можем размещать такие шаблоны по карте и настраивать их более детально. Разместите «func_instance» где вам удобно, откройте его Object Properties и под VMF Filename найдите ваш файл «quest_instance». Обратите внимание, что поиск работает несколько багованно, так что вам может потребоваться ввести путь к файлу вручную. Теперь вы можете раскопировать этот шаблон по карте: создайте столько заданий, сколько хотите.
Выберите первое задание и дайте ему импортировать все необходимые сущности (нажимайте Instancing, Collapse, Selection). Hammer даст всем сущностям префикс, по умолчанию «AutoInstance-». Всё импортированное будет выделено, нам останется только добавить их в одну группу через VisGroups. Откройте Object Properties и выберите там вкладку VisGroups. Вы увидите примерно следующее:
«Sewer» и «Main level» — группы, которые я создавал раньше, так что это нормально, что у вас их нет. Нажмите на «Edit Groups» и вы увидите следующее:
Здесь вы можете создать новые группы, которые потом будете использовать. Нажмите «New group» и вы увидите новый элемент в списке. Переименуйте его в «Quest_n», где n — номер задания. Как закончите с этим, нажмите «Close», вы увидите свою группу в главном списке. Отметьте чекбоксами для добавления сущностей в группу, нажмите «Apply», затем снова «Close». Тперь вы можете скрывать или просматривать группы, используя панель управления VisGroup, как показано ниже. Делайте так с каждым вашим заданием.
Добавление собственных звуковых файлов
Наша РПГ была бы крайне скучна без диалогов, раскрывающих историю, так что мы запишем их через Audacity. Для начала у вас должен быть микрофон. Из-за особенностей работы Face Poser вам стоит записывать по одному предложению за раз. С Audacity всё просто — настройте микрофон, нажмите на красную кнопку, скажите что-то, остановите запись и сохраните файл в формате .wav
. Если у вас возникли какие-то проблемы, можете смело использовать встроенную справку, она очень хорошо сделана. Как закончите, создайте папку «RPG» и поместите в неё все файлы. Папку эту переместите в C:/Program Files/Steam/steamapps/half-life episode two/ep2/sounds/
. Сохранение всех файлов в папку на один уровень выше «sounds» принципиально — иначе движок их просто не увидит.
Идём дальше. Создайте файл «sound_script», чтобы движок мог связать наши звуки в редакторе с игрой. Запустите GCFScape, перейдите к File->Open, перейдите к своей папке «steamapps» и откройте файл «episode two content.gcf». После того, как GCFScape его прогрузит, вам нужно будет найти файл «game_sounds_manifest.txt», который размещён в «/steamapps/ep2/scripts». Нажмите на него правой кнопкой мыши и выберите «Extract» и разместите этот манифест в «/steamapps/half-life 2 episode two/ep2/scripts». С GCFScape мы закончили, можете закрывать его.
Теперь идите в папку со скриптами и откройте «game_sounds_manifest.txt», который мы только что извлекли. В этом файле лежат все звуковые скрипты, которые игра будет использовать, и нам нужно добавить наши записи туда же. Под последней строчкой кода, в последних скобках напишите ровно следующее:
Файл манифеста можно уже закрывать. Создадим файл «rpg_sounds.txt», на который мы ссылаемся и запишем в него следующее:
Первая строка — имя звука, которое отобразится в Face Poser: «rpg_sounds» — префикс, а вторая часть — собственно имя. Вы можете менять их как вам угодно. Следующие четыре строки говорят движку, что ему с этими звуками делать, примите их просто как данное. Последняя строчка — .wav
файл, который будет загружаться, и относительный путь от папки «/steamapps/half-life 2 episode two/ep2/sound/». Всё, что вам нужно сделать — поместить в эту папку все свои звуковые файлы и убедиться, что их имена и расширения совпадают с указанными в скриптовом файле.
Если у вас стоит Windows Vista или Windows 7, нам придётся немного помочь Face Poser. Как указано выше, вам для этого понадобится патч Phoneme Extractor. Тут стоит упомянуть, что Source SDK обновляет себя каждый раз, как вы его запускаете, поэтому патч нужно ставить каждый раз, как вы открываете Source SDK. Да, это утомительно, но это самый простой путь, поверьте.
С открытым Face Poser мы начнём создавать новую сцену. Под меню «Choreography» нажмите «New». Я порекомендую вам сразу же её сохранить. Имя выберите сами, а папка для сохранения — «/steamapps/half-life episode two/ep2/Scenes/RPG_MOD/». Её потом будет гораздо проще найти, если вы дадите ей какой-то префикс, например, «RPG_». Теперь Face Poser попросит вас дать имя главному действующему лицу (Actor). Назовите его «!_targetN», где N — число от 1 до 8, т.к. у нас будет до восьми NPC в каждой сцене. Hammer будет использовать того NPC, которого вы укажете. У нас пока есть только Гриша, поэтому назовём действующее лицо «!_target1». Сделайте правый клик по имени действующего лица, которое появилось в меню «Choreography», затем перейдите к New->Channel->Create Channel box. Назовите этот канал «Audio». Теперь создайте ещё один канал и назовите его «Anim» (для анимации).
Теперь нам необходимо отсортировать наши аудиозаписи. В списке вкладок в нижней части экрана Face Poser дважды нажмите на «Phoneme Editor». В открывшемся окне нажмите «Load» и выберите .wav
файл, который вы хотите добавить. Затем нажмите на «Re-extract», и Face Poser предложит вам написать содержимое аудиофайла текстом. Впишите его. Теперь, если вы нажмёте на кнопку проигрывания, вам будет показано лицо действующего лица, губы которого будут двигаться. Можете сохранять всё и закрывать это окно. Эти действия необходимо повторить для каждого звукового файла.
Если вы хотите добавить жесты, выражения лица или другую анимацию, Вам стоит делать это сейчас. Я не буду рассказывать, как это сделать в этой статье, вы можете прочитать об этом где-то ещё. Далее сохраните свою сцену (Choreography->Save). Теперь осталось применить эту сцену к нашему NPC.
Добавление стороннего аудио к NPC
Теперь нам нужно настроить диалог. Нам нужно добавить созданные нами сцены к «scene_start» и «scene_end», которые мы создавали раньше. Для этого нажмите Alt+Enter, чтобы открыть Object Properties, там найдите опцию «Scene file». Назначьте ей недавно созданную сцену и сохраните изменения. То же самое сделайте для «scene_end».
Активация событий
В целом, вы уже можете сами создавать триггеры, которые будут делать что угодно, но я приведу пример того, какое задание можно сделать и как его реализовать.
Игроку нужно убить пять врагов. Каждый раз, когда умирает враг, math_counter
увеличивается на единицу. Когда счётчик доходит до пяти, math_counter
вызывает logic_relay
. В свою очередь, logic_relay
прекращает спаун мобов, активирует NPC и «relay_complete».
Настройка автосохранения
Никто не любит, когда один случайный крэш убивает результат многочасовой игры. Поэтому вам стоит добавить сущность logic_autosave
и вызывать её каждый раз, когда задание будет пройдено (вы уже знаете, как это делается).
Конец игры
Игра должна будет когда-нибудь закончиться, и будет не очень хорошо, если она просто вылетит в главное меню, поэтому стоит создать титры. Для этого просто разместите где-то на карте следующие сущности:
Заключение
Я рассказал всё, что хотел. Теперь вы можете создавать любые виды заданий, умеете работать с триггерами и, в общем-то, можете начинать писать свои несложные моды к играм. Удачи!
44К открытий46К показов