SL-контент: Скриптинг для ящиков (урок третий) - SL-контент

Перейти к содержимому

Свернуть Прикрепленные теги

Страница 1 из 1
  • Вы не можете создать новую тему
  • Вы не можете отвечать в этой теме

Скриптинг для ящиков (урок третий) Логические операторы и сопсна сама логика.

#1 Пользователь оффлайн   Axon Dezno 

  • Участник
  • PipPipPip
  • Группа: Пользователи
  • Сообщений: 151
  • Дата регистрации: 03.10.08
  • Пол:М
  • Основной цех:Строители
  • Второй цех:Художники
  • SL Status: 

Отправлено 20.01.10 - 01:53

Предыдущий урок

Логик капитулир…

В этом уроке мы рассцмотрим логицские принципы, по каторым работают скрипты.

Сопсна… первым делом скажу, шо логика большинства скриптов основываетсця в основном на так называемых условиях.
Езь правда довольно не большое количество скриптов, которые работают и на чистом ”матане” (математическом анализе),
енто самые трудные для понимания типы скриптов, тем не менее постараюся объясцнить как первый тип, так и второй.

…но сперва ниплоха было бы разобратьсця с базовыми кирпичами из каторых в ЛСЛ любая логика и собираетсця:

Я их тута буду представлять не с той позитции, с которой их обычно в большинстве уроков по скриптингу представляют
(200% которых рассчитаны на апсалютна низнакомых с предметом урока людей имеющих не менее, чем 2-4 годичный опыт работы в этой облати),
а с пазитцыи привязки каждого условия или комбинации условий определённым языковым логицким канструктцыям (скриптовый ЯЗЫК как никак… =О.х=)

if и else, они же, сопстна, условия – дословно переводютсо, как ”если” и ”иначе” и выполняют роли, полностью
соответствуюшчие своим названиям.

Поскольку if является условием это условие должно хде-та задаватьсця. Задаётся условие в круглых скобках, а в фигурных
Скобках, которые идут ПОСЛЕ самого условия находитсця непосредственно код, выполняющийся при его срабатывании.

Шобы яснее представить себе условие приведу его выполнение на примере обычного предложения:

Если на улице темно – идти спать.

Или, если близко к скриптовому синтаксису, то так:

Если(на улице темно) {идти спать;}

Последний вид записи называетсо псевдо код.

ПРАВИЛО: Если вы хотите сделать скрипт с как можно меньшим числом ошибок, ОБЯЗАТЕЛЬНО перед написанием самого кода
набросайте логический ”глобус” скрипта, шобы патом каждый раз не вспоминать зачем вы вчера написали этот вота блок коду
и как он взаимодействует с остальными частями скрипта.

***

else является антиподом заданного условия и без самого условия существовать НЕ МОЖЕТ!!!

Шобы яснее представить себе, почему оно не может существовать без самого условия попрошу вас чётко выполнить следующее
Условие:

В_любом_другом_случае{сесть на стул}

Как мы можем видеть в виду отсутсцтвия самого ”случая” термин ”в любом другом” тут бессцмыселенен.

Связки вида if <=> else называютсо простыми условиями.
Условный пример таких простых условий будит следуюшчим:

if(одна переменная равна другой) {выполнить ”код срабатывания”}
else{выполнить ”код исключения”}

Ну или составное простое условие:

if(на улице всё тает){сказать ”на улице весна”;}
if(на улице тепло){сказать ”на улице лето”;}
if(на улице опадают листья){сказать ”на улице осень”;}
if(на улице теплее чем дома){поискать шубу и валенки;}
else{включить функцию llMosk();}

Помимо простых условий if и else имеетсця ещё и составное else if(условие){код;},
которое дословно переводится, как ”если же…”.

Ну и есесна имеютсо и комплексные условия:

if(на улице утро){плюхать на работу;}
else if (на улице уже день){обматерить всю округу и плюхать на работу в режиме ”лёгкий галоп в припрыжку”;}
else if (на улице выходной){почесать тыкаву и бухнуться спать дальше;}
else {включить функцию llMosk();}

А теперь чешем тыкаву, а не пахоже ли комплексное условие на составное простое? =О.о=

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

Угу… значит с общим принципом работы ифов и элсов разобралися… однако конкретных скриптовых примеров так и не увидели…

Сесна не увидели, паскольку для их понимания нада ещё кое шо знать, а именно – логические операции.
Помните в предыдущем уроке я просил вас не путать ”|”(двоичное сложение) с ”||”(логическое ”или”)?

Вот все эти операции мы сейчас и рассцмотрим.

Логические:

|| – знак означающий ”или”.
Пример: if(a==b || c==d){код} – если(a равно b или c равно d){выполнять код}

&& – знак означающий ”и”.
Пример: if(a==b && c==d){код} – если(a равно b и c равно d){выполнять код}

> он же ”больше”
Пример: if(a>b){код} – если(a больше b){выполнять код}

< он же ”меньше”
Пример: if(a<b){код} – если(a меньше b){выполнять код}

! – знак отрицания.

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

!= - не равно (в не зависимости от того больше или меньше).
Пример – if(a!=b){код} – если(a НЕ РАВНО b){выполнять код}

Работает так же и такой вариант – if(!(a==b)){код} – звучит, как ”если(не_верно_выражение(a=b)){выполнять код}”,
а не как ”если((a не равно b)){выполнять код}”, то есть в этом случае неравенство применяется ко всему выражению.

>= - больше или равно.
Пример: if(a>=b){код} – если(a больше или равно b){выполнять код}

<= - меньше или равно.
Пример: if(a<=b){код} – если(a меньше или равно b){выполнять код}

Бинарные математические (bitwise):

| (OR) - математический бинарный оператор сложения.
Где пригодяетсця: при определении одновременного возвращения нескольких параметров
(ну, там PERM_MOVE|PERM_COPY|PERM_MODIFY|PERM_TRANSFER и т.п.)
Алсо: для запихивания нескольких параметров в один интегер с тцелью экономии места.

& (AND) – математический оператор оставляющий в двух или более двоичных числах тока совпадающие единицы.
Пример: 1001001 & 1000001 => 73 & 65 => 1000001
Ну или так: 1001001 & 1000001 & 1101011 => 73 & 65 & 107 => 65 или 1000001 – то есть среднее число в примере.
Заметим, шо во втором примере получилося число, в котором совпали единицы ВО ВСЕХ ТРЁХ РЯДАХ! Ента важно, паскольку рядов
Может быть и десять, и в результате опять же останется тока число в котором совпадут все десять рядов единиц, ну или нуль
Получитсо.

Сопсна хде енто приминаетсця. В основном в АО, для опрыделения, какая в данный момент кнопка нажата:

//Копипаста из ЛСЛ-вики:
default
{
	state_entry()
	{
		llRequestPermissions(llGetOwner(), PERMISSION_TAKE_CONTROLS);

		//Ну и сопсна, списписок двоичных значений констант  для ллРеквестПермишшн:

		//0 он же ”от ворот поворот”                  0000 0000 0000 0000 0000 0000 0000 0000
		//1 он же х.з. шо…                            0000 0000 0000 0000 0000 0000 0000 0001
		//2 он же PERMISSION_DEBIT                    0000 0000 0000 0000 0000 0000 0000 0010
		//4 он же – PERMISSION_TAKE_CONTROLS          0000 0000 0000 0000 0000 0000 0000 0100
		//8 он же – PERMISSION_REMAP_CONTROLS         0000 0000 0000 0000 0000 0000 0000 1000
		//16 он же – PERMISSION_TRIGGER_ANIMATION     0000 0000 0000 0000 0000 0000 0001 0000
		//32 он же – PERMISSION_ATTACH -              0000 0000 0000 0000 0000 0000 0010 0000
		//64 он же – PERMISSION_RELEASE_OWNERSHIP     0000 0000 0000 0000 0000 0000 0100 0000
		//128 он же – PERMISSION_CHANGE_LINKS         0000 0000 0000 0000 0000 0000 1000 0000
		//256 он же – PERMISSION_CHANGE_JOINTS        0000 0000 0000 0000 0000 0001 0000 0000
		//512 он же – PERMISSION_CHANGE_PERMISSIONS   0000 0000 0000 0000 0000 0010 0000 0000
		//1024 он же - PERMISSION_TRACK_CAMERA        0000 0000 0000 0000 0000 0100 0000 0000
		//2048 он же - PERMISSION_CONTROL_CAMERA      0000 0000 0000 0000 0000 1000 0000 0000
	}
	
	run_time_permissions(integer perm)
	{
		if(perm & PERMISSION_TAKE_CONTROLS)
		{
			llTakeControls(CONTROL_FWD|CONTROL_BACK,TRUE,TRUE);
		}
	}
	
	control(key controller, integer levels, integer edges) 
	{
    	 // Если нажата стрелка вверх (она же ”вперёд”)
    	 if ((levels & CONTROL_FWD) == CONTROL_FWD)  // <== Если врезультате ”эндования” осталась одна цифра…
	  //levels                00000000000000000000000000000011 // десятичное 3
	  //CONTROL_BACK          00000000000000000000000000000010 // десятичное 2
	  //-------------------------------------------------------------------------------
	  //levels & CONTROL_BACK 00000000000000000000000000000010 // десятичное 2

	 	 {
        	llOwnerSay(”Вперёд”);  //Сказать ответ овнеру.
    	 }

    	 // Если нажата стрелка вниз (она же ”назад”)
    	 if ((levels & CONTROL_BACK) == CONTROL_BACK) //<==Если врезультате ”эндования” осталась одна цифра…
		 {
   	     	llOwnerSay(”Назад”); //Сказать ответ овнеру.
  	  	 }
	}
}

***

~ (NOT) – математический бинарный оператор, который обращает все биты числа (было, допустим 111, стало 000).
Применение - может использоваться для обнуления переменной, например:

integer a=4;
integer b=a & ~a;

По русски значение переменной b звучит примерно так – b равно результату отсеивания несовпадающих единиц у a и
инвертированного a (ну и паскоку у второго ”a” нету совпадающих единиц, получутсця одни нули)

Бинарка: b= 100 ~ 011 => 000

***

^ (XOR) – математицский бинарный оператор, который при сXORивании двух и более переменных оставляет в их двоичных значениях
тока не совпадающие единицы.

Пример:

100001^001100 => 101101 -> 33^12=45

100001^010010^001000^000100 => 111111 -> 33^18^8^4=63

Хде его можно использовать?
Использовать его можно, для проверки вида "первая нопка нажата, а вторая нет ИЛИ вторая нажата, первая нет"

control(key controller, integer levels, integer edges)
{
// Если нажато тока CONTROL_FWD, (!)ИЛИ(!) тока CONTROL_RIGHT (но не и то и другое сразу).
if (((levels & CONTROL_FWD) == CONTROL_FWD) ^ ((levels & CONTROL_RIGHT) == CONTROL_RIGHT))
{
//Выполнять код.
}
}

***

>> (шаг в право) – математицский бинарный оператор, каторый смещает фсё битовое поле числа на указанное количество знаков
вправо.

Пример: 93>>4 => 5 или, если в двоичном представлении - 1011101>>4 => 101
Имейте в виду, шо биты, каторые ”ушли за горизонт” безвозвратно теряютсо.

Спраффко: сдвиг двоичного числа на один знак фправо равносилен делению десятичного числа на 2
с последуюшим отсечением дробной части:

93>>1 => 46 или 101110 плюс отсечённый дробный остаток 0.5,
обратное действие – 46*2=92 и плюс 0.5*2, какраз и будит 93.

Сопсна, хде ето дело могёт пригодитьсо? А пригодяетсо оно, если нужно быстро разделить ЧЁТНОЕ целое число на 2.
Так же желательно, шобы в числе, которое вы собираетесь поделить на 2 несколько раз ВСЕ цифры были чётными.

***

<< (шаг в лево) – то же шо и предыдущее, тока биты смещаютсо влево.

Пример: 93<<4 => 1488 или, если в двоичном представлении – 1011101<<4 => 10111010000
Если число сдвинуть за ЛЕВУЮ гранитцу битового поля, то ушедшие ”за бугор” знаки так же потеряютсо.

Спраффко: сдвиг двоичного числа на 1 знак влево равносилен умножению десятичного числа на 2
Пример: 93<<1 => 186 или 10111010 в двоичном представлении,
обратное действие – 186/2=93.

Пригождается для сверхбыстрого УМНОЖЕНИЯ чётных целых чисел на 2.

***

% (остаток) – э… вот это нисафсем двоичный, но тоже полэздный оператор. Возвращает остаток от деления.

Пример: 20 % 18 = 1 целая и 2 в остатке.

***

Угу… значит сопстна с ифами и его атрибутами ознакомилилисць, теперя переползаем к разбору штуки под названием for

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

Пример:

list a=["0","1","2","3","4","5","6","7","8","9"];	//Лист с цифрами.
string input_comand="Многабукав";	//Команда, которую нада побуквенно проанализировать.
string out;	//Переменная, в которую будит складироватьсця ответ.
integer out_num;	//Номер, показывающий сколько знаков из всего поступившего сообщения НЕ ЯВЛЯЮТСЯ ЦИФРАМИ.
integer i;	//Счётчик.

default
{
	state_entry()
	{
		for(i=0; i<llStringLength(input_comand); i++) //До тех пор, пока i равно нулю и i меньше общего числа знаков в
		//поступившей команде, плюс-плюсить переменную i.
		{
			if(llListFindList([llGetSubString(input_comand,i,i)],a)==-1) {out_num++;}
			//Дословный перевод – если поиск тцыфер в текущем символе команды не увенчалсця успехом, 
			//увеличить на 1 переменную out_num.
		}
		
		if(out_num!=i) {out="Переменная либо содержит и тцыферы и букавы, либо тока цифры";} //Если количество букв меньше
		//общего количества знаков в сообщении, выдать соответствующий ответ.
		else{out="Переменная содержит тока букавы";} //В любом другом случае (а он тута фсево один получаетсо),
		//выдать другой ответ.
		
		llOwnerSay(out); //Сопсна сказать ответ.
	}
}


Как мы магём заметить, for у нас находится в state_entry, аналогичное действие можно было бы провернуть с помощью события
timer, но, вопервых, если бы нам таймер вдруг потребовался для какого-то другого блока коду, то пришлось бы либо выключать
и перезапускать таймер, либо гемориться с внедрением ”параллельной” обработки нескольких разных блоков кода в одном событии
(а это, поверьте на слово ППЦ тот ещё), к тому же таймер срабатывает раз в определённый промежуток времени и имеет свои
Физические ограничения на минимальное срабатывание (главным образом в виду того, шо, если скрипт работает на выдачу данных
на всеобщее обозрение, то при значении меньше 0.08-0.05 сек. из за не способности большинства интернет-каналов передавать
данные от клиента SL с такой скоростью, а так же из за мелких глюков в самом LSL, данные начнут теряться, а сам клиент будит
ощутимо тормозить).

Вопщем кароче… представим себе такую ситуатцыю,- у нас нету for, и нам нада увеличить переменную i на 1,
ну, допустим, 200 раз – вапростц – скока нам придётсця ждать ответа, если таймер выставлен на 0.1, а результат нужен нам не
более, чем через 1.0-1.3 секунды? =О.о=

Воо! Доплюхало, теперь, зачем фор пригдяетсо?

Для тех, хто сафсем в танке, разжую – for нужен для сверхбыстрого многократного выполнения определённого блока коду, БЕЗ
Использования таймера и из любого события с сохранением и последующей (при необходимотцти) доработкой этих данных кодом,
Заключённым внутри этого события до закрытия самого события (фпративном случае прыдётсо вызывать это событие повторно).

Ну и для наглядностцти два ИДЕНТИЧНЫХ примера обработки таких вычистцлений из под таймера и с помощью for:

//Наглядный пример скрипта, за который надо хорошо выпороть его создателя. 
//НЕЕЕЕ!!! ТОКА НЕ МЕНЯ!!! =Х_____х= Эт я так… утрированно сказал, на счёт выпороть…

integer trigger=0;	//Триггер, включающий срабатывание расчета.
integer i;	//Сопстна счётчик.
integer d_i;	//Дублирующая переменная счётчика.

default
{
	state_entry()
	{
		llSetTimerEvent(0.01);		//Устанавливаем таймер на одну сотую секунды.
		llListen(0,"",llGetOwner(),"");	//Устанавливаем листен.
	}
	
	timer()
	{
		if(trigger==1)	//Если триггер равен 1.
		{
			if(i<200)	//Если i меньше 200.
			{
				i++; //Плюс-плюсить i.
				//Ну и заодно выполнить какой-нить код.
			}
			if(i>=200) //Если i больше или равно 200.
			{

			d_i=i;	//Дублировать значение переменной i в переменную d_i.
			trigger=0;	//обнулить триггер, поскольку срабатывание этого условия свидетельствует об окончании расчета.
			llMessageLinked(LINK_THIS,0,"i-"+(string)d_i,"");	//Поскольку листен периодцски отказываетсо приминать
			//команды из того же скрипта, в котором он находитсо передаём результат с добавочным индексом через
			//месседжЛинкед
			i=0;	//Обнуляем счётчик ввиду окончания расчета.

			//Обратите вминание на постановку переменных в этом условии – i обнуляется ПОСЛЕ присвоения его значения
			//переменной d_i, иначе в d_i уйдёт нуль! 

			}
		}
		else{}
	}
	
	listen[/color](integer channel, string name, key id, string msg)
	//Листен нужен для того, шобы юзер мог хоть как-то взаимодействовать со скриптом.
	//расчет начанает производиться при поступлении от овнера любой команды.
	{
			trigger=1;	//При любой команде (тока от овнера) из чата, включать расчет переменной.
	}
	
	link_message(integer sender_number, integer number, string msg, key id)
	{
		if(trigger==0 && d_i==200)	//О! А вот тута, как можем заметить сам код АБСОЛЮТНО не использует входные
		//переменные события. 
		//Но… по идее… если он их не использует… то как он тогда может работать?
		//Легко и не принуждённо – это событие активируется каждый раз, как тока в содержащий текущий скрипт прим
		//приползает сообщение самому событию до лампочки использует содержащийся в этом событии код поступившие
		//данные или нет, событие просто активируется, выполняет код и закрываетсо.
		{
			llOwnerSay("i="+(string)d_i+". время затраченное на рассчёт i - "+(string)((float)d_i/50)+" сек.");
			//Сказать хозяину значение i и время его расчета.
			//А вот терь вминание! Заметили тама такую хреновину - (string)((float)d_i/50)?
			//Объясцняю шо ента – как мы помним в ллОвнерСей вводются тока string-и, паскоку мне было ДИКО ЛЕНЬ
			//чепятать отдельно дополнительную переменную с расчетом значения d_i/50, тоя эт самое…
			//образовал цифровую область в string-овом пространстве, путём выполнения математицких вычислений
			//в скобках, с последующим преобразованием результата выражения в string, а, эт самое… float перед d_i
			//стоит потому, шо по факту d_i это integer, а не дробь, а ответ будит какраз дробью.

			d_i=0;		//Обнулить d_i
		}
	}
}

//А теперя сравните со следующим скриптом и почешите тыкву, а нужен ли вам весь вышеприведённый гемор.


Пример с for:

integer i;	//Сопстна счётчик.

default
{
	state_entry()
	{
		llListen(0,"",llGetOwner(),"");	//Устанавливаем листен.
	}

   listen(integer channel, string name, key id, string msg)
   {
	  for(i=0; i<200; i++)
	  {
		//А тута, во время каждого плюс-плюсания переменной i выполняется код.
	  }

	  //Как можем заметить сразу после расчёта for прям в этом же событии говорится ответ.
	  //В предыдущем примере, мне пришлось триггерить этот ответ с помощью анального обхода из ллМесседжЛинкед.
	  llOwnerSay("i="+(string)i+". время затраченное на рассчёт i – ХЗ");
   }
}


Так, для чего нужен for посмотрели, едем дальше.

while эта штука нужна примерно для того же, для чего for она выполняет определённый код до тех пор, пока верно основное
выражение.

Пример:
integer a=1;
integer b=2;

default
{
	state_entry()
	{
		llSetTimerEvent(2.0);
	}

	timer()
	{
		while(a<b) //До тех пор, пока a меньше b говорить овнеру, шо a меньше b.
		//Имейте в виду, шо while будит ПОСТОЯННО выполняться, тока в ПОВТОРЯЮЩИХСЦЯ событиях!
		//В не повторяющихся событиях навроде stste_entry срабатывание while-а произойдёт ьока 1 раз!
		{llOwnerSay(”a меньше b”);}
	}

	touch_start(integer x)
	{
		a=3;
	}
}


И такой вота примерчик:
integer a=1;

default
{
	state_entry()
	{
		llSetTimerEvent(2.0);
	}

	timer()
	{
	while(a)	//Во! Сопстна, весь тцымес примера в этой строчке, дословно переводитсця, как ”до тех пор, пока a равно TRUE”
	//Есть ещё обратный вариант - while(!a), шо переводитсо, как ” до тех пор, пока a НЕ ТРУЪ”.
	//Сесна, такая компановка применима только в случае, если ”a” является булевым значением, тоезь либо TRUE, либо FALSE.
	{
		llOwnerSay(”a равно ТРУЪ”);
	}
   }

	touch_start(integer x)
	{
		a=FALSE;
	}
}
//Примечание: цикл [color="#0000FF"]while[/color] НЕ БУДИТ запускаться, если переменная a ИЗНАЧАЛЬНО равна выполнению условия завершения.


Применяетсця while, в основном, как замена if-овым конструкциям вида if(a!=TRUE) и if(a==TRUE),
ну или полностью идентичным if(a==FALSE) и if(a!=FALSE), поскольку, если в скрипте многа if-ов, то при анализе скрипта
довольно быстро можно запутаться.

Примечание: Цикл while запускается с довольно низким ”приоритетом”, тоезь, фслучае тормозов на симе, цикл будит самым
медленно работающим куском коду. Поэтому рекомендуется вместо них фсёже if-ы юзать.

do{//Код} – Эта штука просто выполняет код. Идёт, как нашлёпка к while.

do{//Код} while(//Условие) – А вот это шо-та типа ”условия наоборот” в сией конструкции, в отличии от if, СПЕРВА
выполняется код, а потом, тока идёт проверка условия… честно говоря до мну нисафсем доехало кому такое нужно и зачем,
но раз есть, значит надо по идее…

jump – Эта штука осуществляет переход от одного куска кода к другому, то есть это что-то типа аналога гиперссылки из HTML.

Сопстна, объясню, как правильно делать прыжок.

Для прыжка необходимо пометить начальную точку и конечную. Начальная помечаетсця, как ”jump имя точки;”,
а конечная, как ”@имя точки;” (”@” перед именем и ”;” после ОБЯЗАТЕЛЬНЫ!!!)

Как это выглядит на практике:

integer a;
integer b;
integer c;
default
{
	state_entry()
	{
		a=1;
		jump end; //Прыгаем в обход кода.
		b=2;
		c=3;
		@end; 	//Продолжаем отсюда.
		llOwnerSay(”А равно ”+(string)a);
	}
}


Примечание: использование jump новяками в скриптинге НАСТОЯТЕЛЬНО НЕ РЕКОМЕНДУЕТСЯ!!!
Ввиду таво, шо с его помощью можно делать рекурсивные (вечные) циклы.

Сопстна, как определить, шо вы не новичок – если вы можете написать скрипт АО с закрытыми глазами и на память помните,
зачем нужна любая функция языка LSL и каждый её атрибут, значит вы уже определённо не нуб.
(я лично такими знаниями похвастаться нимагу, по этому обхожу джампы десятой дорогой).

Так, основные часто используемые операторы вроде бы изучили, давайте теперь пасмотрим,
как создавать свои собственные функции.

Для начала, скажу, шо функции бывают двух типов:

1 Исполняющие - типа llSetText, в них надо тока забить параметры фсё остальное они сделают сами.
Используются в основном для выполнения каких-либо действий направленных ”наружу”, либо для промежуточных операций.

2 Преобразовывающие – навроде float llFrand(float rand), эти функтцыи приминают значение (в скобках которое), преобразует,
проводя, через свой тцыфероварительный тракт и выдаёт результат (флоат перед именем функции видим? Вот это основной признак преобразующей функции).

Начнём с создания исполняющих функций.

llMyFirstFunction(integer param)
{
	if(param==0){llOwnerSay(”Входной параметр функции равен нулю”);}
	else{llOwnerSay(”Входной параметр функции больше нуля”);}
}

default
{
	state_entry()
	{
		llMyFirstFunction(0);
	}
}


Шо мы тута, сопсна видим? А видим мы, шо функция-то по факту не сильно сложная штука и состоит из названия,
скобок с параметрами и блока с кодом.

Также, как мы заметили, начепятанная нами функция находится перед дефолтным состоянием, шо о чём говорит?
Угу, пральна, о том, шо мы можем эту функцию вытащить целиком из этого скрипта и фставить в какой-нить другой,
или наклепать вагон универсальных функций и собирать из них скрипты, как из конструктора LEGO лишь чуууть-чуть
переписывая их при необходимости. Сесна, и при ”блочной” компоновке логику всёравно писать придётсо (надо же чему-то
эти функции активировать), но не в таких количествах, как при написании монолитного кода.

Тока, обращаю внимание на то, шо функция будит работоспособной в любом скрипте, ТОЛЬКО, если все используемые ею переменные
содежатся В НЕЙ САМОЙ! Тоесть у универсальных функций не должно быть никаких ссылок на глобальные переменные текущего
скрипта, иначе если переменная, которую запрашивает функция после переноса в новый скрипт отсутствует, срипт,
сесна, нибудит работать.

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



Так, исполняющие функции более-менее освоили, переходим к окучиванию преобразующих.

Преобразующие функции могут помимо выполнения каких-либо расчетов ещё и возвращать результат этих расчетов непосредственно
туда, откуда эта функция вызываласць:

integer a=1;
integer b=3;

string llAplusB(integer a, integer b)	//Сопсна наша функция, обратите внимание – перед её названием стоит тип string
//возвращаемая переменная должна быть ТОГО ЖЕ ТИПА!!!
{
	integer pre_out=a+b;	//Объявляем переменную типа integer и в ней же рассчитываем результат.
	string out=(string)pre_out;	//Объявляем переменную типа string и сразу запихиваем туда преобразованниый pre_out.
	return out;	//Возвращаем ответ

	//Вышеприведённый код я дал сугубо для наглядности, а вообще всё это можно записать и покороче:
//return (string)(a+b);
//Звучит это, как ”вернуть только что созданную переменную типа string заключающую в себе сумму integer-ов a и b”.
}

default
{
	state_entry()
	{
		llOwnerSay(llAplusB(a,b));	//Ответ вернулся туда же, откуда была вызвана функция.
	}
}


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

Пример:
func_toucher(key avatar)
{
	if(avatar==llGetOwner()){llSay(0,”Халоу”);} //Если дотронулся обладатель скрипта, сказать ”Халоу”
	else {return;}	//Если нет завершить функцию.
}

default
{
	touch_start(integer x)
	{
		func_toucher(llDetectedKey(x));	//Сопсна сама функция.
	}
}


Это, то, шо пока есть в наличии, извиняюся если шо-та не понятно написанно (если хде нашли ошибку или не точность пишите в личку - исправлю).
Вышеприведённое являетсо базисом НЕОБХОДИМЫМ для понимания скриптовой логики без чужой помощи.
Допиливаю урок стахановскими темпами, в виду тог, шо тута, на данный момент отсутствует объяснение сложной логики...
да и по простой не очень многа пока имеетсо...
0

#2 Пользователь оффлайн   Amaro 

  • Новичок на форуме
  • PipPip
  • Группа: Пользователи
  • Сообщений: 33
  • Дата регистрации: 13.05.08
  • Основной цех:Строители
  • Второй цех:Скриптеры
  • SL Status: 

Отправлено 20.01.10 - 03:54

jump - это очень, очень плохо. Лучше про него сразу забыть и никогда не вспоминать. Если только вместо break использовать, и то сомнительно.....
0

#3 Пользователь оффлайн   Web 

  • Новичок на форуме
  • PipPip
  • Группа: Пользователи
  • Сообщений: 34
  • Дата регистрации: 03.03.10
  • Пол:М
  • Откуда:Харьков
  • Основной цех:Скриптеры
  • Второй цех:Строители
  • SL Status: 

  Отправлено 03.03.10 - 08:50

Няааа :o

Как много понаписали-то! Дал же себе кто-то труд все то объяснить :P А то людики-то юзают обычно побитовое сравнение, и не задумываются обо всей этой побитовой мишуре - ну & и &, подумаешь =)) Спасяб ;)

Смотреть сообщениеAmaro, 20.1.2010, 2:54, написал:

jump - это очень, очень плохо. Лучше про него сразу забыть и никогда не вспоминать. Если только вместо break использовать, и то сомнительно.....


А Баба Яга - против! Ну и что вам джампы сделали? Нечитаемый код, значить, да?) А вы знаете, сколько СЕКУНД времени иногда позволяют спасти джампы?)) К примеру, иф+джамп занимает немножечко меньше времени, чем цикл, и работает множечко быстрее. Попробуйте вместо while-а и почувствуйте разницу :D

Вообще, "красивое программирование", "читаемый код" - это не про LSL, потому что код-то скорее всего как раз не будет никто читать... Тут приходится выбирать - или пишешь "красиво", без меток, без тайпкастинга (который иногда тоже спасает секунду-две, ей-богу) - или пишешь как Damen Hax - работает, а вот как работает - хрен разбересся =)
Кодю на LSL. Гадаю по звёздам. Ловлю крабов в заливе. Дорого.
0

#4 Пользователь оффлайн   Axon Dezno 

  • Участник
  • PipPipPip
  • Группа: Пользователи
  • Сообщений: 151
  • Дата регистрации: 03.10.08
  • Пол:М
  • Основной цех:Строители
  • Второй цех:Художники
  • SL Status: 

Отправлено 03.03.10 - 15:23

Блин... зарезервирую-ка я пару-тройку каментов, для продолжения урока, тут если шо пока тока 1/5 где-то от того шо будит.

Насчёт джампов - для новяков (а урок именно на них рассчтан) юзание джампов без наличия в тыкаве головы полной логической схемы работы
скрипта чревато обшЫрным и множественным разрывопереломом моска с далеко и шЫроко разлетающимися последствиями...
X________________________________________________x
Хто хочет - ищет способ, хто не хочет - ищет причину.
0

#5 Пользователь оффлайн   Axon Dezno 

  • Участник
  • PipPipPip
  • Группа: Пользователи
  • Сообщений: 151
  • Дата регистрации: 03.10.08
  • Пол:М
  • Основной цех:Строители
  • Второй цех:Художники
  • SL Status: 

Отправлено 03.03.10 - 15:23

И второй резервный камент...
X________________________________________________x
Хто хочет - ищет способ, хто не хочет - ищет причину.
0

#6 Пользователь оффлайн   Web 

  • Новичок на форуме
  • PipPip
  • Группа: Пользователи
  • Сообщений: 34
  • Дата регистрации: 03.03.10
  • Пол:М
  • Откуда:Харьков
  • Основной цех:Скриптеры
  • Второй цех:Строители
  • SL Status: 

Отправлено 05.03.10 - 00:09

Смотреть сообщениеAxon Dezno, 3.3.2010, 14:23, написал:

Насчёт джампов - для новяков (а урок именно на них рассчтан) юзание джампов без наличия в тыкаве головы полной логической схемы работы
скрипта чревато обшЫрным и множественным разрывопереломом моска с далеко и шЫроко разлетающимися последствиями...


Да, это да =) Некоторые просто делают джампы в другой конец скрипта... Обычно "прыгают" в начало либо конец "логического блока". Как правило, на расстояние 1-3 строчек прыгают, не дальше :o
Кодю на LSL. Гадаю по звёздам. Ловлю крабов в заливе. Дорого.
0

#7 Пользователь оффлайн   Amaro 

  • Новичок на форуме
  • PipPip
  • Группа: Пользователи
  • Сообщений: 33
  • Дата регистрации: 13.05.08
  • Основной цех:Строители
  • Второй цех:Скриптеры
  • SL Status: 

Отправлено 10.03.10 - 14:04

Смотреть сообщениеWeb, 5.3.2010, 0:09, написал:

Смотреть сообщениеAxon Dezno, 3.3.2010, 14:23, написал:

Насчёт джампов - для новяков (а урок именно на них рассчтан) юзание джампов без наличия в тыкаве головы полной логической схемы работы
скрипта чревато обшЫрным и множественным разрывопереломом моска с далеко и шЫроко разлетающимися последствиями...


Да, это да =) Некоторые просто делают джампы в другой конец скрипта... Обычно "прыгают" в начало либо конец "логического блока". Как правило, на расстояние 1-3 строчек прыгают, не дальше :o



А из стейта в стейт никто не пробовал? Вот блин прям интересно стало, чо получиЦЦо =)
0

#8 Пользователь оффлайн   Web 

  • Новичок на форуме
  • PipPip
  • Группа: Пользователи
  • Сообщений: 34
  • Дата регистрации: 03.03.10
  • Пол:М
  • Откуда:Харьков
  • Основной цех:Скриптеры
  • Второй цех:Строители
  • SL Status: 

Отправлено 09.08.10 - 13:26

Смотреть сообщениеAmaro, 10.03.10 - 14:04, написал:

А из стейта в стейт никто не пробовал? Вот блин прям интересно стало, чо получиЦЦо =)

Ничего не получиЦЦо ;-)
Кодю на LSL. Гадаю по звёздам. Ловлю крабов в заливе. Дорого.
0

Сообщить о теме:


Страница 1 из 1
  • Вы не можете создать новую тему
  • Вы не можете отвечать в этой теме