RSS
Меню сайта

Категории каталога
Doom3 [11]
Статьи о разработке карт к Doom3
Общее [7]
Статьи про общие моменты маппинга

Наш опрос
Навигация в "Файлах"
Всего ответов: 21

Copyright C4TNT© 2008

Главная » Статьи » Маппинг » Doom3

Скриптуем #3

Итак, начнём же с конца!!!.


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

Для этого достаточно вспомнить, что результатом сравнений в С и подобных ему языках является число. А именно - 0 если сравнение не выполняется и не ноль в остальных случаях.
Поэтому можно переписать часть кода так:

$func_door_1.lock (mon.getHealth() > 50);


Привыкайте к таким манёврам, они могут встречаться в скриптах довольно часто.

Итак, тайна раскрыта, что дальше...

А дальше будем подробно разбираться, как взаимодействовать с объектами карты и попутно разберёмся с while и for. Фраза о том, что карта состоит из брашей и сущностей (entities), у вас уже, надеюсь, не вызывает священного трепета. Поэтому отталкиваться будем от неё. А именно - объекты и переменные в скриптах (любые) имеют много общего с entity на карте. Они могут меняться в процессе игры, в отличае от статической части кода и брашей на карте. И по этой самой причине любой entity на карте представлен в скрипте каким-то своим объектом. Какие именно возможности есть у объекта-entity, описано в game.dll, в которую мы лезть не будем (до поры до времени). Если у вас ещё нет doom3 SDK - им всегда можно обзавестись на официальном сайте или здесь в каталоге файлов. Лучше всего это сделать, он ещё понадобится. Ну ладно...


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

Итак... в скриптах есть возможность получить любой объект карты по имени, но куда его девать после этого? Для объектов есть специальный тип переменных: entity - да,именно так он и называется. Ну, попробуем:

void test2
{
entity testentity;
testentity = ???; //Ну да, я же совсем забыл...
}

Все способы получения объекта с карты:

  • По имени (имя точно известно и не меняется): $имя_объекта , например $door_of_the_hell
  • По имени (имя меняется при выполнении скрипта) sys.getEntity( string name ) - вместо string name подставляйте вашу переменную с названием объекта. Название можно извлечь, например, из ключей объекта. Плюс этого способа ещё и в том, что при отсутствии объекта на карте (Ну, выкинули ненароком...) не возникает ошибки сценария.
  • Через trace - это тема отдельного особого разговора.
  • От других функций - такие функции есть у монстров в основном. Тоже особая тема.
Итак, второй заход:

void evil_trigger
{
entity testentity;
testentity = sys.getEntity("evil_light_1");
}

Маленькое лирическое отступление: если вы хотите испытывать все последующие примеры - вам понадобится карта, состоящая из одной комнаты, моделек лампочек (отдельно), fx-ов с искрами и небольших лайтов около каждой лампочек и и одного общего лайта для всей комнаты. Названия, соответственно, fx_1,light_1,fx_2,light_2 и дальше в том же духе. Для общего лайта название global_light_1. В дальнейшем предполагается, что скрипт написан для этой карты.

Итак, хочу предложить вашему вниманию следующую задачу: есть комната с лампочками. По сигналу с триггера нужно уничтожить по очереди все лампочки. Естественно, после этого должно стать темно.

Взрываем лампочку.


Для начала нужно научиться взрывать одиночную лампочку, массовостью займёмся позже.
Итак, получаем entity-объект для лампочки (можете этот приём уже запоминать, он очень популярен)

void evil_trigger
{
entity lamp;
entity lampfx;

lamp = sys.getEntity("light_1");
lampfx = sys.getEntity("fx_1");

??? Тут должен быть БУМ...

}

Займёмся БУМом. Для создания эффекта нужно, чтобы сработал fx, а скрипт под шумок выкрутит лампочку. У всех объектов есть метод trigger(); (метод - специальная функция, принадлежащая объекту. Обычно позволяет проделывать с объектом разные операции) Этот метод делает с объектом то-же, что и триггеры на карте. То есть двери открываются, монстры идут в атаку, спикеры пищат и так далее. Поскольку fx отлично работает от обычных триггеров, к нему вполне пойдёт и этот метод. Ну а лампочку(light) можно просто удалить, пока летят искры. Для удаления есть метод remove();

void delight1()
{
entity lamp;
entity lampfx;

lamp = sys.getEntity("light_1");
lampfx = sys.getEntity("fx_1");

sys.trigger(lampfx);
sys.wait(0.25);
lamp.remove();
}

Но в этом варианте лампочки гаснут слишком резко. Попробуем сделать плавное гашение лампочек. Нам хронически везёт, поскольку у лампочек есть метод fadeOutLight( float time ), который их плавно гасит (аналог lightramp из Quake2)

Получаем на выходе:
void delight1()
{
entity lamp;
entity lampfx;

lamp = sys.getEntity("light_1");
lampfx = sys.getEntity("fx_1");

sys.trigger(lampfx);
lamp.fadeOutLight(1);
}

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

Ну а теперь будем взрывать лампочки по кругу!


а заодно разберёмся с оператором for.

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

void delight1()
{
entity lamp;
entity lampfx;
float i;

i=1;
lamp = sys.getEntity("light_"+i);
lampfx = sys.getEntity("fx_"+i);

sys.trigger(lampfx);
lamp.fadeOutLight(1);
}

Этот скрипт делает то же самое, но теперь номер взрываемой лампочки находится в переменной i. Можете попробовать поменять его на 2, в результате лопнет вторая лампочка вместо первой. Мы уже ближе к цели, но нужно взорвать всё по очереди, а не только какую-то одну. Вот как раз таким светлым целям и служит for. Выглядит он так:

for (код1;условие;код2)
{
код3
}

что же это за ужас??? Вспоминаем, что вместо слова "код" вставляется нужный вам текст скрипта, а вместо условия - собственно какое-то условие. А выполняется эта штуковина в таком порядке: сначала выполняется код1, причём однократно, после этого выполняется код3, после этого проверяется условие и если оно верно, то выполняется код2, а за ним - снова  код3, проверка условия и так далее. Если же (а точнее - когда) условие нарушится - этот блок завершает выполнение и скрипт выполняется дальше обычным образом. Вот такой пример:

for (i=0;i<5;i++)
{
  your script;
}

и ход его "мысли":
1. i=0
2. your script;
3. i<5?   (i=0)
4. i++
5. your script;
6. i<5?   (i=1)
7. i++
8. your script;
9. i<5?   (i=2)
10. i++
11. your script;
12. i<5?   (i=3)
13. i++
14. your script;
15. i<5?   (i=4)
16. i++
17. your script;
18. i<5?   (i=5)

Заметьте, что при выполнении участка your script переменная i постоянно увеличивается. А это значит, что если внутрь вставить скрипт для уничтожения лампочек - все лампочки будут поочерёдно взорваны. Получаем нечто такое (у меня на карте восемь лампочек, поэтому i < 9, а у вас?):

void delight1()
{
entity lamp;
entity lampfx;
float i;

for (i=1;i<9;i++)
{
lamp = sys.getEntity("light_"+i);
lampfx = sys.getEntity("fx_"+i);

sys.trigger(lampfx);
lamp.fadeOutLight(1);
}
}

Ну что же, скрипт честно сработал, но шампанское пить ещё рано. А именно - все лампочки жахнули разом. Но это же совсем не производит атмосферы и не вызывает в игроке вселенского ужаса. Непорядок! А раз непорядок, значит надо устранять. Вставим внутрь скрипта sys.wait(1); , чтобы после каждого взрыва скрипт некоторое время ждал. Естественно, добавлять нужно после кода взрыва.

void delight1()
{
entity lamp;
entity lampfx;
float i;

for (i=1;i<9;i++)
{
lamp = sys.getEntity("light_"+i);
lampfx = sys.getEntity("fx_"+i);

sys.trigger(lampfx);
lamp.fadeOutLight(1);
sys.wait(1);
}
}

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

Тестовая карта всегда есть здесь: http://c4tnt.ucoz.ru/testarea/scri1.zip

Категория: Doom3 | Добавил: c4tnt (12.11.2008)
Просмотров: 1137 | Комментарии: 3 | Рейтинг: 0.0/0
Всего комментариев: 3
1 Archi  
1
Вот это я понимаю! Хорошо!

2 c4tnt  
1
Нифига, мы ещё даже на взлётную полосу не вырулили tongue

3 Archi  
1
Значица это хорошее начало!

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Вход:

Поиск

Ссылки


Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0


Работаем на керосине