Урок 6 осветительная лампа часть 2
На прошлом уроке мы разобрали скрипт осветительной лампы. Она включается и выключается по щелчку мыши.
Создадим новый скрипт, приведем его в такое состояние:default
{
state_entry()
{
}
touch_start(integer total_number)
{
}
}
Но мы не можем при этом, пользуясь лампой, менять настройки света и сам цвет освещения… Давайте попробуем это реализовать. Для этого мы воспользуемся так называемым МЕНЮ, через которое мы, и другие пользователи этой лампы получат возможность настраивать параметры работы нашей осветительной лампы.
МЕНЮ, которым мы воспользуемся для выбора параметров работы лампы технически представляет собой ДИАЛОГОВОЕ ОКНО, которое получает пользователь. Оно появляется в правом верхнем углу экрана.
Компоненты задействованные в создании меню:1. Сообщение появиться в диалоговом окне (максимальная длинна сообщения может быть 512 символов)
2. Список пунктов меню
3. Канал связи, по которому будут передаваться данные выбора меню
4. Функция llDetectedKey() с помощью которой мы определим UUID пользователя, вызвавшего данное меню. Для того чтобы меню появилось не у всех людей в радиусе 10 метров, а только у вызвавшего его человека.
5. llDialog() — само диалоговое окно меню
6. llListen() — функция, которое запускает прослушивание канала с определенным номером. Если в этот канал поступит сообщение, она будет реагировать.
7. llListenRemove() — удалить прослушивание канала (Незачем все время слушать канал, это создает дополнительную нагрузку от скрипта)
8. Таймер — если пользователь не сделал выбор в появившемся меню, оно через некоторое время пропадет.
Список вариантов:
Кнопка «Игнорировать» автоматически появляется в нижнем правом углу меню.
Диалоговое окно может представить максимум 12 кнопок для пользователя одновременно.
Создадим список, в котором перечислим название кнопок меню, он будет глобальным:
list main_menu;//Объявляем список, в котором будут содержаться названия кнопок меню
default
{
state_entry()
{
main_menu=[«ВКЛЮЧИТЬ», «ВЫКЛЮЧИТЬ», «СБРОС», «КРАСНЫЙ+», «ЗЕЛЕНЫЙ+»,«СИНИЙ+», «КРАСНЫЙ-», «ЗЕЛЕНЫЙ-»,«СИНИЙ-», «ЯРКОСТЬ+» , «ЯРКОСТЬ-»];
}
touch_start(integer total_number)
{
}
}
Теперь добавим канал коммуникации, по которому будет осуществляться обмен данными между меню и пользователем.
list main_menu;//Объявляем список, в котором будут содержаться названия кнопок меню
integer channel_dialog;//Объявляем канал коммуникации
default
{
state_entry()
{
main_menu=[«ВКЛЮЧИТЬ», «ВЫКЛЮЧИТЬ», «СБРОС», «КРАСНЫЙ+», «ЗЕЛЕНЫЙ+»,«СИНИЙ+», «КРАСНЫЙ-», «ЗЕЛЕНЫЙ-»,«СИНИЙ-», «ЯРКОСТЬ+» , «ЯРКОСТЬ-»];
channel_dialog = -1 - (integer)(«0x» + llGetSubString( (string) llGetKey(), -7, -1) ); //Номер канала генерируется из последних 7 цифр UUID объекта. Это нужно для того, чтобы каналы не пересекались например в том случае, если в комнате будут стоять 2 такие лампы. Уникальный номер канала для каждой лампы обеспечит нормальную работу. Если бы номера каналов были одинаковыми — при настройке первой лампы на них реагировала бы и вторая, такая же лампа, стоящая рядом.
}
touch_start(integer total_number)
{
}
}
Добавим переменную ключа (key), которая будет определять UUID пользователя, взаимодействующего с настройками лампы. И определим этот UUID по нажатию пользователем на лампу.
list main_menu;//Объявляем список, в котором будут содержаться названия кнопок меню
integer channel_dialog;//Объявляем канал коммуникации
key Toucher_ID;//Тут будет храниться UUID пользователя, который хочет настроить работу осветительной лампы.
default
{
state_entry()
{
main_menu=[«ВКЛЮЧИТЬ», «ВЫКЛЮЧИТЬ», «СБРОС», «КРАСНЫЙ+», «ЗЕЛЕНЫЙ+»,«СИНИЙ+», «КРАСНЫЙ-», «ЗЕЛЕНЫЙ-»,«СИНИЙ-», «ЯРКОСТЬ+» , «ЯРКОСТЬ-»];
channel_dialog = -1 - (integer)(«0x» + llGetSubString( (string) llGetKey(), -7, -1) );
}
touch_start(integer total_number)
{
Toucher_ID = llDetectedKey();//Заносит в переменную UUID пользователя, который вызвал меню
}
}
Теперь попробуем вызвать наше диалоговое окно для пользователя, с помощью функции:
llDialog( key avatar, string message, list buttons, integer channel );key avatar — UUID аватара, которому прийдет диалоговое окно
string message — строка сообщения в меню
list buttons — список названий кнопок, на основе которого меню сформирует кнопки
integer channel — номер канала, в которое меню выдаст сообщение при нажатии на кнопку
Да, еще создадим строку message, в нее поместим сообщение, которое будет выводить наше меню.
list main_menu;//Объявляем список, в котором будут содержаться названия кнопок меню
integer channel_dialog;//Объявляем канал коммуникации
key Toucher_ID;//Тут будет храниться UUID пользователя, который хочет настроить работу осветительной лампы.
string message;
default
{
state_entry()
{
message = «ГЛАВНОЕ МЕНЮ»;
main_menu=[«ВКЛЮЧИТЬ», «ВЫКЛЮЧИТЬ», «СБРОС», «КРАСНЫЙ+», «ЗЕЛЕНЫЙ+»,«СИНИЙ+», «КРАСНЫЙ-», «ЗЕЛЕНЫЙ-»,«СИНИЙ-», «ЯРКОСТЬ+» , «ЯРКОСТЬ-»];
channel_dialog = -1 - (integer)(«0x» + llGetSubString( (string) llGetKey(), -7, -1) );
}
touch_start(integer total_number)
{
Toucher_ID = llDetectedKey();//Заносит в переменную UUID пользователя, который вызвал меню
llDialog(Toucher_ID, message, main_menu, channel_dialog);
}
}
Попробуем теперь щелкнуть по нашей лампе. Появляется меню, в котором есть все нами предусмотренные кнопки. При нажатии на каждую кнопу, меню посылает сообщение по установленному нами каналу. Это можно легко проверить, давайте временно установим канал 0, для того, чтобы наше меню отправляло сообщение выбора кнопки в общий чат. Мы сможем увидеть наглядно принцип работы меню. Для этого комментируем строку: channel_dialog, в событии state_entry и ниже (следующий строкой), в том-же событии пишем:
channel_dialog = 0;
Теперь при нажатии на кнопку меню, в общем чате мы видим посылаемые сообщения, которые соответствуют нажатой кнопке. Обратите внимание, что сообщения посылаем мы сами :) т.е. данное меню просто помогает нам (делает удобным) послать нужное сообщение по каналу. Не более, не менее. Все очень просто. Если мы оставим 0 канал, то мы можем заместо того чтобы нажать кнопку меню например «ВКЛЮЧИТЬ», просто написать это в чат. Это будет РАВНОЗНАЧНО. Но нажать кнопку конечно быстрее и удобнее, к тому-же, мы будем использовать другой номер канала, не 0, чтобы не спамить этими (управляющими) сообщениями в общий чат.
Ну с этим вроде разобрались, едем дальше… Да, кстати, давайте вернем все на место, удалим строку channel_dialog = 0; и раскомментируем строку channel_dialog = -1 - (integer)(«0x» + llGetSubString( (string) llGetKey(), -7, -1) );, которую мы до этого комментировали.
Теперь нам нужно сделать так, чтобы это меню, нашим скриптом (прослушивалось), т.е. скрипт мог понять, когда мы нажали на кнопку, и на какую кнопку мы нажали, и выполнить в связи с этим соответствующие действия. Для этого нам нужно постоянно слушать канал, точнее не совсем постоянно, а тока тогда, когда мы нажимаем на лампу, и наше меню появляется на экране. Тут мы воспользуемся функцией:
Function: integer llListen( integer channel, string name, key id, string msg );Обратите внимание, функция возвращает дескриптор в виде целого числа.
integer llListen — ДЕСКРИПТОР
Дескриптор это говоря простым языком, указатель на сам процесс прослушивания канала, который запускает эта функция. С помощью этого дескриптора (указателя), мы, уже после запуска процесса прослушивания канала, можем обратиться к этому процессу и отключить его. И мы это естественно будем делать для того, чтобы наш скрипт работал экономично расходуя предоставляемые сервером ресурсы.
integer channel — номер канала, который будет прослушивать запускаемый процесс
string name — ФИЛЬТР, указывается имя (ник) аватара, или название объекта, который будет прослушивать запускаемый процесс. т.е. если указан ваш ник, тогда никто кроме вас не сможет управлять лампой. Сообщения от другого пользователя, который будет пользоваться меню, конечно будут приходить в канал, и процесс прослушивания их естественно будет (видеть), но при этом никак не будет на них реагировать. Этот фильтр не будет установлен, если просто указать пустую строку "".
key id — ФИЛЬТР, указывается UUID аватара, группы или объекта, который будет прослушивать запускаемый процесс. т.е. если указан например UUID вашей группы, тогда никто кроме членов вашей группы не сможет управлять лампой. Этот фильтр не будет установлен, если просто указать константу NULL_KEY .
string msg — ФИЛЬТР, указывается конкретного сообщения. Этот фильтр не будет установлен, если просто указать пустую строку "".
list main_menu;//Объявляем список, в котором будут содержаться названия кнопок меню
integer channel_dialog;//Объявляем канал коммуникации
key Toucher_ID;//Тут будет храниться UUID пользователя, который хочет настроить работу осветительной лампы.
string message;
integer Listen_Id; //Создаем переменную, в которой будет храниться дескриптор.
default
{
state_entry()
{
message = «ГЛАВНОЕ МЕНЮ»;
main_menu=[«ВКЛЮЧИТЬ», «ВЫКЛЮЧИТЬ», «СБРОС», «КРАСНЫЙ+», «ЗЕЛЕНЫЙ+»,«СИНИЙ+», «КРАСНЫЙ-», «ЗЕЛЕНЫЙ-»,«СИНИЙ-», «ЯРКОСТЬ+» , «ЯРКОСТЬ-»];
channel_dialog = -1 - (integer)(«0x» + llGetSubString( (string) llGetKey(), -7, -1) );
}
touch_start(integer total_number)
{
Toucher_ID = llDetectedKey();//Заносит в переменную UUID пользователя, который вызвал меню
llDialog(Toucher_ID, message, main_menu, channel_dialog);
Listen_Id = llListen(channel_dialog, "", Toucher_ID, "");//Запускаем процесс прослушивания канала
}
}
Теперь, после того, как мы запустили процесс прослушивания, мы можем воспользоваться событием listen, которое будет срабатывать каждый раз, когда какое либо сообщение будет отправлено в установленный нами канал.
Event: listen( integer channel, string name, key id, string message ){; }integer channel — возвращает номер канала, на котором появилось сообщение
string name — возвращает имя аватара или название объекта, который отправил сообщение
key id — возврящает UUID аватара, группы или объекта, от которого пришло сообщение
string message — возвращает само сообщение
Добавим это событие, и установим в нем условия, при которых будут происходить действия с нашей лампой (реакции на нажатие кнопок меню)
list main_menu;//Объявляем список, в котором будут содержаться названия кнопок меню
integer channel_dialog;//Объявляем канал коммуникации
key Toucher_ID;//Тут будет храниться UUID пользователя, который хочет настроить работу осветительной лампы.
string message;
integer Listen_Id; //Создаем переменную, в которой будет храниться дескриптор.
default
{
state_entry()
{
message = «ГЛАВНОЕ МЕНЮ»;
main_menu=[«ВКЛЮЧИТЬ», «ВЫКЛЮЧИТЬ», «СБРОС», «КРАСНЫЙ+», «ЗЕЛЕНЫЙ+»,«СИНИЙ+», «КРАСНЫЙ-», «ЗЕЛЕНЫЙ-»,«СИНИЙ-», «ЯРКОСТЬ+» , «ЯРКОСТЬ-»];
channel_dialog = -1 - (integer)(«0x» + llGetSubString( (string) llGetKey(), -7, -1) );
}
touch_start(integer total_number)
{
Toucher_ID = llDetectedKey();//Заносит в переменную UUID пользователя, который вызвал меню
llDialog(Toucher_ID, message, main_menu, channel_dialog);
Listen_Id = llListen(channel_dialog, "", Toucher_ID, "");//Запускаем процесс прослушивания канала
}
listen(integer channel, string name, key id, string message)
{
if (message == «ВКЛЮЧИТЬ»)
{
}
else if (message == «ВЫКЛЮЧИТЬ»)
{
}
}
}
Мы добавим пока обработку только двух команд, «ВКЛЮЧИТЬ» и «ВЫКЛЮЧИТЬ»
Осталось немного. Добавим функцию, которая будет удалять процесс прослушивания сразу после того, как вы сделаете выбор в меню.
llListenRemove(listen_Id);
Где listenHandle — дескриптор нашего процесса (указатель на процесс)
Также добавим туда функции, которые будут включать свет и освещение, и соответственно выключать (мы работали с ними в первой части нашего урока).
Для включения:
llSetPrimitiveParams([PRIM_FULLBRIGHT, ALL_SIDES, TRUE, PRIM_POINT_LIGHT, TRUE, <1.0,1.0,1.0>, 1.0, 10.0, 0.6]);
Для выключения:
llSetPrimitiveParams([PRIM_FULLBRIGHT, ALL_SIDES, FALSE, PRIM_POINT_LIGHT, FALSE, <1.0,1.0,1.0>, 1.0, 10.0, 0.6]);
И еще добавим таймер, для того, чтобы наше меню выключалось через определенное время само, если за это время пользователь не сделал выбор. Главная задача такого таймера, чтобы остановить процесс прослушивания. Представьте себе ситуацию, когда пользователь нажал на лампу, у него появилось меню, и наш юзер после этого нажал на телепорт в другую локацию (к примеру). Или если пользователь нажимает кнопку меню «ИГНОРИРОВАТЬ»… В этом случае, даже если он потом закроет это меню у себя на экране, скрипт не получит подтверждение выбора, т.к. попросту не услышит, что был сделан выбор. И процесс прослушивания не будет остановлен. А мы подстрахуемся :)
Для этого используем таймер.
Function: llSetTimerEvent( float sec );float sec — количество секунд, в которое мы устанавливаем таймер.
Таймер начинает отсчитывать время назад (как таймер)
После установки таймера, мы получаем возможность использовать событие
Event: timer( ){; }Которое сработает тогда, когда время таймера станет 0 секунд.
Итак:
list main_menu;//Объявляем список, в котором будут содержаться названия кнопок меню
integer channel_dialog;//Объявляем канал коммуникации
key Toucher_ID;//Тут будет храниться UUID пользователя, который хочет настроить работу осветительной лампы.
string message;
integer Listen_Id; //Создаем переменную, в которой будет храниться дескриптор.
default
{
state_entry()
{
message = «ГЛАВНОЕ МЕНЮ»;
main_menu=[«ВКЛЮЧИТЬ», «ВЫКЛЮЧИТЬ», «СБРОС», «КРАСНЫЙ+», «ЗЕЛЕНЫЙ+»,«СИНИЙ+», «КРАСНЫЙ-», «ЗЕЛЕНЫЙ-»,«СИНИЙ-», «ЯРКОСТЬ+» , «ЯРКОСТЬ-»];
channel_dialog = -1 - (integer)(«0x» + llGetSubString( (string) llGetKey(), -7, -1) );
}
touch_start(integer total_number)
{
Toucher_ID = llDetectedKey();//Заносит в переменную UUID пользователя, который вызвал меню
llListenRemove(Listen_Id);//Удаляем процесс прослушивания
llDialog(Toucher_ID, message, main_menu, channel_dialog);
Listen_Id = llListen(channel_dialog, "", Toucher_ID, "");//Запускаем процесс прослушивания канала
llSetTimerEvent(10.0);//Устанавливаем таймер на 10 секунд
}
listen(integer channel, string name, key id, string message)
{
if (message == «ВКЛЮЧИТЬ»)
{
llSetPrimitiveParams([PRIM_FULLBRIGHT, ALL_SIDES, TRUE,PRIM_POINT_LIGHT, TRUE, <1.0,1.0,1.0>, 1.0, 10.0, 0.6]);
}
else if (message == «ВЫКЛЮЧИТЬ»)
{
llSetPrimitiveParams([PRIM_FULLBRIGHT, ALL_SIDES, FALSE, PRIM_POINT_LIGHT, FALSE, <1.0,1.0,1.0>, 1.0, 10.0, 0.6]);
}
llListenRemove(Listen_Id);//Удаляем процесс прослушивания
llSetTimerEvent(0.0);//Сбрасываем (выключаем) таймер
}
timer()
{
llSetTimerEvent(0.0);//Сбрасываем (выключаем) таймер
llListenRemove(Listen_Id);//Удаляем процесс прослушивания
llWhisper(, «Извините, вы долго выбирали на что нажать :)»);
}
}
При написании статьи я руководствовался материалами вот с этого источника: