Итак, начнём же с конца!!!.
То есть с того, как избавиться от лишнего 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
|