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

Reading Mode

Этап 5. Управление миром и UI

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

Глава 17. Спавн и проверки

В прошлых Главах мы выдавали игроку задание на убийство и заставляли его бегать по миру, чтобы найти нужных мобов. Это работает и подстегивает исследовать мир, но иногда в некоторых ситацияых это выглядит, как сказать гостю: «Хочень торт? Иди сгоняй на кухню, найди его там в холодильнике и притащи мне».

В этой Главе мы научимся призывать мобов прямо во время диалога, проверять их наличие, очищать мир от всех них и запрещать их естественный спавн

Шаг 1. <spawn/> – Призыв мобов

Тег <spawn/> спавнит нужного моба прямо во время квеста. Буквально, как по щелчку пальцев

Полный синтаксис тега:

<spawn mob="ИмяМоба" distance="5" angry="false"/>

Где:

  1. mob – Системное имя призываемого моба (см. таблицу GigaList)
  2. distance – На каком расстоянии (в блоках) заспавнить моба
  3. angry – Делать ли нейтрального моба агрессивным (true/false). Для враждебных и мирных мобов этот атрибут не указывать

!!! Важные нюансы:

  1. В одном шаге нельзя спавнить больше трёх мобов одного типа за раз. Условно, если напишите 10, то гарантированно заспавнится только 3 моба, а остальные как повезет.
  2. Боссы и мини-боссы – только по одному. Точно заспавнится только один, если попробуете больше – они просто не появятся

Шаг 2. Практика спавнов

В Главе 16 Аарон просил нас убить Арагога, и мы бегали его искали. Теперь сделаем покруче. Допустим, пока Аарон перед нами распинался, Арагог сам пришел и застал всех в расплох. Получается наша Цель сама к нам пожаловала.

Открываем квест Аарона (WarriorFirstQuest.xml – «Маленькая Проблемка») и находим там наш шаблонный шаг small_problem_step. Теперь нам нужно добавить туда спавн Арагога, но шаблонный шаг такого не позволит. Значит, заменяем его на 4 обычных (step), где в первом нам будут рассказывать историю из intro, во втором он будет орать от испуга, в третьем будет спавн Арагога и сама битва, а в четвертом нам выдадут награду и распрощаются.

Можно было и в 2-3 шага уложиться, но для эффектности сделаем 4, заодно потренируемся и повторим несколько тем из прошлых Глав.

Было:

    <killstep id="small_problem_step">
      <intro>Видишь ли, у меня тут появилась небольшая проблемка. Говорят, что на дне земных провалов на тамошних деревьях растут         самые вкусные яблочки. Я бы и рад туда спуститься, но там сидит огромный паук – Арагог. \nЯ, понимаешь ли, даже мелких               паучков страшусь, а тут аж огромный Паучище
      \nВ общем, не мог бы ты мне немножко подсобить с этой маленькой проблемкой? Я готов немного приплатить за это.
      </intro>
      <desc>Так ты поможешь или нет?</desc>
      <finish>Спасибо. Наконец я смогу без опаски спуститься в те провалы и насладиться тамошними яблочками</finish>

      <kill enemy="GiantSpider" count="1"/>

      <rewards>
          <reward exp="500"/>
          <reward item="Gold Coin" count="30"/>
      </rewards>

      <option to="after_aragog_step" text="Ок"/>
  </killstep>

Стало:

    <step id="small_problem_step">
      <desc>Видишь ли, . . . маленькой проблемкой? Я готов немно...</desc>
         
      <rewards type="Display">
          <reward exp="500"/>
          <reward item="Gold Coin" count="30"/>
      </rewards>

      <option to="before_aragog_step" text="Да"/>
  </step>

  <step id="before_aragog_step">
      <desc></desc>
      <label>[FF0000]А-А-А-А! ОН УЖЕ ЗДЕСЬ![-]\n\nКто не спрятался — я не виноват!</label>

      <option to="battle_aragog_step" text="!!!"/>
    </step>

  <step id="battle_aragog_step">
      <info>
          <label>Убей [FF0000]Арагога[-]</label>
          <kill enemy="GiantSpider" count="1"/>
      </info>

      <option auto="#close">

          <spawn mob="GiantSpider" distance="3"/>
      </option>

      <option auto="after_battle_aragog_step">
          <kill enemy="GiantSpider" count="1"/>
      </option>
  </step>

  <step id="after_battle_aragog_step">
      <desc>Да ты мне жизнь спас! Так ещё я смогу насладиться тамошними яблочками в провалах!\nДержи, ты заслужил</desc>
     
      <option to="after_aragog_step" text="Ок"/>

      <rewards type="Award">
          <reward exp="500"/>
          <reward item="Gold Coin" count="30"/>
        </rewards>

        <info>
            <label>Скажи Аарону, что ты убил Арагога</label>
      </info>

    </step>

Обратите внимание на авто-опцию с #close!

В шаге battle_aragog_step банально нет ни одного текстового блока, а это значит, что при переходе на него у игрока будет «пустой экран», точнее сломанный диалог. Чтобы не допустить этого, мы добавляем в самый верх авто-опцию с #close, которая автоматически при переходе на этот шаг закроет сломанное диалоговое окно. В нашем случае, эта авто-опция еще и Арагога спавнит.

Вообще можете использовать эту авто-опцию без вложенных тегов:

<option auto="#close"/>

Обязательно ставьте её в САМЫЙ верх вашего невидимого шага. Игра проходиться по коду сверху вниз, а значит закроет диалоговое окно она в первую очередь. Тем самым игрок даже ничего не заметит.

Шаг 3. <existmobs/> – жив ли моб

Иногда нужно проверить: есть в мире моб или нет. На такой случай как раз есть тег <existmobs/>, который кладется внутрь опций

<existmobs name="ИмяМоба"/>

Условие сработает, если моб жив. Если умер/задеспавнился, то условие не сработает.

Если нам нужно проверить, что моб отсутствует. Умер/задеспавнился, то для этого внутрь <existmobs/> вкладываем тег <inverse>, который инвертирует условие

<existmobs name="ИмяМоба">
  <inverse/>
</existmobs>

Использование:
Сработает, если в видимых (прогруженных) чанках есть живая Паула

<option auto="paula_alive_step">
<existmobs name="FemaleWarrior"/>
</option>

Сработает, когда Паулы нет в видимых чанках (задеспавнилась/умерла)

<option auto="paula_dead_step">
<existmobs name="FemaleWarrior">
<inverse/>
</existmobs>
</option>

Наш квест

В нашем квесте мы будем использовать второй вариант с <inverse/>. С помощью него мы будем проверять: аздеспавнился Арагог или нет. Если он задеспавнился, то есть не был убит игроком, то тогда спавним его по-новой.

Для этого внутрь шага battle_aragog_step добавим ещё одну авто-опцию

ОЧЕНЬ ВАЖНО! Добавляем эту авто-опцию СТРОГО под опцией, проверяющей убийство Арагога (где kill). Игра проверяет код сверху вниз. Сначала она проверит, что Арагог не убит игроком (kill) и только потом узнает: есть он в мире вообще или нет (existmobs).

Если перепутать порядок, то, сразу после убийства Арагога, игра заспавнит нового, но при этом авто-опция с kill перейдет на шаг с победой. Получится странная ситуация, когда Босс опять есть, но задание считается выполненым

Код:

    <step id="battle_aragog_step">
      <info>
          <label>Убей [FF0000]Арагога[-]</label>
          <kill enemy="GiantSpider" count="1"/>
      </info>

      <option auto="#close">
          <spawn mob="GiantSpider" distance="3"/>
      </option>

      <option auto="after_battle_aragog_step">
          <kill enemy="GiantSpider" count="1"/>
        </option>

      <option auto="battle_aragog_step">
        <existmobs name="GiantSpider">
            <inverse/>
        </existmobs>
      </option>
    </step>

Наша новая опция проверяет: задеспавнился Арагог или нет. Если он задеспавнился, то она перезапускает свой же шаг battle_aragog_step

Еще раз, опция с existmobs должна быть ПОД опцией с kill

Как видите, даже если игрок умирает, то Арагог все равно респавнится радом с ним. Даже смерть не спасет

Шаг 4. <clearmobs/> – удалить всех мобов

Перед битвой, например, с Боссом из квеста в мире гарантировано будут бродить другие сущетсва. В игре мобов в прогруженных чанках может быть ограниченное количество. Если этот лимит заполнен, то новые существа (даже те, которые спавняться через <spawn/> в квесте) появляться не будут и это проблема

Для очистки используется тег <clearmobs/>. Он удалет вообще ВСЕХ мобов из мира. Даже NPC, с которым сейчас говорит игрок. Поэтому используйте этот тег осторожно и строго по необходимости.

Добавим в квест Аарона

Добавлять мы будем во всё тот же шаг battle_aragog_step в авто-опцию, которая спавнит Арагога:

    <step id="battle_aragog_step">
      <option auto="#close">
          <clearmobs/>
          <spawn mob="GiantSpider" distance="3"/>
      </option>
      . . .
    </step>

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

По желанию, также можно добавить спавн Аарона сразу после убийства Арагога, чтобы игроку не пришлось бегать по миру и искать его:

    <step id="battle_aragog_step">
      . . .

      <option auto="after_battle_aragog_step">
          <kill enemy="GiantSpider" count="1"/>
          <spawn mob="Warrior" distance="5"/>

        </option>

      . . .
    </step>

Шаг 5. <spawnmobs/> – Естественный спавн

Во ремя важных сюжетных битв (с Боссами, например) нужно чтобы не мешали всякие сторонние мобы. Сражаетесь вы с условным Арагогом, почти уже добили его, как вдруг спавниться Волшебник и выносит его. Либо вообще во время битвы на игрока нападают враждебные мобы, а самого Босса дамажат снова появившиеся нейтральные NPC. <clearmobs/> лишь единожды очищает мобов, повторно его применить не получиться, иначе исчезнет ещё сам Босс.

Благо для этого есть тег <spawnmobs/>, который регулирует естественный спавн мобов в мире. Он никак не влияет на спавн через тег <spawn/> в квестах или через спавнеры.

Всего у него есть 2 состояния:

  1. <spawnmobs value="false"/> – Отключает естественный спавн мобов
  2. <spawnmobs value="true"/> – Включает его

Важно! Не забывайте включать спавн обратно (value="true") в конце квеста/шага-победы. Иначе мир останется «мертвым» и мобы просто не будут самостоятельно появляться в мире.

Используем в квесте Аарона:

Добавим в шаг battle_aragog_step, в опцию, ведущую на #close, то бишь закрывающее сломанное диалоговое окно. Помним, что в этом шаге нет <desc>, поэтому диалоговое окно тут битое.

    <step id="battle_aragog_step">
      <option auto="#close">
          <clearmobs/>
          <spawnmobs value="false"/>
          <spawn mob="GiantSpider" distance="3"/>
      </option>
      . . .
    </step>

Не забываем обратно включать естественный спавн в шаге-победе (after_battle_aragog_step). Засунем это в кнопку:

    <step id="after_battle_aragog_step">
      <desc>Да ты мне жизнь спас! . . .\nДержи, ты заслужил</desc>
     
        <option to="after_aragog_step" text="Ок">  
          <spawnmobs value="true"/>
     </option>
     . . .
    </step>

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

  1. Сделайте квест от Крестьянина, в котором он спавнит трех оборотней
  2. Сделайте квест от Волшебника, в котором он спавнит 3 волны монстров. На третьей Волне добавьте какого-нибудь Босса, например, Ашкор. Квест визуально оформите на свое усмотрение (уведомления, надписи, разноцевтный текст и так далее)

Заключение

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

В следующих главах перейдем к картинкам, спецэфектам и анимациям.

Итоговый код Главы

WarriorFirstQuest.xml – «Маленькая Проблемка»

<?xml version="1.0" encoding="UTF-8"?>
<quest npc="Warrior" title="Маленькая Проблемка">
    <complete quest="Основной Квест" step="go_to_warrior_step" />

  <step id="#start">
      <desc>Привет, Наездник Дракона. Полагаю, тебя послал Волшебник. \nЧтож у меня есть для тебя небольшое заданьеце</desc>
      <option to="small_problem_step" text="?">
          <journal />
      </option>
    </step>

  <step id="small_problem_step">
      <desc>Видишь ли, у меня тут появилась небольшая проблемка. Говорят, что на дне земных провалов на тамошних деревьях растут самые вкусные яблочки. Я бы и рад туда спуститься, но там сидит огромный паук – Арагог. \nЯ, понимаешь ли, даже мелких паучков страшусь, а тут аж огромный Паучище
      \nВ общем, не мог бы ты мне немножко подсобить с этой маленькой проблемкой? Я готов немно...</desc>
         
      <rewards type="Display">
          <reward exp="500"/>
          <reward item="Gold Coin" count="30"/>
        </rewards>

      <option to="before_aragog_step" text="Да"/>
    </step>

  <step id="before_aragog_step">
      <desc></desc>
        <label>[FF0000]А-А-А-А! ОН УЖЕ ЗДЕСЬ![-]\n\nКто не спрятался — я не виноват!</label>

      <option to="battle_aragog_step" text="!!!"/>
    </step>

  <step id="battle_aragog_step">
      <info>
          <label>Убей [FF0000]Арагога[-]</label>
          <kill enemy="GiantSpider" count="1"/>
        </info>

      <option auto="#close">

          <clearmobs/>
          <spawnmobs value="false"/>
          <spawn mob="GiantSpider" distance="3"/>
      </option>

      <option auto="after_battle_aragog_step">
          <kill enemy="GiantSpider" count="1"/>
          <spawn mob="Warrior" distance="5" />
        </option>

      <option auto="battle_aragog_step">
          <existmobs name="GiantSpider">
              <inverse/>
          </existmobs>
      </option>
    </step>

  <step id="after_battle_aragog_step">
      <desc>Да ты мне жизнь спас! Так ещё я смогу насладиться тамошними яблочками в провалах!\nДержи, ты заслужил</desc>
     
      <option to="after_aragog_step" text="Ок"/>

      <rewards type="Award">
          <reward exp="500"/>
          <reward item="Gold Coin" count="30"/>
      </rewards>
    </step>

  <step id="after_aragog_step">
      <desc>Пока, и ещё раз спасибо за помощь</desc>
      <option to="#close" text="Ок">
          <spawnmobs value="true"/>
      </option>

      <info>
          <label>Иди к Волшебнику и проверь, есть ли у него задания</label>
        </info>

      <option auto="before_find_bed_step">
          <complete quest="Основной Квест" step="after_pig_go_warrior"/>
      </option>
    </step>

  <step id="before_find_bed_step">
        <desc>Слу-у-ушай...</desc>

      <option to="find_bed_step" text="Ок"/>
    </step>

  <removestep id="find_bed_step">
      <intro>Можешь найти мне кровать? Да, обычную кровать. Моя что-то в совсем уж печально состоянии</intro>
      <desc>Так ты найдешь кровать?</desc>
        <finish>Спасибо, Наездник Дракона. Эта кровать мне очень пригодиться</finish>

        <remove item="Bed" count="1"/>

      <rewards>
          <reward exp="777"/>
        </rewards>

      <option to="#end" text="Ок"/>
    </removestep>

  <step id="#end">
      <desc>Ну а теперь пока, Наездник Дракона. Был рад повидаться.\nИди к Волшебнику, может, у него есть какое-то задание для тебя</desc>
      <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