Новости/News | | Туториалы/Tutorials | | Форум/Forum | | ЧаВо/FAQ | | Файлы/Downloads | | Ссылки/Links | | Авторы/About |

Мутатор: первые шаги

Содержание

Вступление

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

Основная идея:
При попадании в игрока, наш мутатор будет переводить урон полученный игроком, в энергию движения этого игрока. Т.е. если в игрока попадут из редимера, то он (разумеется игрок) улетит о-о-чень далеко, не получив ни единой царапины. По ходу дела мы еще введем парочку изменений, но общая идея останется прежней. Мутатор не претендует ни на что особенное, он просто выбран для примера. Назовем его - ZeroDamage.

Общие сведения

Я не буду использовать UnrealED для написания кода, и вам не советую. Текст скрипта набивайте в любом удобном для вас редакторе. Итак, начнем.

Первое что вам надо знать - UT основан на системе паков (packages), т.е. игровые ресурсы (текстуры, звуки и пр.) распределяются по отдельным файлам - пакам. Например текстуры хранятся в *.utx файлах, звуки в *.uax. Скрипты тоже имеют свои паки - *.u файлы, причем у этих файлов есть одна особенность - кроме скриптов там могут хранится также модели (meshes), текстуры и звуки - эдакий универсальный формат (правда следует сказать что все паки построены по единому принципу и на одном формате, различие по расширениям введено для удобства).

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

  1. Создайте следующие два каталога:

    UnrealTournament
     |
     +- ZeroPack
         |
         +- Classes
    

    Каталог ZeroPack - это и есть наш будущий пак ZeroPack.u. В каталоге Classes будут храниться файлы скриптов (*.uc), в одном таком файле хранится реализация одного класса. Создайте в этом каталоге файл ZeroDamage.uc - там и будет храниться текст нашего мутатора.

  2. В созданном ZeroDamage "набейте" следующий код:

    //------------------------------------
    // ZeroDamage mutator
    //------------------------------------
    
    // Наследуем от класса Mutator
    class ZeroDamage extends Mutator;
    
    var bool initialized;
    
    // Эта функция вызывается при инициализации любого актора
    function PostBeginPlay()
    {
      if(initialized)
        return;
    
      initialized = true;
    
      // Регистрация damage мутатора
      Log("------ !c00l! ZeroDamage mutator !c00l! ------");
      Level.Game.RegisterDamageMutator(Self);
    }
    
    // Эта функция вызывается для зарегистрированных damage мутаторов
    // перед подсчетом финального ущерба
    function MutatorTakeDamage(out int ActualDamage, Pawn Victim, Pawn InstigatedBy,
                               out Vector HitLocation, out Vector Momentum, name DamageType)
    {
      // Сообщения для отладки
      broadcastmessage("Killer: "$InstigatedBy.PlayerReplicationInfo.PlayerName);
      broadcastmessage("Victim: "$Victim.PlayerReplicationInfo.PlayerName);
      broadcastmessage("ActualDamage: "$ActualDamage);
    
      // Увеличиваем величину момента удара (это вектор), не меняя самого вектора
      Momentum.x+=ActualDamage;
      Momentum.y+=ActualDamage;
      Momentum.z+=ActualDamage;
    
      // Обнуляем полученные повреждения
      ActualDamage = 0;
    
      // Передаем изменившиеся параметры следующему damage мутатору
      if ( NextDamageMutator != None )
        NextDamageMutator.MutatorTakeDamage(ActualDamage, Victim, InstigatedBy, 
                                                 HitLocation, Momentum, DamageType );
    }
    
    defaultproperties
    {
    }
    

    Некоторые пояснения. Первое, зачем следующая строчка:

    if (initialized)
      return;
    

    До недавнего времени это была одна из особенностей мутаторов (да и вообще всех акторов), для них (Post)BeginPlay функции вызывалась два раза, чтобы код инициализации не выполнялся дважды - мы поставили это простое условие. В последних версиях движка это пофиксено (начиная с 413), однако не у всех игроков всегда последняя версия UT, так что это условие стоит оставить.

    Level.Game.RegisterDamageMutator(Self);
    

    Переменная Level типа LevelInfo - указывает на текущий уровень (данная переменная определена в классе Actor), в классе LevelInfo определена переменная Game типа GameInfo - указатель на текущий тип игры (DeathMatchPlus, CTF и пр.). В GameInfo - определена функция RegisterDamageMutator - которую мы и вызываем, передавая в качестве параметра Self (ссылку на наш мутатор). Регистрировать нам нужно, чтобы движок вызывал функцию MutatorTakeDamage для нашего мутатора. Данная функция вызывается каждый раз, когда какой-либо игрок получил повреждения. Параметры этой функции ясны из их названий, нас пока интересуют: ActualDamage - непосредственный ущерб и Momentum - вектор удара.

    BroadcastMessage - текстовые сообщения во время игры, мы используем эту функцию для отладки (просмотр значений). Log - текстовые сообщения в лог игры, здесь также используется для отладки.
    Далее, изменив интересующие нас параметры, мы передаем параметры следующему damage мутатору, если таковой есть.

    if ( NextDamageMutator != None )
      NextDamageMutator.MutatorTakeDamage(ActualDamage, Victim, InstigatedBy, 
                                               HitLocation, Momentum, DamageType );
    

  3. Теперь пора создать соответствующий пак. Откройте файл UnrealTournament.ini, в нем найдите раздел [Editor.EditorEngine] В этом разделе ищите строчки вида EditPackages=... и в самом конце добавьте строчку EditPackages=ZeroPack, должно быть что-то типа:

    [Editor.EditorEngine]
    ...
    EditPackages=Botpack
    EditPackages=UTServerAdmin
    EditPackages=UTMenu
    EditPackages=UTBrowser
    EditPackages=ZeroPack
    
  4. Теперь запустите ucc make (программа UCC находится в каталоге UT\System). Если вы все сделали правильно, UCC должен выдать что-то типа:

    ...
    --------------------ZeroPack--------------------
    Analyzing
    Parsing ZeroDamage
    Compiling ZeroDamage
    
    Success - 0 error(s), 0 warnings
    

    В системном каталоге UT должен появиться файл ZeroPack.u

  5. Остался последний штрих. Нам надо чтобы UT находил наш мутатор и добавлял его в список мутаторов. Для этого создайте файл ZeroPack.int, в который добавьте строчки:

    [Public]
    Object=(Name=ZeroDamage.ZeroDamage,Class=Class,MetaClass=Engine.Mutator,Description="Zero Damage, c00l mutator!")
    

  6. Теперь собственно все. Запускаем UT...

Примечание №1: Каждый раз, когда вы будете компилировать пак при помощи ucc, предварительно удаляйте ZeroPack.u из системного каталога UT, иначе компилятор не будет создавать обновленную версию пака.

Примечание №2:Есть достаточно удобные программы автоматизирующие процесс компиляции, смотрите раздел "Файлы" на нашем сайте.

Некоторые усовершенствования

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

Во-первых, мы будем проверять свойство InstigatedBy (тот кто нанес дамаж), и во-вторых, мы будем уменьшать повреждения при падении с высоты, но не обнулять его. Изменения в коде мутатора выделены:

function MutatorTakeDamage(out int ActualDamage, Pawn Victim, Pawn InstigatedBy,
                           out Vector HitLocation, out Vector Momentum, name DamageType)
{
  // Увеличиваем момент
  Momentum.x+=ActualDamage;
  Momentum.y+=ActualDamage;
  Momentum.z+=ActualDamage;

  // Обнуляем полученные повреждения только если киллер - игрок
  if (InstigatedBy.IsA('Pawn')) ActualDamage=0;
  // Если падение с высоты, то дамаж уменьшаем, но не обнуляем
  if (DamageType == 'Fell')
    ActualDamage/=2;
  // Передаем параметры следующему damage мутатору
  if ( NextDamageMutator != None )
    NextDamageMutator.MutatorTakeDamage(ActualDamage, Victim, InstigatedBy, 
                                           HitLocation, Momentum, DamageType );
}

Мы используем метод IsA для проверки принадлежности InstigatedBy к классу Pawn (это игрок, боты, стационарные пушки и монстряки) и обнуляем ActualDamage. Если это будет что-то иное - ActualDamage останется прежним. К тому же, мы еще проверяем тип дамажа, если игрок упал с высоты - то ActualDamage уменьшается в два раза. Если вы хотите, чтобы игроку наносились его же повреждения, то можно написать что-то типа:

if (Victim != InstigatedBy && InstigatedBy.IsA('Pawn'))
  ActualDamage=0;

Исходный код обеих версий мутатора ZeroDamage можно взять здесь.

Заключение

Вот собственно и все. Изучайте и испытывайте, ничего сложного здесь нет. Испробовав парочку таких штучек вы будете "щелкать" мутаторы как орехи, самое трудное здесь - подобрать идею.

Напоследок, пара слов о применении мутаторов. Назначение мутаторов - небольшое изменение геймплея, в распоряжении мутатормейкера ряд эффективных, но ограниченных средств, т.к. различные мутаторы должны уметь работать вместе. Если у вас глобальные идеи, то мутаторы вам не помогут, тут есть другое средство - создание своего типа игры (GameInfo) - но это совсем другая история...

Автор

Автор: Shadow
Mail: shadow_m777@mail.ru

Хостинг от uCoz