Функции и примеры кода языка squirrel
http://www.squirrel-lang.org/doc/squirrel2.html
Точку с запятой в конце строки ставить не нужно, тип переменной указывать не нужно (хотя что вектор).
Создание переменной:
MyX <-null
MyX <-0
MyX <-true
Установка значение переменной знаком = либо <- описанным выше.
MyX =1
Локальные переменные
local a=0 //будет видна только в этом куске кода
Циклы.
for(local a=0;a<10;a+=1)
print(a+"\n"); //10 раз вывести значение переменной а
Работа со string (строковым типом данных)
MyName<-"Stridemann” //Берем в кавычки т. к. это текст
MyName=MyName.slice(0,5) //возвращает обрезанную строку от начала до 5-го символа
print(MyName+"\n") //На выходе: Strid
MyName=MyName+”er”
print(MyName+"\n") //На выходе: Strider
Векторы
Вариант 1:
local pos = Vector()
pos.x = myX
pos.y = myY
pos.z = myZ
Entities.FindByName(null, "MyEntity”).SetAbsOrigin(pos)
Вариант 2:
Entities.FindByName(null, "MyEntity”).SetAbsOrigin( Vector(myX,myY,myZ) )
Функции движка Source (Portal 2) и примеры кода
Это ваша библия на все время работы со скриптами в сорсе : https://developer.valvesoftware.com/wiki/List_of_Portal_2_Script_Functions:ru
Описываю примеры наиболее используемых функций на примере:
MyPlayerEntity <- Entities.FindByName(null, "!player")
MyPlayerEntity.GetName() - получить имя энтити. Получим string. В данном случае получим пустую строку, ибо у игрока имени нету..
EntFire( "MyPlayerEntity.GetName()", "SetHealth", "0" )
EntFire( "MyPlayerEntity.GetName()", "Kill" ) - выдать аутпут указанной энтите.
SendToConsole("developer 1") - написать команду в консоль.
MyPlayerEntity.GetAngles() - получить угол поворота энтити. Получим вектор (x,y,z)
MyPlayerEntity.GetOrigin() - получить координату энтити. Получим вектор (x,y,z)
MyPlayerEntity.GetClassname() - получить класс энтити. Получим string. В данном случае player.
MyPlayerEntity.GetForwardVector() - получить Forward вектор энтити. Если к координате энтити прибавлять этот вектор (умноженный на значение скорости), то энтитя будет двигатся куда смотрит. Пример:
MyPlayerEntity.SetAbsOrigin( MyPlayerEntity.GetOrigin() + (MyPlayerEntity.GetForwardVector()*10))
С игроком не удачный пример. Там точность получения значения поворота +-20 градусов. Правильно обрабатываются только при быстром и длительном повороте. Об этом в конце статьи.
MyPlayerEntity.GetModelName() - получить модель энтити. В нашем случае получим models/player/chell/player.mdl
MyPlayerEntity.SetAbsOrigin(10,10,10)
MyPlayerEntity.SetOrigin(10,10,10)
Телепортировать\переместить объект в указанную координату.
Разница между этими функциями что в SetAbsOrigin есть сглаживающая функция, и в связке с “ускорителем выполнения кода” объект будет двигатся очень плавно.
MyPlayerEntity.SetAngles() -повернуть энтитю в углах Эйлера (по координатам XYZ).
Это примеры наиболее часто используемых функций. В этом списке вы найдете все доступные функции.
Некоторые хитрости
Получить угол поворота игрока
Нельзя правильно получить угол поворота игрока через MyPlayerEntity.GetOrigin() . Точность +-20 градусов (примерно). Чтоб получить точный поворот нужно создать два info_target’а (view_target1 у глаз игрока и припарентить к игроку и view_target2) и постоянно телепортировать второй командой в консоль (желательно через ускоритель кода):
SendToConsole("ent_teleport view_target2")
Далее получаем Pitch и Yaw (Y, Z) поворота игрока через код:
x1<-Entities.FindByName(null, "view_target1").GetOrigin().x
y1<-Entities.FindByName(null, "view_target1").GetOrigin().y
z1<-Entities.FindByName(null, "view_target1").GetOrigin().z
x2<-Entities.FindByName(null, "view_target2").GetOrigin().x
y2<-Entities.FindByName(null, "view_target2").GetOrigin().y
z2<-Entities.FindByName(null, "view_target2").GetOrigin().z
x12<-x1-x2
y12<-y1-y2
z12<-z1-z2
tmp<-0
yaw<-0
pitch<-0
if (y12 == 0 && x12 == 0)
{
yaw = 0
if (z12 > 0)
pitch = 270
else
pitch = 90
}
else
{
yaw = (atan2(y12, x12) * 180 / 3.14)
if (yaw < 0)
yaw += 360
tmp = sqrt (x12*x12 + y12*y12)
pitch = (atan2(-z12, tmp) * 180 / 3.14)
if (pitch < 0)
pitch += 360
}
Этот код переводит вектор в углы Эйлера.
В переменных yaw и pitch будет хранится поворот игрока.
Фикс багов после релиза.
После релиза своего мода (Thinking with Time Machine) были ошибки в логике из за которых пришлось бы перекомпиливать карту, потом бы начались проблемы с сейвами (об этом попозже) и т. д.
В энтите math_counter был установлен максимальный предел счета 1, а нужно было 2. Достаточно было наступить на 1 кнопку (вместо 2-х нажатых кнопок) и дверь откроется. Такой баг.
Но у меня был скрипт, который запускался на каждой карте. При запуске карты одноразово выполнялась функция CheckMap(). В ней я написал:
function CheckMap()
{
if(GetMapName()=="tm_training_01")
EntFire( "button_counter", "SetHitMax", "2")
}
Таким способом при запуске карты фиксился мелкий баг логики.
На основе этого можно почти любые ошибки логики исправлять без рекомпиляции карты.
"Безопасное" обновление карт
После того как мод выпущен обычно делаются фиксы багов, в основном в картах. После этого делается патч (или новый билд, если мод в стиме). После обновления карты у игроков перестают корректно работать автосейвы. Это сразу видно: триггеры стают видимыми (желтыми), куча энтитей перехерячены на карте, мало что работает.
Я решил придумать систему безопасного обновления.
Когда игрок загружает карту при переходе на уровень- он попадает на новую, обновленную карту. Если грузит автосейв, то играет на старой карте без поломки автосейва.
Как это сделать.
1) Новая карта именуется другим именем с приставкой -update2 .
2) По завершению карты запускается функция ( logic_script - CallScriptFunction NextMap ), которая меняет карту.
И нужно делать смену карты через скрипт:
MapCFG<- [
{ map = "tm_map_01b", next_map = "tm_scene_map-update2"},
{ map = "tm_scene_map", next_map = "tm_map_02b"},
{ map = "tm_scene_map-update2", next_map = "tm_map_02b"},
{ map = "tm_map_02b", next_map = "tm_map_03b"},
]
function NextMap()
{
foreach (index, level in MapCFG)
{
if (level.map == GetMapName())
{
SendToConsole("map " +level.next_map)
}
}
}
В этом случае если игрок прошел карту tm_map_01b - запускается функция NextMap, которая ищет в массиве название карты (tm_map_01b) и сравнивает с текущим названием карты (tm_map_01b). Если оно равно- сменить карту на tm_scene_map-update2, то есть на обновленную. В таком случае у игроков на карте tm_scene_map не будет сломан автосейв. Есть один минус, что игрок не увидит уже исправленной карты, но поверьте, это в 100 раз лучше чем получать сотни багрепортов о том, что видны триггеры, автосейв накрылся и т. д.