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

Lode's All about movers tutorial v1.0

Загрузка этой страницы требует некоторого времени, так что не пинайте модем ногами - ну если это конечно не WinModem :).
Просмотреть оригинал (на английском языке) можно воспользовавшись линком: Lode's Unreal Tournament Tutorials page

Содержание

Первичные требования

Перед прочтением данного раздела настоятельно рекомендуется ознакомится с основными элементами UnrealEd. Вы должны уметь оперировать простейшими понятиями, а также уметь конструировать более или менее простые карты. Если таковых знаний Вы не обнаружили у себя ни в левом, ни в правом полушариях мозга, ознакомьтесь с basic tutorials.

Вступление

Вообще сделать простенький мувер (mover) не сложно, например дверь или лифт, но на самом деле этим муверы не ограничиваются. Этот туториал (tutorial) расскажет Вам обо всем касающимся муверов. Каждое свойство (propertie) и каждый тип мувера (movertype) досконально будет рассмотрен.

Этот туториал оптимизирован под UnrealEd2.0, но если у Вас установлен UnrealEd1.0, не нужно впадать в панику, т.к. эти две версии практически ничем не отличаются. В тех местах, где встречаются отличия (меню, иконки, браузеры), присутствуют замечания. Но если Вы в танке, то пропатчте UT с помощью UT420 или выше - и Вы получите заветный UnrealEd2.0 8). Если Вы решились - то рекомендуется ставить патч UT436 минимум по причине добавления оным в едитор таких функций как просмотр в реальном времени "небесных" зон (skyzone), настройки текстур муверов и функции замены текстур (replace texture).

Этот туториал разбит на три части:

Часть I

Что такое мувер?

Мувер - это двигающийся браш (brush). Он может двигаться в любую точку и/или вращаться. Большинство муверов имеют несколько промежуточных положений - кадров (keys). Key0 - это начальное положение мувера до тех пор, пока он не будет возбужден - запущен. Остальные кадры-ключи - это положения, в которые будет перемещаться мувер при активизации. Он будет двигаться через все положения, пока не достигнет последнего кадра-ключа.

Вы легко можете отличить мувер в едиторе из-за его фиолетового цвета. В 3D виде (3D view), муверы видны через стены.

Муверы могут быть использованы для дверей, лифтов, поездов, лодок, кнопок, вращающихся метеоритов, в общем, для всего, что может двигаться.

В этот туториале когда говорится, что мувер "открыт" имеется в виду что он находится в последнем положении (кадре-ключе), а "закрыт" - соответственно при положении в кадре0 (key0). "Закрывающийся" мувер - это мувер двигающийся в направлении из последнего кадра-ключа к первому, "открывающийся" - наоборот, из первого кадра-ключа к последнему. Эта терминология родилась из-за применения муверов, в основном, в качестве дверей. Но в последующем, в туториале эта терминология сохранится, даже если мувер не будет являться дверью.

Создаем простенький лифт

Стандартный мувер в Unreal Engine - это мувер перемещающийся в новую позицию, когда Вы до него дотрагиваетесь, потом "ждет" несколько секунд и возвращается в исходное положение.

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

В комнате передвиньте активный браш (active brush) - он ярко красного цвета - в положение где Вы хотите расположить Ваш первый лифт и нажмите на кнопку , расположенную слева на панели инструментов (toolbar) под кнопками Добавить (Add), Вырезать (Subtract), Пересечение (Intersect), Вычетание (Deintersect)

В UnrealEd1.0, Вам нужно нажать на кнопку, выглядящую так:

По нажатию этой кнопки, Вы увидите, что активный браш стал фиолетовым. Это и есть мувер! Но этот мувер пока никак не отреагирует, если Вы на него наступите. Также этот мувер возможно не имеет ни текстур, ни формы, которую Вы задумали. В версии 436 едитора, Вы можете просмотреть и настроить текстуры мувера, нажав правой кнопкой мыши на нем и в появившемся меню выбрать Show Polys, но это не даст Вам возможности поменять форму мувера. Важно понимать, что мувер обязательно должен быть одним законченным брашем (а не состоять из группы брашей), именно поэтому Вы не сможете таким путем создать сложный мувер.

Вот почему возникает необходимость создания сперва шаблона (образца) будущего мувера - пользуясь обычными способами, а затем применить Пересечение (Intersect) для того чтобы активный браш принял форму задуманного Вами мувера (более детально следует ознакомиться с туториалом по созданию сложных брашей). После этого можете смело воспользоваться кнопкой Добавить Мувер (Add mover).

Удалите только что созданный мувер потому, что сейчас Вам предстоит создание более сложного. Сделайте сперва шаблон лифта. Обычно для этой цели, где-то вне уровня создается комната под подобную "мастерскую" или если Ваш уровень - открытое пространство, то шаблон можно смастерить прямо где-нибудь в небе. Используйте нормальные браши для построения шаблона (имеется в виду голубые и желтые). Примените текстуры, подгоните их, в общем сделайте лифт таким каким Вы хотите видеть его в уровне. Когда закончите, перестройте геометрию (Rebuild Geometry), затем обведите активным брашем Ваш шаблон. Убедитесь что будущий мувер полностью вписывается (вмещается) в активный браш и при этом активный браш не включает в себя ничего "лишнего".


Сейчас самое время нажать кнопку . Активный браш примет в точности форму вашего лифта:


Спокойно удаляем Ваш шаблон (Вы же не хотите, что бы он так и висел в небе).

Передвиньте активный браш в начальное положение лифта (в нижнее положение). Нажмите кнопку Add Mover . Сейчас мувер (лифт) в едиторе будет выглядеть как фиолетовые линии, но если Вы запустите Вашу карту, то лифт будет выглядеть в точности как созданный Вами шаблон.


На этом этапе Ваш лифт все же остается неподвижным. Для того чтобы заставить его работать, Вам необходимо указать ему как минимум еще один кадр-ключ. Для этого нажмите правой кнопкой мыши на мувере (фиолетовый браш), в появившемся меню зайдите в Movers и здесь выберите Key1:

Теперь просто переместите Ваш мувер в позицию верхнего положения лифта:

Браш мувера теперь имеет два положения: Key0(base) - нижнее положение лифта и Key1 - верхнее положение лифта. Если Вы теперь нажмете правой кнопкой мыши опять и выберете Key0(base), то мувер переместится в положение соответствующее этому кадру-ключу. Теперь Ваш лифт будет работать. Важно помнить, что исходным положением не всегда является Key0(base). На самом деле исходное положение лифта будет таким, каким оно было при перестройке уровня (Rebuild Level). Теперь, когда Вы наступите на лифт, он поднимется, и, спустя несколько секунд опустится в исходное положение.

Создание простенькой двери

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

Создание створчатой двери

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



Теперь Вы знаете как создавать лифты, раздвижные двери и вращающиеся двери. Также Вы можете этим же способом создать любые движущиеся объекты. Unreal Engine не видит никакой разницы между лифтами, дверями, поездами и пр. Движок просто-напросто перемещает объекты между различными кадрами-ключами (Keys).

Муверы с несколькими кадрами-ключами

Лифт и двери, созданные только что Вами, имеют всего 2 кадра-ключа: Key0(base) и Key1. Вы также можете создавать муверы с более чем 2-я кадрами-ключами - максимум их может быть 8. Если Вы создали такой мувер, к примеру, с 4 кадрами-ключами, он при активации будет двигаться от Key0 к Key1, затем к Key2 и, наконец, в Key3. В этом положении лифт остановится на несколько секунд и начнет движение назад - вернется в Key2, затем в Key1 и в базовое положение в Key0, где будет находиться пока не будет опять активирован. Для того чтобы "задать" муверу несколько кадров-ключей, действуйте как в примере с лифтом, но на этот раз задействуйте еще и Key2, Key3 и т.д. по своему усмотрению. Но это еще не все, после того как Вы задали все кадры-ключи, Вы должны также "сказать" муверу сколько кадров-ключей Вы будете использовать. Нажмите правой кнопкой мыши на мувере и в меню щелкните на Mover Properties. В появившемся окне разверните свойство Mover (нажмите + рядом) - появится список доступных настроек. Здесь в поле NumKeys введите количество кадров-ключей. То есть, если Вы использовали Key0, Key1, Key2 и Key3 то в поле нужно ввести число 4.

Свойство KeyNum действует также как и выбор кадра-ключа непосредственно на самом мувере. Когда Вы нажимаете правой кнопкой мыши на мувере, затем в меню заходите в Movers и здесь выбираете Key1 - тот же эффект будет и при выборе KeyNum равном 1 в Свойствах Мувера (Mover Properties).

В большинстве случаев Вы будете устанавливать KeyNum равным 0 перед сохранением уровня и непосредственно перед игрой, но можно и оставить KeyNum равным, например, 1. Это даст Вам дополнительный эффект: допустим Key1 - это верхнее положение лифта, а Key0 - нижнее его положение, также Вы оставили перед сохранением лифт в положении Key1 и запустили игру. Лифт при запуске уровня будет находиться в верхнем положении до тех пор, пока Вы его каким-либо образом не активируете (наступите на него), затем лифт "подождет" несколько секунд и опустится вниз. Теперь в нижнем положении он останется "навсегда" - т.е. до тех пор, пока он не будет активирован снова. Но с этих пор лифт будет нормально действовать: при активации - поднимется, задержится в верхнем положении на несколько секунд, и опустится где будет оставаться до следующей активации.

Перемещаем Мувер в едиторе

В едиторе Вы можете двигать практически все (браши, актеры, ...), даже муверы. Как Вы теперь знаете, муверы имеют несколько положений, соответствующий каждому кадру-ключу. Чтобы переместить конкретный кадр-ключ, Вы должны сперва выбрать этот кадр-ключ, а затем уже перемещать его куда Вам захочется. Если Вы двигаете кадры-ключи Key1, Key2, Key3, ..., Key7 - то перемещения будут относиться непосредственно к данному кадру-ключу. Это не относится к Key0(base) - при перемещении этого кадра-ключа все остальные кадры-ключи перемещаются тоже. Например, если Вы сделали поднимающийся лифт (вне зависимости, сколько он имеет кадров-ключей), и хотите его установить в каком-нибудь другом месте на уровне нет необходимости тягать все кадры-ключи, достаточно выбрать Key0(base) и переместить его - остальные автоматически "последуют" за ним.

Вы можете не только передвигать мувер, но также и вращать. Если Вы повернете Key0(base), то и остальные кадры-ключи также повернутся, но при этом они не переместятся. Это означает, что если у Вас дверь как эта (яркая дверь - это Key0(base), темная - Key1):

и Вы повернете Key0(base) на 90 градусов, это будет выглядеть так:

а не так как Вы ожидали:

Поэтому, если у Вас раздвижная дверь, и Вы хотите сделать еще одну такую же, но повернутую на 90 градусов, то после того как Вы скопировали (duplicate) дверь и повернули ее, Вам необходимо будет переместить все остальные кадры-ключи для корректной ее работы.

Основные свойства мувера

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

Чтобы перейти к свойствам мувера, нажмите правой кнопкой мыши на нем и щелкните на Mover Properties. В окне перейдите к пункту Mover.

Ниже перечислены основные свойства:

Звуки муверов

Теперь перейдем к пункту MoverSounds. Здесь Вы можете задавать звуки, которые будут использоваться мувером. В наличии имеются 5 полей соответственно отображающих разные действия мувера:

Для того чтобы выбрать звук, сперва откройте Браузер Звуков (SoundBrowser) - он находится в меню View, или нажмите кнопку на панели инструментов. Затем в SoundBrowser-е зайдите в меню File и щелкните на пункте Открыть (Open). Здесь перейдите в директорию Sounds (она расположена там, куда Вы инсталлировали Unreal Tournament). В Вашем распоряжении находятся два пака (packages) с хорошими звуками дверей и лифтов: DoorsAnc.uax и DoorsMod.uax. DoorsAnc.uax - в нем содержаться звуки старинных дверей (в основном деревянные и скрипучие), в то время как пак DoorsAnc.uax содержит более современные звуки. Выберете понравившийся Вам звук, перейдите в окно Mover Properties и здесь нажмите кнопку Использовать (Use) в нужном Вам поле для активации звука.

При выборе звуков следует помнить следующее:

Часть II

Вещи, которые неплохо бы знать

Многие люди интересуются подобными вещами но никогда не пробовали в действии:

Вращающиеся муверы

Нет никакой необходимости специального класса для вращающихся муверов. Можно заставить вращаться любой объект, декорацию, оружие, мувер и т.д., всего лишь задав соответствующую настройку.

Создайте мувер. Сейчас Вам не понадобиться указания никаких кадров-ключей - достаточно присутствия самого мувера. Откройте свойства мувера, кликнув правой кнопкой мыши на нем, и зайдите в MoverProperties. Здесь перейдите к пункту Movement, в котором есть свойство Rotation Rate. Rotation rate включает в себя три настройки: Pitch, Roll и Yaw. По умолчанию они установлены по нулям - поэтому мувер не вращается. Маленькие значения, такие как 1, 10, 100 заставит мувер вращаться очень медленно, и Вы вообще с трудом заметите какое-либо движение. Значение 1000 - уже более весомо (хотя все же достаточно медленно), ну а 2000-10000 самый раз для шустрого вращения. Естественно, Вы можете заставить мувер вращаться с такой скоростью, какой захотите, но при больших значениях, например 100000, не исключена возможность появления странных эффектов, особенно когда Вы находитесь непосредственно на мувере (стоите на нем).

Воспользуйтесь свойством Pitch для вращения вокруг оси x, Roll - оси y и Yaw - оси z. Все просто: если Вам необходимо вращающаяся платформа - измените значение Yaw, для колес машин же используйте Pitch или Roll.

Вообще у каждого мувера присутствует своя ось/точка вращения. Месторасположение этой оси указано красной точкой с крестиком. Именно вокруг этой точки и будет происходить вращение. Пример: цилиндр на первой картинке будет вращаться вокруг центра, в то время как другой - вокруг одной из своих сторон:

Для того чтобы передвинуть красную точку в другое положение, просто щелкните мышью на любой точке (vertex) браша мувера и красная точка сама туда переместится.

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

Еще одна важная деталь - это установить значение InitialState равным None, т.к. в противном случае кручение мувера будет прервано когда игрок дотронется до него. Эта настройка находится в MoverProperties, в пункте Objects.

Муверы с датчиком (Triggered Movers)

Все муверы которые Вы делали ранее активируются при прикосновении игроком. Но теперь Вы познакомитесь с новым способом активации муверов - датчики (triggers). Сперва следует сказать как создать такой датчик. Откройте Браузер Актеров (Actor Class Browser) - он находится в меню View или нажмите на панели задач кнопку . Здесь зайдите в раздел Triggers и выберете Trigger:

Датчик активируется, когда игрок попадает в радиус его действия. При этом датчиком возбуждается действие (event), активирующее мувер или что-нибудь еще. Устанавливать датчики следует в местах доступных игроку, для того, чтобы он смог активировать его.

Заставим датчик включать Ваш мувер: у датчика в поле Event укажите имя (Tag) мувера. Для этого откройте Настройки Датчика (TriggerProperties) - это делается с помощью нажатия правой кнопкой мыши на датчике. Здесь перейдите к разделу Events и в поле Event введите в точности имя (Tag) Вашего мувера, например Mover1. А затем в свойствах мувера (MoverProperties), который необходимо активировать датчиком, зайдите также в пункт Events, но здесь введите имя Mover1 в поле Tag. Если проследить логически за всеми манипуляциями получается, что действие датчика направлено на объект с именем Mover1 - а объект с этим именем как раз и является Вашим мувером.

При этом едитор автоматически проведет красную линию из датчика к муверу, указывая тем самым на их взаимосвязь:

Также Вам необходимо будет указать муверу, что он должен активироваться по датчику, а не при прикосновении игроком. Заходим в раздел Objects в окне MoverProperties и здесь воспользуемся свойством InitialState:

Для того чтобы заставить мувер работать согласовано с датчиком, Вам необходимо будет воспользоваться одним из вышеприведенных опций, например TriggerOpenTimed или TriggerToggle.

Есть также возможность указать радиус действия датчика: зайдем в TriggerProperties, раздел Collision:

Радиус действия датчика, на самом деле, представляет из себя цилиндр: используйте CollisionHeight для указания высоты цилиндра и CollisionRadius - непосредственно для радиуса цилиндра. Пока игрок находится любой точкой своего тела в этом цилиндре, датчик будет считаться активированным. Очень удобно посмотреть радиус действия в 2D View (в одном из трех окон: Top, Side или Front). Для этого нужно нажать правой кнопкой мыши на заголовке соответствующего окна, зайти в меню Actor и здесь поставить галочку на Radii View:

Вернемся к Свойствам Датчика (Trigger Properties), т.к. здесь есть еще несколько настроек, заслуживающих Вашего внимания. Развернем раздел Trigger:

Перечислим наиболее важные из опций:

Муверы и освещение

Муверы имеют несколько настроек, связанных с освещением. Их можно найти в пункте Mover окна Mover Properties.

Пример эффекта WorldRaytraceKey показан на скринах ниже. Мувером является лифт с двумя кадрами-ключами: Key0(base) - в нижнем положении и Key1 - в верхнем. Cледует помнить, что это сработает только при bDynamicLightMover равном false:


WorldRaytraceKey = 0


WorldRaytraceKey = 1

Вторая тень вычислена для лифта в верхнем положении. Вы также можете использовать это для изготовления искусственных теней.

Зацикленные муверы (Looping movers)

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

The DualDispatcherMethod (Thanks to Wanderer): необходимо иметь два диспетчера (dispatchers) и датчик. При активации датчика один диспатчер начинает "цепную реакцию", представляющую из себя бесконечное движение мувера между различными кадрами-ключами.

Итак, приступим. Сперва добавим в уровень обычный мувер с необходимым количеством кадров-ключей, перейдем в его свойства (Movie Properties). В пункте Objects изменим InitialState на TriggerToggle. Также в разделе Events дадаим ему имя (Tag), например, loopingmover. Теперь добавим два диспетчера (они находятся в Браузере Актеров (Actor Browsers), в разделе Triggers).

Лезем в свойства одного из диспетчеров, в раздел Events, находим поле Tag и вписываем сюда имя, например, Dispatcher1. В разделе dispatcher зайдем в настройку OutEvents. В поле [0] впишем имя (Tag) мувера, в данном случае loopingmover, а в поле [1] - вводим dispatcher2. Не забудьте в свойстве OutDelays в поле [1] указать время (в секундах), необходимое для полного открытия/закрытия. Узнать время не трудно: если MoveTime мувера равен 2, и у него 4 кадра-ключа, ему понадобится 6 секунд для открытия/закрытия, а не 8 секунд: 4 кадра-ключа подразумевают движение из Key0(base) в Key1, затем из Key1 в Key2, и наконец, из Key2 в Key3, т.е. три промежутка по 2 секунды. Итого 6 секунд.

Теперь то же самое проделаем и для второго диспетчера: имя (Tag) дадим ему dispatcher2, а OutEvent[1] - dispatcher1:

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

После установки датчика не забудьте в свойcтве Events, в поле Event указать либо Dispatcher1 либо dispatcher2 (в данном случае не имеет значения какой из них будет являться первым).

The LoopMover

Вообще в едиторе различают несколько видов муверов. Посмотреть типы можно нажав правой кнопкой мыши на кнопке Добавить Мувер (Add Mover). В развернувшемся списке Вы увидите все типы муверов. Самый верхний (Mover) используется по умолчанию. Теперь же выберем LoopMover:


Классы муверов

После непосредственного сконструирования самого мувера (ну и, естественно, нескольких кадров-ключей), стоит залезть в его опции (Mover Properties). Затем заходим в Objects, в пункт InitialState. Как Вы видите, здесь появилось новое свойство - LoopMove. Это единственное свойство заставляющее работать мувер бесконечно. Поэтому выберем его.

Единственный недостаток в том, что LoopMover не начнет движение сам. Его нужно активировать. Для этого добавьте где-нибудь датчик (Trigger) и в его свойствах в поле Event введите имя (Tag) Вашего LoopMover. Теперь при старте уровня, мувер начнет движение как только кто-то попадет в радиус действия датчика. Если же Вы покинете радиус действия, то и движение мувера прекратится в положении ближайшего кадра-ключа.

Если же Вы хотите, чтобы мувер продолжал свое движение вне зависимости от того находитесь ли Вы в радиусе действия датчика или нет, нужно позаботится о том чтобы датчик был активирован все время. Вам понадобится кто-то или что-то для активации датчика, но при этом им не должен являться игрок. Естественно это что-то должно находится все время в радиусе действия Вашего датчика. К счастью большинство pawns подходит для этой роли. Итак, выставляем опцию TriggerType в положение TT_PawnProximity. Идеальный pawn для таких вещей - это Налийский кролик (Nali Rabbit). Он находится в Браузере Актеров (Actor Class Browser) - смотри скрин внизу. Но перед тем как Вы добавите кролика, Вам понадобится комната размером, скажем, 256*256*256 за пределами Вашей карты. Сюда же воткнем датчик. В данном случае здесь никто не сможет пристрелить кролика, да и убежать ему будет некуда.

Скорее всего Вы подумаете, что нужно всего лишь закинуть этого кролика поближе к датчику и все будет ОК. Но спешу Вас огорчить - не все так просто. В едиторе есть баг - когда кто-то находится в радиусе действия датчика при старте уровня, датчик не активируется. Для реальной активации Вам придется именно "зайти" в радиус действия. Выход из этой ситуации - поместить кролика над датчиком, так чтобы при падении он попал в радиус его действия. После того как Вы добавили кролика в нужное место (над датчиком), нужно выставить его физику для падения. Сделаем это, открыв его свойства, пункт Movement. Здесь в списке Physics выберем PHYS_Falling:

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

Также Вы должны быть уверены, что кролик находится точно над пространством действия датчика (если помните - то это цилиндр) и что он не разобьется при падении. При использовании комнаты размером 256*256*256 поместите датчик ровно по центру, примерно на высоте 64 юнита. Теперь перейдите в его свойства, раздел Collision. Здесь установите CollisionHeight равный 64, а CollisionRadius сделайте 200. Теперь смело добавляйте кролика. Вы можете посмотреть как это выглядит на скрине ниже. Красный прямоугольник - не что иное, как радиус действия датчика (его видно, потому что установлена Radii View):

Ну и последняя вещь о которой стоит упомянуть - в свойствах мувера, в списке MoverEncroachType выберем ME_IgnoreWhenEncroach, в противном случае мувер остановиться навсегда при прикосновении к нему одним из игроков.

Если же Вы хотите избежать подобных проблем, Вы можете воспользоваться комбинацией двух вышеописанных методов: DualDispatcherMethod и LoopMover. В данном случае установите OutDelay[1] равным MoveTime Вашего мувера, вместо указания времени полного открытия/закрытия.

Теперь рассмотрим некоторые отличия этих двух методов. Основное отличие состоит в порядке движения между кадрами-ключами в случае если их больше чем 2. К примеру, возьмем мувер с тремя кадрами-ключами. Нормальный мувер будет двигаться так: из Key0(base) в Key1, из Key1 в Key2, после этого вернется в Key1 и, наконец, в Key0(base):

LoopMomer будет вести себя несколько иначе: из Key0(base) в Key1, потом в Key2, но после этого мувер кратчайшим путем вернется в Key0(base):

Поэтому в зависимости от Ваших потребностей используйте либо первый либо второй метод.

TriggerPound: этот метод использует специфическое значение InitialState вашего мувера: TriggerPound. То есть после изготовления мувера и нескольких кадров-ключей не забудьте установить это значение в InitialState. В принципе TriggerPound это то же самое что и InitialState равный LoopMove при использовании LoopMover, с той лишь разницей, что в данном случае мувер будет двигаться как в DualDispatcherMethod. Для активации мувера воспользуйтесь той же схемой с кроликом.

Преимущество этого метода состоит в том, что Вы можете регулировать время задержки мувера перед началом закрытия (последний кадр-ключ), а также время задержки перед открытием (исходное положение). Для этого перейдем в свойства мувера (Mover Properties), в раздел Mover. Для задержки перед открытием воспользуйтесь полем StayOpenTime, а перед закрытием - OtherTime.

Что-то типа вот этого:

Связанные муверы (AttachMovers)

Существует особый вид муверов - связанные муверы (AttachMover). Смысл их заключается в том, что они привязаны к другому муверу и в точности копируют их движения. На самом деле для тех же целей намного легче, да и надежней использовать нормальные муверы, если Вы хотите, чтобы объект двигался вместе с мувером.

Для начала создайте нормальный мувер, дайте ему имя (Tag), например, AttachMover. Теперь добавьте любой объект: оружие, декорацию, свет и т.д. в Ваш уровень. Откройте окно свойств объекта, и перейдите в пункт Movement. Здесь в поле AttachTag впишите имя (Tag) мувера, в данном случае AttachMover. После этого в разделе Advanced установите следующие значения: bMovable равный true, bNoDelete равный false и bStatic тоже в положение false:

Теперь "привязанный" объект будет в точности повторять движения мувера, не зависимо от каких-либо внешних помех - даже будет проходить сквозь стены.

Если Вы все же хотите воспользоваться классом AttachMover, то нажмите правой кнопкой мышки на иконке Add Mover и выберете его в списке. После этого откройте свойства связанного мувера (AttachMover Properties). Дайте ему имя связного :) (AttachTag). Теперь все объекты, имеющие такое же имя будут двигаться вместе в ним.

Получается, что единственная разница между использованием AttachMovers и обычного мувера лишь в том, что при использовании последнего Вы указываете одинаковое имя (Tag) в поле AttachTag объекта и в поле Tag самого мувера, а в другом случае наоборот: в поле AttachTag мувера и в поле Tag объекта.

Муверы, связанные между собой

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

Мувер В, в свою очередь можно спрятать где-то на карте, так что игроки будут видеть только мувер А!

Если Вы захотите чтобы мувер был привязан к нескольким муверам, необходимо будет создать цепочку: мувер А привязан к муверу В, а мувер В к муверу С и т.д.

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

Основное использование такой техники - это лифты с внутренними дверями. В этом случае двери будут опускаться и подниматься вместе с лифтом.

Кручение может не работать, хотя иногда встречаются рабочие.

Используя привязки муверов друг к другу Вы увидите, что это направление имеет огромный потенциал. С помощью привязки Вы сможете делать поразительные вещи, не прибегая к помощи скриптов!

События муверов

Ниже описано несколько полезных событий муверов.

Первый тип событий - это когда что-то или кто-то запускает мувер. В разделе Movers окна свойтсв (Mover Properties) есть две опции: BumpEvent и PlayerBumpEvent. BumpEvent - событие возникающее каждый раз при запуске мувера кем-либо (игроком, объектом и т.д.), в то время как событие PlayerBumpEvent возникает в следствие запуска только игроком.

Второй тип событий - те же что использовались для датчиков (Triggers). В окне свойств, выберем пункт Events. Когда Вы введете в поле Event имя события, оно будет вызвано при достижении мувером своего последнего кадра-ключа. С помощью этого Вы можете создать кнопочку, являющуюся мувером, которая заезжает в стену при нажатии, и как только кнопка достигнет своего последнего положения откроется дверь. В данном случае датчики не понадобятся.

При использовании некоторых типов муверов, таких как GradualMover и AssertMover, Вы можете указать различные события для каждого кадара-ключа. Это будет объяснено ниже.

Лифтовой мувер (ElevatorMover)

ElevatorMover, наверное, является самым продвинутым мувером, т.к. он предоставляет Вам возможность контролировать каждый кадр-ключ. Пример: если у Вас мувер с четырьмя кадрами-ключами, Вы можете поставить 4 лифтовых датчика (ElevatorTriggers) на уровне - один для Key0(base), второй для Key1, третий для Key2 и четвертый для Key3.

Чтобы добавить мувер этого класса просто нажмите правой кнопкой мыши на иконке AddMover и в списке выберете ElevatorMover. Организуйте для него 4 кадра-ключа.

Откроем свойства мувера (ElevatorMover) и в разделе Objects установим InitialState в положение ElevatorTriggerGradual. Затем в пункте Events дадим муверу имя (Tag), например, ElevatorMover.

Лифтовые муверы не работают с нормальными датчиками. Вам необходимо будет использовать специальный вид датчиков - лифтовые датчики (ElevatorTriggers). Ясное дело, что у таких датчиков есть свои, присущие только им, настройки. Кстати, ElevatorTrigger находятся в Браузере Актеров (Actor Class Browser) в разделе Triggers:

Добавьте 4 таких датчика (каждый для соответствующего кадра-ключа), и перейдите в их настройки. В разделе Events в поле Event введем ElevatorMover. Теперь Вы увидите красные линии, проведенные из датчиков к муверу:

Затем, выберете один из лифтовых датчиков (ElevatorTriggers), откройте окно свойств, пункт ElevatorTrigger:

Здесь находятся следующие настройки:

Установим свойство GotoKeyFrame для каждого датчика соответственно равным 0, 1, 2 и 3.

Если теперь запустить карту, и Вы активируете один из датчиков, мувер переместиться в положение кадра-ключа, номер которого Вы указали в опции GotoKeyFrame данного датчика. Не имеет значения, с какого кадра-ключа мувер начал движение - он всегда переместиться в нужное положение!

Этот тип мувера называется Лифтовой мувер, но, тем не менее, его можно использовать для других вещей. Для всего, что требует фиксации в разных кадрах-ключах, может быть использован этот класс муверов. Яркий пример этому - поезд, перемещающийся между различными станциями. Также, если Вы задумаете использовать мувер с двумя кадрами-ключами, но с отдельными датчиками для каждого положения - воспользуйтесь Лифтовым Мувером.

Что касается звуков: для Лифтовых Муверов (ElevatorMover) никогда не используйте зацикленные звуки - они останутся звучать вечно.

И еще одна вещь, вернее баг: если мувер был заблокирован при движении, он остановиться и не будет слушаться кнопок (датчиков). Единственный выход - установить опцию MoverEncroachType в положение ME_IgnoreWhenEncroach.

AssertMover

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

Сделать этот мувер просто: на кнопке Add Mover нажмите правый батон мыши и в списке выберете AssertMover. сделайте для него более 2 кадров-ключей, например 4. В его свойствах укажем InitialState равный AssertTriggerOpenTimed. И дадим ему имя (Tag) - например AssertMover. Затем добавим датчик с таким же именем в поле Event.

Откроем окно свойств мувера (AssertMover Properties), и воспользуемся настройками в разделе AssertMover:

GradualMover

Этот тип муверов по достижении каждого из своих кадров-ключей меняет свое имя (Tag). Поэтому в положении, соответствующем кадру-ключу 0 (Key0), мувер будет "слушаться" одного датчика, в другом положении (например, в Key1) - уже другого. Также у Вас есть возможность указать разные события для каждого кадра-ключа мувера. Добавим такой мувер и зайдем в его свойства (GradualMover Properties):

Зайдя в пункт InitialState в разделе Object свойств мувера, Вы заметите 3 новых значения для InitialState:

Группа возврата (ReturnGroup)

Группа возврата (ReturnGroup) - неизвестная большинству мапперов, но играющая очень важную роль для муверов, настройка. Используется для разбиения муверов с одинаковыми именами (Tags) на подгруппы.

Если у мувера при движении возникло препятствие, то в зависимости от настроек, мувер либо остановиться, либо вернется, либо проигнорирует препятствие, либо просто-напросто раздавит препятствие (игрока) - в данном случае не имеет значение какое поведение выбрано (см. настройку MoverEncroachType). Итак, допустим, у Вас имеется несколько муверов с одинаковыми именами (Tags), и один из них был каким то образом заблокирован при движении. В этом случае все муверы соответствующей группы либо остановятся, либо вернуться, либо.... Во избежании подобного поведения единственный выход распределить каждый мувер в отдельную группу возврата (ReturnGroup). Теперь все муверы одной группы (т.е. с одинаковыми Tags, активирующиеся одним общим датчиком, и.т.д) не будут при блокировке одного из них реагировать на поведение своего "брата".

Предупреждение: когда Вы добавляете мувер, вне зависимости от их количества, имя устанавливаемое по умолчанию будет Mover. Это означает, что все муверы будут иметь один и тот же Tag (ну если Вы, конечно, не поменяли имя вручную), и соответственно будут членами одной группы. Поэтому, если Вы очень удивлялись странному поведению, скажем, дверей при блокировке лифта на одном уровне, причина кроется именно в группе возврата.

Некоторые классы муверов, такие как GradualMover будут также останавливаться и возвращаться вместе, даже если у них разные имена (Tags). В данном случае Вам просто необходимо будет распределить их по разным группам возврата. Если Вы, к примеру, соорудили головоломку, используя GradualMover, то ее работа может не соответствовать задуманному Вами сценарию, из-за неадекватного поведения муверов. Здесь также выручит использование различных ReturnGroup для каждого мувера.

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

Еще некоторые свойства муверов

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

Часть III

Дверь, открывающаяся при нажатии кнопки

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

Для начала построим две комнаты и дверь, соединяющую их между собой. Установим InitialState двери в положение TriggerToggle или TriggerOpenTime, а имя дадим ей Door. Теперь добавим мувер в виде кнопки где-нибудь рядом с дверью. Кадр-ключ0 (Key0(base)) кнопки укажем снаружи стены, а Key1 - внутри стены ("утопим" чуть-чуть кнопку в стене). В поле Event введем Door. Здесь можно также воспользоваться BumpEvent вместо обычного Event - тогда событие возникнет при прикосновении к кнопке, а не по достижении ею последнего кадра-ключа. Обратите внимание на наличие красной линии проведенной из кнопки к двери.

Теперь сделаем такую же кнопку с другой стороны (для того чтобы можно было открыть дверь находясь и в смежной комнате) и произведем те же манипуляции со свойствами.

Это будет выглядеть примерно так:

Поезд с кнопкой

На поезде будет установлена одна кнопка при нажатии на которую поезд будет двигаться от одной станции к другой. На каждой станции тоже будет по кнопке для вызова поезда.

Сообразите огромную комнату и сделайте в ней подобие рельсов. Затем создайте мувер, выглядящий как поезд с кнопкой. Теперь сделайте так, чтобы он мог перемещаться (укажите ему кадры-ключи):

InitialState поезда установите в TriggerToggle, а имя муверу дайте Train. Добавьте датчик в упор к кнопке на поезде, и затем, зайдя в свойства датчика, введите в полях AttachTag и Event имя поезда, т.е. Train. Датчик теперь будет "привязан" к поезду и, соответственно, будет вместе с ним перемещаться. Иногда могут возникать всякого рода проблемы, особенно если указать датчику маленький радиус. Поэтому следует установить большой радиус. Если же Вы установите два фиксированных датчика на обоих концах пути (имеется в виду на одой и на другой станциях), то по прибытии туда поезда, он будет автоматически вызывать реактивацию датчика. Выходом является привязка датчика непосредственно к самому муверу поезда.

Теперь добавим две кнопки и два датчика на каждой из станций. В их свойствах в поле Event введите Train (поля AttachTag проигнорируйте).

Теперь эти кнопки будут вызывать мгновенно поезд на станцию, даже если он находится в движении. В мультиплеере это может нежелательно действовать на ЦНС игрока находящегося на поезде, в то время как два других тыкают одновременно кнопки на разных концах пути. Для избежания подобных пагубных влияний на аксоны и дендриты, воспользуйтесь Лифтовым мувером (ElevatorMover) для создания поезда, и установите на нем две кнопки. ElevatorMover не слушается датчиков во время движения. Единственный недостаток - Вы не сможете установить для мувера звук.

Пример карты, DM-Train.unr, Вы можете найти в архиве.

Покачивающаяся на волнах лодка

В реальном мире, лодка всегда слегка покачивается на волнах. По этой причине попробуем воспроизвести что-то подобное в Unreal Tournament.

Для этого понадобиться привязать мувер лодки или плота к другому муверу, совершающему волнообразные движения. Для движения непосредственно самой лодки, укажите ей кадры-ключи - базовый (Key0(base)) на одном берегу, другой (Key1) - на противоположной стороне.

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

Ниже по шагам описано как создать подобную лодку:

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

Укажите плоту другой кадр-ключ (Key1) на противоположной стороне бассейна. Теперь у Вас в наличии обычный плот, который может двигаться на другую сторону бассейна и обратно.

Теперь вырежьте комнату размером 256*256*256 где то за пределами Вашей карты и поместите на полу датчик. Убедитесь, что радиус действия датчика (CollisionRadius) больше чем комната, а высота действия датчика (CollisionHeight) достаточна для Налийского кролика (NaliRabbit).

Добавьте в эту комнату кролика - установите его над датчиком, а в свойствах установите настройку Physics в положение PHYS_Falling (подробнее см. главу Зацикленные муверы (Looping movers)).

Также, сюда воткните маленький мувер и укажите ему следующие настройки: InitialState сделайте TriggerPound, StayOpenTime и OtherTime равным 0.5, MoveTime равным 1. Кадр-ключ1 (Key1) сделаем несколько ниже исходного положения (Key0(base)), например, на 8 или 16 юнитов. Теперь, когда кролик попадет (здесь: упадет) в радиус действия датчика, маленький мувер придет в движение. Так как кролик сбежать никуда не может, то и движение будет бесконечно (для живодеров: можете открыть консоль и ввести "killall unreali.nalirabbit" - хороший был кролик).

В поле Event датчика введите Wiggle, затем это же имя дайте маленькому муверу (в поле Tag). Также введите такое же имя и в поле AttachTag Вашей лодки.

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

Пример карты, DM-Boat.unr, Вы можете найти в архиве.

Лифт каким мы его знаем

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

Для начала вырежьте четыре комнаты/этажа размером 256*1024*1024 (H*W*B соотвественно), оставив прослойку из 128 юнитов между каждой из них. Теперь сделайте лифтовую шахту на левой или правой стороне "офиса" на расстоянии примерно 32 юнитов. Самый подходящий размерчик для шахты 1408*256*256. Осталось вырезать 4 дырки на каждом этаже ведущие в шахту. Должно получиться что-то очень похожее на это:

Для последующих построек отведите себе "мастерскую" - комнату вне вашей карты размером 1024*1024*1024. Здесь Вам предстоит сконструировать мувер лифта. Сам лифт будет представлять из себя кубик размером 256*256*256 с вырезанным внутри него другим кубиком размером поменьше - 240*240*240. Поместим 4 кнопки на одну из стен и воспользуемся текстурами с нарисованными на них номерами (из пака Starship.utx) для их декорации. Не забудьте поставить галочку на опции Bright corners в свойствах этих текстур для избежания некоторых проблем с освещением. Теперь при помощи функции Пересечения (Intersect) создайте один цельный браш будущего мувера:

Переместите активный браш в форме лифта в его исходное положение - на первый этаж, нажмите добавить Лифтовой мувер (правой кнопкой на иконке AddMover, здесь в списке выберете ElevatorMover). Укажите лифту 4 кадра-ключа для каждого из этажей. На скрине показаны все кадры-ключи мувера:

Откройте свойства мувера (ElevatorMover Properties), в пункте Objects установите для InitialState значение ElevatorTriggerGradual. Имя (Tag) ему дайте ElevatorMover.

Теперь установите 4 лифтовых датчика (ElevatorTrigger) внутри лифта для каждой кнопки. В их свойствах найдите поле AttachTag и впишите туда ElevatorMover, теперь датчики будут перемещаться вместе с лифтом. Радиус действия (CollisionRadius) сделайте им маленький, например 25, так Вы не сможете "нажимать" две кнопки одновременно. Воспользуйтесь Radii View для более точной настройки радиуса. Также у всех датчиков в поле Event введите ElevatorMover, а у каждого датчика в отдельности укажите GotoKeyFrame соответственно равным 0, 1, 2 и 3.



Добавьте кнопку на каждом этаже рядом с выходом в шахту. Вы можете скопировать (duplicate) все 4 лифтовых датчика, и поместить их на свои места рядом с кнопками (смотрите не перепутайте какой датчик за какой этаж отвечает). Почему легче скопировать - Вам тогда не придется лазить по их свойствам - лень Великая штука 8). Для избежании путаницы поместите датчик с GotoKeyFrame равным 0 на самый нижний этаж и т.д. Последняя вещь - лезем в их свойства (эх, все-таки пришлось) и очищаем поля AttachTag - этим датчикам нет надобности кататься.

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

Осуществить это можно только так: сделать двери тоже Лифтовым Мувером (ElevatorMover), чтобы они могли кататься вместе с лифтом, а для открытия/закрытия воспользоваться двумя отдельными муверами к которым и будут привязаны створки двери.

Создайте браш двери - в этом примере сделаны маленькие окошечки в створках, и поместите его в положение показанное на скрине ниже. Затем добавьте его как Лифтовой Мувер. Теперь добавьте точно такой же, но с другой стороны - это же двухстворчатая дверь. Обеим дверцам укажите такие же кадры-ключи что и у кабины лифта, а InitialState установите ElevatorTriggerGradual. Также не забудьте дать обеим створкам одно и то же имя (Tag): idoors.

Скопируйте (duplicate) ВСЕ лифтовые датчики, и поместите их ТОЧНО в то место, где находятся старые, в поле Event всех датчиков укажите событие idoors (самый быстрый способ это сделать - нажмите правой кнопкой мыши на одном из лифтовых датчиков, в меню выберете select all ElevatorTriggers, при этом все датчики окрасятся в зеленый цвет. Теперь нажмите опять правой кнопкой мыши на любом из них и щелкните на Скопировать (Duplicate). После этого все вновь появившиеся датчики тоже будут отмечены (selected) - что Вам наруку. Откройте свойства сразу всех датчиков и перейдите к полю Event. Здесь впишите idoors. Затем осталось только переместить их в нужное положение. Это сделать не сложно, т.к. при движении одного из них , остальные также будут перемещаться). Этим самым Вы добьетесь того, что при "нажатии" кнопки в лифте или вне его, Вы на самом деле будете активировать два разных датчика: один отвечает за перемещение лифтовой кабины, другой - за перемещение обеих створок раздвижной двери. Так как активация происходит одновременно, никакие проблемы с синхронизацией движения мучить Вас не будут.

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

Key1 укажите для них такой:

Затем верните их в положение Key0(base). Одной створке дайте имя idoor1, другой - idoor2. InitialState укажите им TriggerControl. Теперь установите два датчика место, показанное на скрине:

Таким образом сделайте 8 подобных датчиков - по 2 на каждом из этажей. При этом одному из них в поле Event укажите idoor1, а другому - idoor2. И так на каждом этаже.

Теперь выберете одну створку двери внутри лифта, зайдите в свойства и в поле AttachTag введите имя соответствующей створки вне карты: либо idoor1, либо idoor2. То же самое проделайте для всех створок на всех этажах.

Внешние двери - с ними попроще. Добавьте их на каждом этаже. Всего для них будет использовано 8 муверов: по 2 на каждом этаже, т.к. они тоже двухстворчатые. Нижним створкам дайте имена, например, odoor1. На втором этаже - имена будут odoor2 и т.д. Также всем им установите в InitialState значение TriggerControl. Затем добавьте по одному датчику на каждом этаже - на том же месте где Вы установили датчики для внутренних дверей. И последнее: укажите всем датчикам соответствующий Event: датчику на нижнем этаже впишите odoor1, на втором - odoor2 и т.д.

Теперь Ваша карта будет выглядеть примерно так:

Если все сделано верно, то на Вашей уровне будет:

И все это только для одного "офисного" лифта :(

Перестройте карту (rebuild), сохраните, перекреститесь и нажмите Ctrl+P.

Пример карты, DM-Elevator.unr, Вы можете найти в архиве.

Автор

По словам автора этот туториал будет обновляться.

Если у Вас возникли какие либо идеи, предложения, вопросы или же Вы обнаружили неточности и ошибки, автор будет рад Вашим письмам (на английском ленгве of course).

© 2000-2002 Lode Vandevenne
Перевод сделан 32_Pistoleta с разрешения автора.

Хостинг от uCoz