Этап 4. Оптимизация и Цепочки Квестов
На этом Этапе вы научитесь значильно сокращать код у некоторых рутинных задач (убийство, сбор и т.д.), а также делать цепочки из нескольких квестов (.xml файлов)
Глава 15. Шаблонные шаги
Вспомните, скоько кода мы писали в прошлых Главах, чтобы сделать шаг с примитивным заданием на убийство мобов. Мы понемногу тащтельно собирали всё из мелких кусочков. Пока заданий мало, это некритично, но когда заданий становятся разнообразней, а их количество увеличивается, тогда могут начаться проблемы. Например, забыл вставить какой-то тег, не проверил что-то, не уследил за положением кнопок и так далее. Всё это требует внимательного написания и тщательной проверки, что явно неудобно
На этот случай в игре есть заранее заготовленные супер-шаги, которые объединяют в себе: выдачу задания, проверку условий и выдачу награды + текстовыми блоками (intro, desc, finish). Это позволяет сделать код намного более читаемым, а также существенно упростить создание однотипных заданий.
Шаг 1. Конструктор VS Шаблон
Обычный <step>, которым мы пользовались во всех прошлых Главах – это конструктор. Вы сами ручками собираете каждую отдельную детальку. Это удобно, когда шаг включает сразу несколько разносторонних заданий или сложные условия.
Шаблонные шаги – это готовая фигурка, которую уже собрали за вас. Вам лишь нужно раскрасить её под себя. Они подходят, когда шаг включает в себя несколько однотипных заданий
Всего есть 5 шагов-шаблонов:
<killstep>– убийство мобов<collectstep>– сбор предметов (предметы НЕ забирают)<removestep>– сбор предметов (предметы забирают)<craftstep>– задания на крафт чего-либо<consumestep>– задание на поедание чего-либо
Дальше рассмотрим каждый подробнее, некоторые из них применим в нашем Основном Квесте
Шаг 2. <killstep> – убийства
На примере killstep разберемся со струтурой шаблонных шагов:
<killstep id="hunt_step"><intro>Убей 3 пауков!</intro><desc>Пауки ещё живы.</desc><finish>Молодец! Держи награду.</finish><kill enemy="Spider" count="3"/><rewards> <reward exp="200"/> </rewards><option text="Ок" to="after_hunt_step"/></killstep>
Кнопка одна на всех. Допустим, это будет кнопка «Ок». В теге rewards атрибут type НЕ УКАЗЫВАЕМ. Игра сама подставит нужный
Жизненый цикл такой:
- Игрок перешел на шаблонный шаг. Ему показывается текст из
<intro>, а также<rewards>сtype="Display". Задание появляется в Журнале и начинает остслеживаться автоматически. Игрок жмёт «Ок» и закрывает диалог


- Если игрок вновь подойдет к NPC, то ему покажется
<desc>со все той же кнопкой «Ок» и<rewards>сtype="Display"

- После выполнения задания, когда игрок подойдет к NPC, игрок увидит блок
<finish>и<rewards>сtype="Award". После нажатия на «Ок», ему выдадут награду и квест перейдет на следующий шаг, указанный в опции-кнопке

Аналогично работают все остальные шаблонные шаги. Разница только в названиии (<killstep>, <craftstep> и т.д.) и допустимых тегах-условиях внутри (<kill>, <craft> и т.д.)
Что можно добавлять внутрь:
item– Иконка предметаrecipe– Показать рецептrow– Группировкаlabel– Текст в диалоге. Нюанс: этот текст будет отображаться на всех этапах квеста под всеми текстовыми блоками (intro,desc,finish)labelатрибутомloationи тегом<persist/>– Текст, выводящийся на экран игрока. Нюанс: Текст на экране остается на протяжении всего шага (отintroдоfinish), начиная моментом принятия задания и заканчивая моментом сдачи. При переходе на следующий шаг, текст с экрана исчезнетnotify– Уведомления, но только внутри единственной кнопки-опции
Нельзя добавлять:
- Авто-опции
- Неподходящие цели (например, в
killstepдобавитьcollect) - Дополнительные кнопки
Все это будет проигнорировано
Шаг 3. Используем в квесте
На шаблонный шаг заменить spider_hunt_step не получиться, так как там несколько разных Целей (убийство + сбор), выводящиеся на экран Цели, который должен отображаться только на определенном этапе, а также сложные авто-опции с уведомлениями. В общем, его заменить не получиться.
Шаг brew_health_potion_step из ветки Плохого Настроения тоже не получиться заменить, так как там сложное оформление, которое должно отображаться только на этапе сбора, а не на этапе сдачи. В шаблонных же шагах все label отображаются на всех этапах квеста
Но мы можем добавить в эту ветку новый шаг consumestep.
Суть такая:
- Меняем
brew_health_potion_step, чтобы там просто показывали рецепт и просили сварить Зелье - После варки, перебрасывает на шаг:
return_to_wizard_step, который заменяет запись в Журнале на: «Вернись к Волшебнику и скажи, что ты сварил Зелье» - Игрок подходит к Волшебнику и тот ему говорит, чтобы он выпил это зелье
- После нажатия кнопки «Ок», игрока перебрасывает на наш consumestep, который назовем
consume_health_potion_step - За выполнение дается 50 опыта
Приступим:
- Изменим текст info + добавим отступ в
brew_health_potion_step, а также добавим авто-опцию, которая отработает, когда игрок сварит Зелье Здоровья и перебросит игрока на следующий шаг (return_to_wizard_step)
<step id="brew_health_potion_step"><desc>Могу предложить тебе сварить Зелье Здоровья. Это должно помочь поднять тебе настроение.</desc><option to="#close" text="Понял"/><label>Вот рецепт:</label><recipe name="Health Potion" type="Cauldron" /><label><scale x="1000" y="8"/>[FFFF00]_[-]</label><row><label>Скрафти Котел</label><item name="Cauldron" count="0"/><label>и помести:</label></row><row><item name="Lilia Flower" count="1"/><item name="water" count="1"/><item name="Energy" count="1"/></row><info><label>Свари Зелье Здоровья по рецепту: </label><recipe name="Health Potion" type="Cauldron" /><label>После приготовления, подойди к Волшебнику!</label><label></label><label>Для приготовления потребуются: </label><item name="Cauldron" count="1"/><item name="Lilia Flower" count="1"/><item name="water" count="1"/><item name="Energy" count="1"/></info><option auto="return_to_wizard_step"><collect item="Health Potion" count="1"/></option></step>
- Теперь добавим промежуточный шаг
return_to_wizard_step, который заменит текст в блокеinfo, а также выведет на экран игроку надпись: «Цель: Отнести зелья Волшебнику»
<step id="brew_health_potion_step">. . .</step><step id="return_to_wizard_step"><desc>Отлично! Вижу, что ты справился</desc><option to="consume_health_potion_step" text="Ок"/><label location="HUD"><persist/><position x="-200" y="-300"/><scale x="24" y="24"/>[FFAA00]Цель:[-] Отнести зелья Волшебнику</label><info><label>Вернись к Волшебнику и скажи, что ты сварил Зелье</label></info></step><step id="#end_dark_side">. . .</step>
- Теперь добавим наш шаблонный шаг на выпивание Зелья. Он находиться между
return_to_wizard_stepи#end_dark_side
<consumestep id="consume_health_potion_step"><intro>Теперь выпей это Зелье! Тебе сразу же полегчает</intro><desc>Давай пей. Чего ты ждёшь?</desc><finish>Вот видишь. Я прямо вижу, как ты стал здоровее выглядеть!</finish><consume target="Player" item="Health Potion" count="1" /><rewards><reward exp="50"/></rewards><option to="#end_dark_side" text="Ок"/></consumestep>
- И наконец отредачим текст в
#end_dark_side:
<step id="#end_dark_side"><desc>Пока, Наездник Дракона. Был рад повидаться!</desc><option to="#start" text="Назад"/><option to="#close" text=". . ."/></step>
Шаг 4. Проверяем
Всё работает.
Шаг 5. Добавить/заменить текст в Журнале
В обычных шагах такое не работает.
Когда игрок завершает задание, например, на убийство двух тигров. После выполнения у него просто висит «Убить Тигр 2 / 2». Без какого-либо пояснения. Выглядит это не очень красиво.
Мы же можем добавить новый текст к заданию в Журнале, например, «Вернись к [Имя NPC]» или вообще заменить на этот текст всё задание, убрав надпись «Убить Тигр 2 / 2»
Для этого будем использовать теги:
<replace>— заменить все строки задания от квеста в Журнале<append>— добавить новые строки к записи в Журнале
Размещается внутри <intro>, <desc>, <finish>, сразу под текстом:
Для <replace>
<intro>Какой-то текст<replace><info><label>Замещающий текст</label></info></replace></intro>
Для <append>
<intro>Какой-то текст<append><info><label>Этот текст добавится снизу</label></info></append></intro>
Готовые шаблоны шагов
Ниже приведены готовые наборы для всех типов шаблонных шагов. Отличаются друг от друга только названием (<killstep>, <craftstep> и т.д.) и тегами-условиями внутри (<kill>, <craft> и т.д.)
Убийство
<killstep id="spider_kill_step">
<intro>Убей парочку пауков!</intro>
<desc>Пауки ещё живы.</desc>
<finish>Молодец! Держи награду.</finish>
<kill enemy="Spider" count="2"/>
<rewards>
<reward exp="50"/>
</rewards>
<option text="ОК" to="#end"/>
</killstep>
Крафт
<craftstep id="craft_tools_step">
<intro>Скрафти топор и факел на верстаке.</intro>
<desc>Тебе ещё нужно скрафтить инструменты.</desc>
<finish>Отлично! Теперь ты готов к работе.</finish>
<craft name="Axe" type="Table"/>
<craft name="Tourch" type="Table"/>
<rewards>
<reward exp="50"/>
</rewards>
<option text="Далее" to="#end"/>
</craftstep>
Сбор
<collectstep id="gather_step">
<intro>Принеси мне 10 яблок и 5 костей.</intro>
<desc>Ещё не всё собрано.</desc>
<finish>Спасибо! Ты очень помог.</finish>
<collect item="Apple" count="10"/>
<collect item="Bone" count="5"/>
<rewards>
<reward exp="50"/>
</rewards>
<option text="Ага" to="#end"/>
</collectstep>
Передача
<removestep id="help_step">
<intro>Мне нечего есть, дай, пожалуйста, 5 булок хлеба</intro>
<desc>Ты мне дашь хлеб?</desc>
<finish>Благодарю! Ты очень щедр.</finish>
<remove item="Bread" count="5"/>
<rewards>
<reward exp="50"/>
</rewards>
<option text="Кушай" to="#end"/>
</removestep>
Поедание
<consumestep id="feed">
<intro>Съешь 2 хлеба и скорми 1 яблоко своему дракону</intro>
<desc>Давай же, скорми своему дракончику 2 хлеба и 1 яблоко</desc>
<finish>Отлично! Теперь вы сыты.</finish>
<consume target="Player" item="Bread" count="2"/>
<consume target="Drako" item="Apple" count="1"/>
<rewards>
<reward exp="50"/>
</rewards>
<option text="Все" to="#end"/>
</consumestep>
Задания на закрепление
- Перепишите квест Теда (
Viking) из Главы 12, заменив вручную собранный шаг<removestep> - Сделайте квест для Крестьянина (
PeasantMale), используя<consumestep>и<craftstep>, в котором крестьянин показывает игроку рецепт Хлеба, а затем просит приготовить и съесть его.
Заключение
В этой Главе мы разобрались с шаблонными шагами – мощным инструментом для ускорения разработки и сокращения объемов кода. Мы разобрали струтуру, поняли, что значит кавждый отдельный тег и применили свои знания на практике. Теперь мы можем попрощаться с бесконечной рутиной
Итоговый код Главы
<?xml version="1.0" encoding="UTF-8"?><quest npc="Wizard" title="Мой Первый Квест"><step id="#start"><intro>Привет, [FFAA00]как дела[-]?</intro><desc>[FFAA00]Рад[-] тебя снова видеть! Как дела?</desc><option to="bad_mood_step" text="[FF0000]Плохо[-]"/><option to="good_mood_step" text="[00FF00]Норм[-]"/></step><!-- Хорошее настроение --><step id="good_mood_step"><intro>Это хорошо, что хорошо.У меня есть одно плёвое заданьеце для тебя.Готов ли его выполнить?</intro><desc>Снова ты?\nМоё предложение всё ещё актуально.\nГотов приступить?</desc><option to="spider_hunt_step" text="Да"><journal/></option><option to="#start" text="Назад"/></step><step id="spider_hunt_step"><desc>Хорошо. Попробуй убить парочку пауков для разминки. Также принеси мне яблочко, а то я уж больно проголодался</desc><item name="Apple" count="1"/><option to="#close" text="Ок"/><rewards type="Award"><reward exp="300"/><row><reward item="Axe" count="5"/><reward recipe="Sunshard Paula" type="Table"/></row></rewards><label location="HUD"><persist/><position x="-200" y="-300"/><scale x="24" y="24"/>[FFAA00]Цель:[-] 2 паука и яблоко</label><info><kill enemy="Spider" count="2"/><collect item="Apple" count="1"/><label>Яблоко: </label><item name="Apple" count="1"/></info><option auto="after_hunt_step"><kill enemy="Spider" count="2"/><collect item="Apple" count="1"/><notify>[00FF00]Задание выполнено![-] \nВернись к Волшебнику!</notify></option></step><step id="after_hunt_step"><desc>Отлично! Ты справился</desc><rewards type="Display"><reward exp="300"/><row><reward item="Axe" count="5"/><reward recipe="Sunshard Paula" type="Table"/></row></rewards><option to="spider_hunt_step" text="Уйти"/><option to="#end" text="Ок"><remove item="Apple" count="1"/><reward exp="300"/><reward item="Axe" count="5"/><reward recipe="Sunshard Paula" type="Table"/></option><info><label>Вернись к Волшебнику и скажи, что ты убил всех пауков</label></info></step><step id="#end"><desc>Прощай, Наездник Дракона! Рад был повидаться</desc><option to="#start" text="Назад"/><option to="#close" text="Пока"/></step><!-- Плохое настроение --><step id="bad_mood_step"><intro>Очень жаль! Крепись там</intro><desc>Понимаю, что тебе сейчас не хорошо, крепись там!</desc><option to="brew_health_potion_step" text=":("><journal/></option><option to="#start" text="Назад"><reward item="Health Potion" count="1000"/></option></step><step id="brew_health_potion_step"><desc>Могу предложить тебе сварить Зелье Здоровья. Это должно помочь поднять тебе настроение.</desc><option to="#close" text="Понял"/><label>Вот рецепт:</label><recipe name="Health Potion" type="Cauldron" /><label><scale x="1000" y="8"/>[FFFF00]_[-]</label><row><label>Скрафти Котел</label><item name="Cauldron" count="0"/><label>и помести:</label></row><row><item name="Lilia Flower" count="1"/><item name="water" count="1"/><item name="Energy" count="1"/></row><info><label>Свари Зелье Здоровья по рецепту: </label><recipe name="Health Potion" type="Cauldron" /><label>После приготовления, подойди к Волшебнику!</label> <!-- --><label></label><label>Для приготовления потребуются: </label><item name="Cauldron" count="1"/><item name="Lilia Flower" count="1"/><item name="water" count="1"/><item name="Energy" count="1"/></info><option auto="return_to_wizard_step"><collect item="Health Potion" count="1"/> <!-- --></option></step><step id="return_to_wizard_step"><desc>Отлично! Вижу, что ты справился</desc><option to="consume_health_potion_step" text="Ок"/><label location="HUD"><persist/><position x="-200" y="-300"/><scale x="24" y="24"/>[FFAA00]Цель:[-] Отнести зелья Волшебнику</label><info><label>Вернись к Волшебнику и скажи, что ты сварил Зелье</label></info></step><consumestep id="consume_health_potion_step"><intro>Теперь выпей это Зелье! Тебе сразу же полегчает</intro><desc>Давай пей. Чего ты ждёшь?</desc><finish>Вот видишь. Я прямо вижу, как ты стал здоровее выглядеть!</finish><consume target="Player" item="Health Potion" count="1"/><rewards><reward exp="50"/></rewards><option to="#end_dark_side" text="Ок"/></consumestep><step id="#end_dark_side"><desc>Пока, Наездник Дракона. Был рад повидаться!</desc><option to="#start" text="Назад"/><option to="#close" text=". . ."/></step></quest>
Отличный гайд, но осталось несколько вопросов:
1) Куда делся раздел с кастомным магазином из прошлой версии руководства. В 13.5.0? Его больше нельзя кастомизировать?
2) У Фуза в 13.5.0 есть свой магазин, следовательно, они тоже стали квестовыми НПС и для них можно делать кастомные квесты. Или нельзя?
1) Кастомные магазины полностью убраны (даже для Алхимика, Фуза и Крестьян). Теперь игра не будет подгружать квесты, содержащие в коде тег <store>
В логах будет писать:
Skipped custom quest ‘ИмяКвеста’ from file [Путь до XML-файла квеста]: NPC stores are not allowed in custom quests
UnityEngine.DebugLogHandler:Internal_Log(LogType, LogOption, String, Object)
UnityEngine.Logger:Log(LogType, Object)
UnityEngine.Debug:LogWarning(Object)
QuestManager:AddUserQuests(XmlSerializer, String)
d__77:MoveNext()
UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)
2) Да, для Фуза можно теперь тоже делать квесты. Список Квестовых NPC только что обновил, просто изначально забыл добавить
Из нюансов: У них пока что нет своего портрета, поэтому будет видно просто имя