[13.5] Создание Своих Квестов для Игры

Reading Mode

Этап 4. Оптимизация и Цепочки Квестов

На этом Этапе вы научитесь значильно сокращать код у некоторых рутинных задач (убийство, сбор и т.д.), а также делать цепочки из нескольких квестов (.xml файлов)

Глава 15. Шаблонные шаги

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

На этот случай в игре есть заранее заготовленные супер-шаги, которые объединяют в себе: выдачу задания, проверку условий и выдачу награды + текстовыми блоками (intro, desc, finish). Это позволяет сделать код намного более читаемым, а также существенно упростить создание однотипных заданий.

Шаг 1. Конструктор VS Шаблон

Обычный <step>, которым мы пользовались во всех прошлых Главах – это конструктор. Вы сами ручками собираете каждую отдельную детальку. Это удобно, когда шаг включает сразу несколько разносторонних заданий или сложные условия.

Шаблонные шаги – это готовая фигурка, которую уже собрали за вас. Вам лишь нужно раскрасить её под себя. Они подходят, когда шаг включает в себя несколько однотипных заданий

Всего есть 5 шагов-шаблонов:

  1. <killstep> – убийство мобов
  2. <collectstep> – сбор предметов (предметы НЕ забирают)
  3. <removestep> – сбор предметов (предметы забирают)
  4. <craftstep> – задания на крафт чего-либо
  5. <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> и т.д.)

Что можно добавлять внутрь:

  1. item – Иконка предмета
  2. recipe – Показать рецепт
  3. row – Группировка
  4. label – Текст в диалоге. Нюанс: этот текст будет отображаться на всех этапах квеста под всеми текстовыми блоками (intro, desc, finish)
  5. label атрибутом loation и тегом <persist/> – Текст, выводящийся на экран игрока. Нюанс: Текст на экране остается на протяжении всего шага (от intro до finish), начиная моментом принятия задания и заканчивая моментом сдачи. При переходе на следующий шаг, текст с экрана исчезнет
  6. notify – Уведомления, но только внутри единственной кнопки-опции

Нельзя добавлять:

  1. Авто-опции
  2. Неподходящие цели (например, в killstep добавить collect)
  3. Дополнительные кнопки

Все это будет проигнорировано

Шаг 3. Используем в квесте

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

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

Но мы можем добавить в эту ветку новый шаг consumestep.

Суть такая:

  1. Меняем brew_health_potion_step, чтобы там просто показывали рецепт и просили сварить Зелье
  2. После варки, перебрасывает на шаг: return_to_wizard_step, который заменяет запись в Журнале на: «Вернись к Волшебнику и скажи, что ты сварил Зелье»
  3. Игрок подходит к Волшебнику и тот ему говорит, чтобы он выпил это зелье
  4. После нажатия кнопки «Ок», игрока перебрасывает на наш consumestep, который назовем consume_health_potion_step
  5. За выполнение дается 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»

Для этого будем использовать теги:

  1. <replace> — заменить все строки задания от квеста в Журнале
  2. <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>

Задания на закрепление

  1. Перепишите квест Теда (Viking) из Главы 12, заменив вручную собранный шаг <removestep>
  2. Сделайте квест для Крестьянина (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>

 

2
0

Comments

  1. Northern_77
    Northern_77

    Отличный гайд, но осталось несколько вопросов:
    1) Куда делся раздел с кастомным магазином из прошлой версии руководства. В 13.5.0? Его больше нельзя кастомизировать?
    2) У Фуза в 13.5.0 есть свой магазин, следовательно, они тоже стали квестовыми НПС и для них можно делать кастомные квесты. Или нельзя?

    1
    0
    • Da-Damych
      Da-Damych

      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 только что обновил, просто изначально забыл добавить
      Из нюансов: У них пока что нет своего портрета, поэтому будет видно просто имя

      1
      0

Leave a Reply