ааааааааааа как урок алгебры понл немного а так нихера аааа нана видеокурс и всё обьяснять все значения слов в вайре хорошо рублю а экспрешен неочеь
лана так и быть вот вам мои знания
Туториал по Expression 2
(Туториал переведён с английского языка и слегка изменён,оригинал смотреть тут) В данном туториале цель - показать основы Е2,причём показать это как можно нагляднее.
Введение
Сначала ознакомимся с первыми пятью строками:
Code
@name
@inputs
@outputs
@persist
@trigger All
"@name" - имя экспрешина,которое будет видно при
наведении на него взгляда. Необязательно,если оставить пустым то при
наведении взгляда заместо имени будет "generic".
"@inputs" - строка для входов, т.е. что экспрешин будет обрабатывать
"@outputs" - строка для выходов, т.е. результат вычислений экспрешина
«@persist» - строка для переменных,сюда надо добавлять переменные в случае если этого просит чип (например,использование в конструкции if-then-else или дельта)
Для примера разберём несложный код:
Code
@name Add Expression
@inputs A B
@outputs Out
@persist
@trigger All
Out = A + B
Этот код складывает значения A и B и выводит на выход Out
Кроме этого можно производить другие математические действия:
Out = A – B
Out = A / B
Out = A * B
Out = A ^ B (возведение A в степень В)
If-then-else конструкция.
Функция if — самая элементарная и частоиспользуемая. Она работает на принципе клапана — если (if) условие верно,то (then) сделать действие1,иначе (else) сделать действие2.Схема такая:
Code
if (A) {Out = B} else {Out = C}
То есть если A — верно (больше нуля) то приравнять Out к В,иначе приравнять к С.
Ну и пример на практике:
Code
@name Control
@inputs Button
@outputs Out
@persist
@trigger All
if(Button) {Out = 30} else {Out = 5}
Думаю,тут понятно.
Кроме того можно писать и без else:
Code
if (Button) {Out = 30}
В этом случае значение не сбрасывается и после нажатия на нашу кнопку Out продолжит быть 30 пока мы не сделаем условие чтобы оно принимало нужное нам значение (например, if(Button2) {Out = 5} )
Теперь ещё один пример:
Code
@name Speed
@inputs Speedometer Button
@outputs Out
@persist
@trigger All
if(Button) {Out = Speedometer}
То есть когда мы нажимаем на кнопку выход Out принимает значение спидометра,но тут проблема — когда мы выключаем кнопку Out остался как в последний момент перед выключением? Чтоже делать?
Мы забыли сделать возврат к нулю (else),и правильный код будет:
Code
@name Speed
@inputs Speedometer Button
@outputs Out
@persist
@trigger All
if(Button) {Out = Speedometer} else {Out = 0}
Теперь изучем проверки. Они бывают такими:
«==» - равно
«<» - больше
«<=» - больше либо равно
«>» - меньше
«>=» - меньше либо равно
«!=» - не равно
пример:
Code
@name Bell
@inputs Timer
@outputs Sound
@persist
@trigger all
if (Timer >= 10) {Sound = 1} else {Sound = 0}
В нашем случае это код будильника.Когда таймер (время) больше либо равно 10 то подаём звук, иначе — молчим (просьба не спрашивать меня как делать для этого таймер и как выводить звук,это просто пример — прим.авт)
Так же можно вставлять несколько условий,например:
Code
@name Test
@inputs Button1 Button2
@outputs Out
@persist
@trigger All
if (Button1 | Button2) {Out = 5} else {Out = 0}
Если нажата либо одна либо друга кнопка,то подать на выход 5.Так же кроме «A | B» (или) есть «A & B» (то есть если и А и В больше нуля).Можно делать и более сложные комбинации:
Code
@name Test
@inputs Button1 Button2
@outputs Out
@persist
@trigger All
if (Button1 >= 0 & Button2 == 54) {Out = 5} else {Out = 0}
То есть если кнопка 1 больше либо равна нулю И кнопка 2 равна 54 то подать на выход 5.
Интервал
Теперь ознакомимся с функцией interval(),которая задаёт частоту прогона кода, т.е. время через которое код будет заново перезапускаться,в милисекундах.Сделаем простой таймер:
Code
@name Timer
@inputs
@outputs Explode
@persist Time
@trigger All
interval(1000)
Time = Time + 1
if(Time == 10) {Explode = 1, Timer = 0} else {Explode = 0}
Разберём по строкам (минуя первые четыре,их я описал в начале туториала):
«@persist Time» - отмечаем переменную для времени т.к. она используется в конструкции if
«interval(1000)» - делаем так чтобы код перезапускался каждые 1000 мс или каждую секунду
«Time = Time + 1» - при запуске кода прибавляем к времени 1 единицу,а поскольку у нас код прогоняется каждую секунду получается,что каждую секунду мы прибавляем к времени единицу.Так же може записыватся как «Time += 1» или «Time++» (последняя команда означает поднятие на единицу;если бы мы поднимали значение не на единицу то использовать её нельзя было бы)
«if(Time == 10) {Explode = 1, Timer = 0} else {Explode = 0}» - условие, что если время будет равно 10 то на выход «бабах» будет подано 1 а таймер сбросится,а если время меньше его — то на «взрыв» подаём 0
Ну и наконец напишем ещё более сложный код:
Code
@name Timer
@inputs Button
@outputs Explode
@persist Time
@trigger All
interval(1000)
if(Button) {
Time = Time + 1
if(Time == 10) {Explode = 1} else {Explode = 0}
} else {Time = 0}
То есть если включена кнопка то:
Прибавляется время
Если время больше 10 то подать на Explode 1,иначе 0
,а если кнопка выключена то время сбрасывается на ноль.
Векторы
Векторы - одно из нововведений в Е2 в отличии от первого,здесь является небольшим массивом вида X,Y,Z.Зачем же он вообще нужен? В основном для определения местоположения чего-либо и передвижения (см. ниже),так же вектором удобнее задавать какую-то определённую точку.Вектор и простые числа - это разные типы входов,выходов и переменных.Пример:
Code
vec(300,200,300) + 8
Тут вас чип остановит и скажет,что недопустимая операция,т.к. мы попытались сложить 2 разных типа переменных. А правильный код должен выглядеть так:
Code
vec(300,200,300) + vec(8,8,8) = vec(308,208,308)
Естественно что не обязательно чтобы у второго слогаемого были одинаковые XYZ
Code
vec(300,200,300) + vec(23,432,43) = vec(323,632,343)
Чтобы экспрешин различал типы переменных к векторным входам\выходам надо добавлять постфикс :vector
Code
@name GPS
@inputs GPS:vector Button
@outputs Out:vector
@persist
@trigger All
if(Button) {Out = GPS} else {Out = vec()}
Где vec() - нулевой вектор,можно также записать как vec(0,0,0).
Векторам можно отдельно задавать каждый параметр:
Code
V:setX(#)
V:setY(#)
V:setZ(#)
А если вам надо получить какое-то значение с вектора
Code
V:x()
V:y()
V:z()
Для примера узнаем высоту на которой мы находимся:
Code
@name Height
@inputs GPS:vector
@outputs Height
@persist
@trigger All
Height = GPS:z()
Так же к векторам можно отнести applyForce() но о нём расскажу после entity...
Entity
Дословно - объекты,то есть тип переменной,хранящей в себе информацию о пропе\нпц\игроке.из ентити можно узнать местоположение,имя,модель итд. В простом ваире альтернатива - Beacon Sensor,но всётаки у Е2 куда больше возможностей.
Предположим,мы хотим знать точно где расположен наш экспрешин. У экспрешина есть собственная Entity - entity(),из которого можно узнать вектор. Ну а из вектора можно "извлечь" координаты,вот пример:
Code
@name GPS
@outputs X Y Z
@persist Ent:entity Vec:vector
@trigger All
interval(10)
Ent = entity()
Vec = entity():pos()
X = entity():pos():x()
Y = entity():pos():y()
Z = entity():pos():z()
Здесь мы сначало нашли ентити экспрешина,затем из него выразили все координаты.Заметьте,совсем не обязательно делать столько переменных,я их сделал для пущей наглядности.Как вы поняли entity тоже имеют свой постфикс - :entity.Поскольку при одном прогоне кода позиция не будет изменятся то мы поставили интервал.
applyForce(V)
Теперь можно ознакомится с одной из самых интересных функций экспрешина - применением силы.Вектором задаётся тяга.
Code
@name Force Test
@persist
@trigger All
entity():applyForce( vec(0,0,1000) )
Как видите,тут тоже появляются ентити,именно они тянут. В данном случае на сам экспрешин прилагается сила в 1000 единиц,то есть он летит вверх (если вы конечно его не заморозили).Если бы мы подали не 1000 а -1000 - экспрешин бы стремился вниз,и так по всем трём осям.
Как же сделать простого пропа-убийцу? Давайте попробуем.
Code
@name MingeProp
@inputs Player:entity
@persist
interval(10)
LocalPos = Player:pos() - entity():pos()
entity():applyForce(LocalPos*10000000)
Для того чтобы приложить силу в направлении какого либо нужно знать локальные координаты относительно экспрешина,они узнаются (координата назначения - координата положения экспа).Но поскольку вектор получается не очень большим мы его умножаем на очень большое число (чем больше тем больнее). Поскольку мы ещё не умеем находить игроков самим экспом предусмотрен вход ентити,который можно получить с Target Finder'а. Интервал здесь нужен для обновления информации о местоположении. Когда вы запустите вашего убийцу то он сразу полетит в направлении игрока.
Strings
В Е2 стало появился новый тип данных - strings,"тексты". Они нужны для чат-ботов,Console Screen и Entity Discover (всё это будет ниже). Сами тексты записываются в виде "test" и отображаются серым цветом, в первых четырёх строках у них постфикс S:string .
Тексты можно складывать ("Te" + "st" = "Test"),сравнивать (if (S == "string") {...} ) и использовать команду += ( if (Button) {Text += "a"} )
Разберём простой пример:
Code
@name String Test
@inputs Button
@persist
@trigger All
if (Button) {
print("Hello world!")
}
И когда мы нажимаем на кнопку у нас в чате появляется Hello world!.
Для следующего примера мы залезем в докоментацию ( (я вам вообще советую при чтении этого туториала постоянно держать документацию в соседней вкладке\окне) и напишем код чтобы отслеживать статистику сервера.
Code
@name Server Info
@persist
@trigger All
interval(50) #интервал нужен для обновления последнего сообщения чата
if ( lastSaid() == "getinfo") {
print( hostname() )
print( "Map: " + map() )
print( "Players: " + toString(numPlayers()) + "/" + toString(maxPlayers()) )
}
Когда мы в чат пишем getinfo - получаем
Здесь я вобрал несколько наиболее часто используемых команд связаных с текстами
lastSaid() - команда возвращает (понятней - "означает","равняется") последнее сообщение чата
toString(#) - команда которая переводит цифры в текстовой формат ( toString(5) + " test" = "5 test")
А значение других команд найдите сами в документации (подсказка - ищите в Server Information,пункт 4.21),там же можно посмотреть другие команды strings,например,S:toNumber()
Array и Table
Я решил совместить массивы и таблицы потому что по сути это почти одно и то же. Массив - это группа нескольких значений (цифры,тексты,ентити),причём каждое значение имеет свой номер,а таблица - это несколько значений (те же типы) но каждое имеет своё название в форме текста (string). На первых четырёх строках постфиксы переменных R:array и T:table соответственно.
Разберёмся сначала с массивом.
Изменяется информацию в ячейках массива командами:
Code
R:setNumber(<номер ячейки>,<число>)
R:setString(<номер ячейки>,<текст>)
R:setEntity(<номер ячейки>,<объект>)
Получать же значения из ячеек мы будем с помощью команд:
Code
R:<тип>(<номер ячейки>) #где тип - number,string или entity
Пример для демонстрации:
Code
@name Array Test
@persist R:array
@trigger All
R:setString(1,"lolwut?")
R:setString(2,"omg")
R:setString(3,"NOOO")
Мы создали небольшой массив,его можно представить так:
Code
1 lolwut?
2 omg
3 NOOO
Теперь выведем это к нам в чат:
Code
@name Array Test
@persist R:array
@trigger All
R:setString(1,"lolwut?")
R:setString(2,"omg")
R:setString(3,"NOOO")
print( R:string(1) )
print( R:string(2) )
print( R:stirng(3) )
Таблицы - это те же самые массивы только заместо ячеек - названия,то есть код будет выглядеть весьма знакомо:
Code
@name Array Test
@persist R:array
@trigger All
R:setString("ololo1","lolwut?")
R:setString("ololo2","omg")
R:setString("ololo3","NOOO")
print( R:string("ololo1") )
print( R:string("ololo2") )
print( R:stirng("ololo3") )