RAILWORKS сообщество


Всё для фаната RailWorks и Train Simulator 2016!

Язык программирования LUA. Скрипты.

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

Испытываете ли Вы желание разобраться в программировании на языке Lua?

Опрос закончился 20 май 2016, 18:05

Да, хотелось бы
7
70%
Нет, и без того забот немерено
0
Голосов нет
Надо посмотреть. Пока не знаю
3
30%
 
Всего голосов : 10

Re: Язык программирования LUA. Скрипты.

Сообщение Света » 02 июн 2016, 22:05

Можно ли полностью выполнять расчет тяги в скрипте и выдавать для симулятора?
Да, причем очень просто. Функция достаточно простая. Её легко интегрировать в готовый скрипт. В готовом варианте занимает 60 строк для 8 позиций.
Возможно ли заменить стандартные тормоза на скриптованные?
Да. Можно сделать тормоза, работа которых будет очень сильно зависеть от длины состава, а можно сделать систему, когда работа тормозов будет зависеть не только от длины состава, а и от типа вагонов, их состояния, сезона, профиля пути. К сожалению, второй вариант требует правки скриптов всех вагонов, поэтому он теоретический. А первый - вполне реальный. Готового варианта нет, так как пока в нём не было необходимости.
Сильные люди - это не те, у которых всё хорошо, а те, у которых всё хорошо несмотря ни на что.
Света
 
Аватара пользователя
Разработчик
 
Сообщения: 565
Зарегистрирован:
Баллы репутации: 129
За это сообщение пользователю Света сказали "спасибо":
Dmitryi JD

Re: Язык программирования LUA. Скрипты.

Сообщение Света » 13 июн 2016, 17:33

Всем доброго дня :)

Представляю вниманию разработчиков фрагменты кода, которыми я предлагаю дополнять новые вагоны/локомотивы. Также, было бы нелишне, ИМХО, дополнить такими функциями уже выпущенный ПС.

[+] дополнение для вагона
Код: Выделить всё
--------------------------------------------------------------------------------------
-- ON GAME LOAD

function Initialise ()

   -- Consist Message IDs
   REPORT_MSGID = 1818190301       -- Метка сообщения, определяющая содержимое пакета

   WagonName = Call("GetRVNumber") -- Номер вагона (присваиваемый в редакторе сценария)
   WagonLength = 10800            -- Длина вагона
   AmountAxle = 4               -- Количество осей вагона
   TimeRelease_1 = math.random (20, 60) -- Время отпуска тормозов вагона (задается случайно внутри возможных значений для вагона)
   TimeRelease_2 = math.random (40, 60) --[[ Время отпуска тормозов вагона для уклона больше 4 тысячных (задается
                                 случайно внутри возможных значений для вагона) ]]
end

function Update ( time )

   local Length = Call("GetConsistLength")
   local Mass = Call("GetTotalMass");

   if Length ~= prevLength or Mass ~= prevMass then
      
      local TransMass = math.floor(Mass*1000)         
      local TransMess = WagonName..":"..AmountAxle..":"..WagonLength..":"..TransMass..":"
      
      if Call ("GetGradient") > 0.4 then
         TransMess = TransMess..TimeRelease_2..":"
      else
         TransMess = TransMess..TimeRelease_1..":"
      end
      
      Call( "SendConsistMessage", REPORT_MSGID, TransMess, 0 );
      Call( "SendConsistMessage", REPORT_MSGID, TransMess, 1 );
      
      prevLength = Length
      prevMass = Mass
   end

end -- Update ( time )

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

Передаваемые данные.
В текущей версии пересылаются следующие данные вагона:
- Номер
- Количество осей
- Длина
- Полный вес
- Время отпуска тормозов
(Список отсылаемых данных можно легко изменить/пополнить)

Зачем это нужно?
В первую очередь для реализации полноценных тормозов, когда реакция тормозной магистрали будет на 100% зависеть от данных состава. Благодаря случайно заданному времени отпуска для каждого вагона, поведение состава в каждой сессии сценария будет отличаться. Примененный метод позволяет очень легко реализовать зависимость поведения тормозной системы от времени года (и, возможно, погодных условий).
Также информация о составности поезда и оперативно измеряемом количестве осей может пригодится при постройке продвинутых систем локомотива.
Полный вес состава может помочь решить проблему с самоходом груженых вагонов - вагон может для движка числиться пустым (по конфигах) и при том, значение, переданное им локомотиву может напрямую влиять на поведение тяги локомотива, создавая иллюзию тяжелющего состава.

Насколько проблемно это реализовать?
Вообще не проблема. Если этот код вставить в новые вагоны, и собрать состав из новых и старых, где эти методы не используются, правильно построенный скрипт локомотива сможет определить наличие в составе вагонов, которые не отчитались и усреднить значения для всего состава. Это будет намного реалистичнее, чем рассчитывать тормоза по длине поезда.

[+] дополнение для локомотива
Код: Выделить всё
---------------------------------------------------------------------------------------------
-- ON GAME LOAD

function Initialise ()

-- Consist Message IDs
   REPORT_MSGID = 1818190301

   prevLength = 1
   TabIndex = { [1] = "Wagonname", [2] = "AmountAxle", [3] = "Length", [4] = "Mass", [5] = "TimeRelease" }
   transtimer = 0
   readenable = false

end
---------------------------------------------------------------------------------------

function OnConsistMessage ( msg, argument, direction )

   if msg == REPORT_MSGID then
      
      local Length = Call("GetConsistLength")
      
      if Length ~= prevLength then
         transtimer = 0
         TabAmountAxle = {}
         TabLength = {}
         TabMass = {}
         TabTimeRelease = {}
         prevLength = Length
      end
      
      allocation (argument)
      return
   end
end
---------------------------------------------------------------------------------------

function Update ( time )

   if readenable == true then
      if transtimer < 1 then
         transtimer = transtimer + time
      else
         if transtimer > 0.5 then
            transtimer = 2
            readenable = false

-- реакция систем на изменение состояния состава

         end
      end
   end
end -- Update ( time )
---------------------------------------------------------------------------------------

function allocation (data)
   TabAmmountchar = {}

   local Length = string.len (data)
   local index, indexparameter = 1, 1
   local temp = ""
   
   while index < Length + 1 do
      temp = string.sub(data, index, index);
      if temp == ":" then
         TabAmmountchar[TabIndex[indexparameter]] = index - 1
         indexparameter = indexparameter + 1
      end
      index = index + 1
   end
   
   local keywagnum = string.sub(data, 1, TabAmmountchar.Wagonname);
   TabAmountAxle[keywagnum] = tonumber(string.sub(data, TabAmmountchar.Wagonname + 2, TabAmmountchar.AmountAxle));
   TabLength[keywagnum] = tonumber(string.sub(data, TabAmmountchar.AmountAxle + 2, TabAmmountchar.Length));
   TabMass[keywagnum] = tonumber(string.sub(data, TabAmmountchar.Length + 2, TabAmmountchar.Mass));
   TabTimeRelease[keywagnum] = tonumber(string.sub(data, TabAmmountchar.Mass + 2, TabAmmountchar.TimeRelease));

   readenable = true
end

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

Ресурсоемкость обработчика незначительная - обсчет производится разово при получении данных, а данные отсылаются вагоном один раз при изменении состояния.

Как пруф работоспособности представляю лог-файл, записанный на тестовой поездке. В процессе поездки были произведены прицеп/отцеп вагонов, а также погрузка. Использовалось 6 дозаторов, из которых 2 были изначально загружены.
Вся эта информация четко фиксировалась:

[+] лог-файл испытательной поездки
Код: Выделить всё
00:00:00   ТЭМ2 запуск
00:00:13   Вагоны прицепленны. Текущее состояние:

----------------------------------------------------------------
   СВОДНАЯ ИНФОРМАЦИЯ:

   Всего прицеплено вагонов, штук: 2
   Общее количество осей: 8
   Суммарная длина вагонов (без локомотива), мм: 21600
   Суммарное время отпуска тормозов всех вагонов, сек: 79
   Полный вес всех вагонов, кг: 45400

----------------------------------------------------------------
   ИНФОРМАЦИЯ ПО ОТДЕЛЬНЫМ ВАГОНАМ:

   Количество осей:
 № вагона - 30523512 значение - 4
 № вагона - 30523570 значение - 4

   Длина:
 № вагона - 30523512 значение - 10800
 № вагона - 30523570 значение - 10800

   Время отпуска тормозов:
 № вагона - 30523512 значение - 53
 № вагона - 30523570 значение - 26

   Вес вагона:
 № вагона - 30523512 значение - 22700
 № вагона - 30523570 значение - 22700

================================================================



00:00:17   Вагоны прицепленны. Текущее состояние:

----------------------------------------------------------------
   СВОДНАЯ ИНФОРМАЦИЯ:

   Всего прицеплено вагонов, штук: 6
   Общее количество осей: 24
   Суммарная длина вагонов (без локомотива), мм: 64800
   Суммарное время отпуска тормозов всех вагонов, сек: 235
   Полный вес всех вагонов, кг: 256200

----------------------------------------------------------------
   ИНФОРМАЦИЯ ПО ОТДЕЛЬНЫМ ВАГОНАМ:

   Количество осей:
 № вагона - 30523579 значение - 4
 № вагона - 30523596 значение - 4
 № вагона - 30523570 значение - 4
 № вагона - 30523512 значение - 4
 № вагона - 30523588 значение - 4
 № вагона - 30523539 значение - 4

   Длина:
 № вагона - 30523579 значение - 10800
 № вагона - 30523596 значение - 10800
 № вагона - 30523570 значение - 10800
 № вагона - 30523512 значение - 10800
 № вагона - 30523588 значение - 10800
 № вагона - 30523539 значение - 10800

   Время отпуска тормозов:
 № вагона - 30523579 значение - 27
 № вагона - 30523596 значение - 26
 № вагона - 30523570 значение - 26
 № вагона - 30523512 значение - 53
 № вагона - 30523588 значение - 53
 № вагона - 30523539 значение - 50

   Вес вагона:
 № вагона - 30523579 значение - 22700
 № вагона - 30523596 значение - 82700
 № вагона - 30523570 значение - 22700
 № вагона - 30523512 значение - 22700
 № вагона - 30523588 значение - 22700
 № вагона - 30523539 значение - 82700

================================================================



00:00:25   Вагоны отцепленны. Текущее состояние:

----------------------------------------------------------------
   СВОДНАЯ ИНФОРМАЦИЯ:

   Всего прицеплено вагонов, штук: 5
   Общее количество осей: 20
   Суммарная длина вагонов (без локомотива), мм: 54000
   Суммарное время отпуска тормозов всех вагонов, сек: 185
   Полный вес всех вагонов, кг: 173500

----------------------------------------------------------------
   ИНФОРМАЦИЯ ПО ОТДЕЛЬНЫМ ВАГОНАМ:

   Количество осей:
 № вагона - 30523579 значение - 4
 № вагона - 30523596 значение - 4
 № вагона - 30523570 значение - 4
 № вагона - 30523588 значение - 4
 № вагона - 30523512 значение - 4

   Длина:
 № вагона - 30523579 значение - 10800
 № вагона - 30523596 значение - 10800
 № вагона - 30523570 значение - 10800
 № вагона - 30523588 значение - 10800
 № вагона - 30523512 значение - 10800

   Время отпуска тормозов:
 № вагона - 30523579 значение - 27
 № вагона - 30523596 значение - 26
 № вагона - 30523570 значение - 26
 № вагона - 30523588 значение - 53
 № вагона - 30523512 значение - 53

   Вес вагона:
 № вагона - 30523579 значение - 22700
 № вагона - 30523596 значение - 82700
 № вагона - 30523570 значение - 22700
 № вагона - 30523588 значение - 22700
 № вагона - 30523512 значение - 22700

================================================================



00:00:30   Вагоны отцепленны. Текущее состояние:

----------------------------------------------------------------
   СВОДНАЯ ИНФОРМАЦИЯ:

   Всего прицеплено вагонов, штук: 2
   Общее количество осей: 8
   Суммарная длина вагонов (без локомотива), мм: 21600
   Суммарное время отпуска тормозов всех вагонов, сек: 79
   Полный вес всех вагонов, кг: 45400

----------------------------------------------------------------
   ИНФОРМАЦИЯ ПО ОТДЕЛЬНЫМ ВАГОНАМ:

   Количество осей:
 № вагона - 30523512 значение - 4
 № вагона - 30523570 значение - 4

   Длина:
 № вагона - 30523512 значение - 10800
 № вагона - 30523570 значение - 10800

   Время отпуска тормозов:
 № вагона - 30523512 значение - 53
 № вагона - 30523570 значение - 26

   Вес вагона:
 № вагона - 30523512 значение - 22700
 № вагона - 30523570 значение - 22700

================================================================



00:01:22   Произведена погрузка. Текущее состояние:

----------------------------------------------------------------
   СВОДНАЯ ИНФОРМАЦИЯ:

   Всего прицеплено вагонов, штук: 2
   Общее количество осей: 8
   Суммарная длина вагонов (без локомотива), мм: 21600
   Суммарное время отпуска тормозов всех вагонов, сек: 79
   Полный вес всех вагонов, кг: 105400

----------------------------------------------------------------
   ИНФОРМАЦИЯ ПО ОТДЕЛЬНЫМ ВАГОНАМ:

   Количество осей:
 № вагона - 30523512 значение - 4
 № вагона - 30523570 значение - 4

   Длина:
 № вагона - 30523512 значение - 10800
 № вагона - 30523570 значение - 10800

   Время отпуска тормозов:
 № вагона - 30523512 значение - 53
 № вагона - 30523570 значение - 26

   Вес вагона:
 № вагона - 30523512 значение - 22700
 № вагона - 30523570 значение - 82700

================================================================



00:01:53   Произведена погрузка. Текущее состояние:

----------------------------------------------------------------
   СВОДНАЯ ИНФОРМАЦИЯ:

   Всего прицеплено вагонов, штук: 2
   Общее количество осей: 8
   Суммарная длина вагонов (без локомотива), мм: 21600
   Суммарное время отпуска тормозов всех вагонов, сек: 79
   Полный вес всех вагонов, кг: 165400

----------------------------------------------------------------
   ИНФОРМАЦИЯ ПО ОТДЕЛЬНЫМ ВАГОНАМ:

   Количество осей:
 № вагона - 30523512 значение - 4
 № вагона - 30523570 значение - 4

   Длина:
 № вагона - 30523512 значение - 10800
 № вагона - 30523570 значение - 10800

   Время отпуска тормозов:
 № вагона - 30523512 значение - 53
 № вагона - 30523570 значение - 26

   Вес вагона:
 № вагона - 30523512 значение - 82700
 № вагона - 30523570 значение - 82700

================================================================


Приглашаю всех, кого интересует подобное введение, к его воплощению. Данный пример - всего лишь заготовка, реальные возможности такого метода намного шире. Приветствуются все пожелания и предложения по повышению эффективности и расширению возможностей.
Сильные люди - это не те, у которых всё хорошо, а те, у которых всё хорошо несмотря ни на что.
Света
 
Аватара пользователя
Разработчик
 
Сообщения: 565
Зарегистрирован:
Баллы репутации: 129
За это сообщение пользователю Света сказали "спасибо":
Dmitryi JD, fav39, le Sandro, Linx, Romazan67, taurus1016

Re: Язык программирования LUA. Скрипты.

Сообщение BooYa » 21 июн 2016, 20:12

Я в деле. Когда будет уже на тестах лок с такой системой, предоставлю вагоны с нужным скриптом. Если результаты всех тестов будут положительные, сделаю патч на своё и RRSное. Заодно и косяк попробуем исправить с тормозами у ботов.
Владение русской орфографией - это как владение кунг-фу, настоящие мастера не применяют его без необходимости.
BooYa
 
Аватара пользователя
Разработчик
 
Сообщения: 140
Зарегистрирован:
Откуда: Екатеринбург
Баллы репутации: 30
За это сообщение пользователю BooYa сказали "спасибо":
Света

Re: Язык программирования LUA. Скрипты.

Сообщение Dmitryi JD » 04 июл 2016, 05:07

Привет,есть такой вопрос.Как написать скрипт для cinematic camera,просто насколько я понял.Сей скрипт нужен только для того что бы активировать камеру.Но самого скрипта найти не могу.Смотрел видео у одного,англоязычного товарища.Нифига не понял.Может кто-то помочь?
Обзор и поск дополнений в Railworks Youtube
Dmitryi JD
 
Аватара пользователя
Специалист
Специалист
 
Сообщения: 216
Зарегистрирован:
Откуда: Россия
Баллы репутации: 5
 
 

Re: Язык программирования LUA. Скрипты.

Сообщение Света » 04 июл 2016, 16:59

На тему cinematic camera можно почитать здесь.
Сильные люди - это не те, у которых всё хорошо, а те, у которых всё хорошо несмотря ни на что.
Света
 
Аватара пользователя
Разработчик
 
Сообщения: 565
Зарегистрирован:
Баллы репутации: 129
За это сообщение пользователю Света сказали "спасибо":
Dmitryi JD

Re: Язык программирования LUA. Скрипты.

Сообщение Dmitryi JD » 08 июл 2016, 02:52

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

--- добавлено позже в 08 июл 2016, 16:28 ---

С грехом пополам,почти разобрался.Но изучать ещё много!.
А от той ссылки на форум,с пояснением толку мало.Новичку в нём не разобраться.Проще самому методом тыка,проб и ошибок.
Нет не одного толкового видео пособия,чтоб посмотреть на практике.Тот скрипт который там выложен,он вообще не работает.Брал скрипт у чехов,он работает.Но проблема в том,что после проезда камеры до конечного пункта.Отрубается всё,HUD и ескейп тоже невозможно нажать,как буд то,что-то блокирует.
Обзор и поск дополнений в Railworks Youtube
Dmitryi JD
 
Аватара пользователя
Специалист
Специалист
 
Сообщения: 216
Зарегистрирован:
Откуда: Россия
Баллы репутации: 5
 
 

Re: Язык программирования LUA. Скрипты.

Сообщение Света » 09 июл 2016, 20:27

[+] Dmitryi JD
Ну это все, что именно я могу предложить :unknown: Я знаю о существовании той статьи, потому даю ссылку, но на практике мне работать с этой камерой не приходилось, потому качество и достоверность этого материала мне не известны.

Всем доброго дня :)

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

[+] совсем чуть-чуть теории
Принцип вычисления тяги заключается в том, что для каждого значения текущей скорости сопоставляется уровень тяги, развиваемой локомотивом. В идеале должно быть столько пар "скорость - тяга", сколько может быть значений скорости, включая дробные значения. Но это очень много, поэтому применяется метод, сходный с усреднением при оцифровке аналогового сигнала. Весь диапазон скорости (от 0 до максимальной) делится на несколько участков (чем больше, тем лучше, как и битрейт). Потом берутся крайние точки скорости по краях участка, рассчитывается, на каком "расстоянии" от меньшего значения находится текущая скорость. Применив значение "расстояния", можно определить, насколько надо сместиться между крайними точками тяги.
Думаю, теории достаточно. Мне трудно передать эти мысли без рисунков, а рисовать, не имея уверенности, что это кому-нибудь действительно интересно, я не очень хочу :oops:

Первопроходец этого метода - Максим ака Supermax. Если я ошибаюсь, поправьте меня, пожалуйста, я исправлю.
Моя роль в этом коде - его упрощение и трансформация в функцию, которую можно без правок использовать в любом скрипте, просто скопировав. Единственное, что надо подгонять в каждом локомотиве - таблицу тяги.

В блоге, ссылку на который я привожу, показано, что собой представляет таблица и какие правки необходимо сделать в файлах Tractive Effort VS Speed , Tractive Effort vs Throttle, поэтому я не буду повторяться.

Вот функция:
Код: Выделить всё
function TractionValue(currentSpeed, PosThrottle)

   local   MaxSpeed = 0
   local   TrDownLim, TrUpLim, SpUpLim, SpDownLim = 0, 0, 0, 0
   local   TractionPercent = 0

   for k,v in ipairs(POS_S[PosThrottle]) do
      if(v ~= nill) then
         MaxSpeed = v
      else
         break
      end
   end

   if currentSpeed < MaxSpeed and PosThrottle > 0 then
      for k,v in ipairs(POS_S[PosThrottle]) do
         if(v < currentSpeed) then
            TrDownLim = POS_T[PosThrottle][k]
            SpDownLim = v
         else
            TrUpLim = POS_T[PosThrottle][k]
            SpUpLim = v
            break
         end
      end
      TractionPercent = (TrDownLim + (1 - (SpUpLim - currentSpeed) / (SpUpLim - SpDownLim)) * (TrUpLim - TrDownLim))
   else
      TractionPercent = 0
   end
   
   return TractionPercent/100
--   Call( "*:SetControlValue", "Regulator", 0, TractionPercent/100);
end


Для использования функции необходимо скопировать её в любое место скрипта. Вызов производится из функции Update. Как правило, в функции Update используются данные о позиции регулятора тяги и о текущей скорости, поэтому я не привожу их вычисление, думаю, за этим дело не станет. Вызывается функция TractionValue(А, В) в зависимости от того, как будет использоваться результат её работы дальше. Если значение сразу передается на системный контрол тяги, то нужно раскомментировать строку
Код: Выделить всё
Call( "*:SetControlValue", "Regulator", 0, TractionPercent/100);
и закомментировать ту, что выше. Тогда вызов имеет такую форму:
Код: Выделить всё
 TractionValue(А, В)
где А - это текущая скорость, В - позиция.

Если же дальше надо будет проводить ещё какие-то вычисления (шунтирование, блокировки или т.п.), то функцию править не надо, а вызов будет иметь такую форму:
Код: Выделить всё
 local Tr_Percent = TractionValue(А, В)
где Tr_Percent - результат вычисления, который возвращается. А - это текущая скорость, В - позиция.

В процессе работы функция использует массивы пар "скорость - тяга", которые нужно составить к конкретной модели по её графику ТХ. Структуру функции, содержащей эти, а также вспомогательные таблицы, я представляю на примере разработанной мной к ТЭМ2:
Код: Выделить всё
function TractionValueTab()

POSITION1_S = {0,   2,      4,      6,      8,      10}
POSITION1_T = {12,   8.5,   5.7,   2.8,   1.4,   0}

POSITION2_S = {0,   2,      4,      6,       8,       10,      15,      20}
POSITION2_T = {24,   19,      14.2,   10,      7,      3.5,   1.4,    0}

POSITION3_S = {0,   2,      4,      6,       8,       10,      15,      20}
POSITION3_T = {75,   48.5,   20,      14,      8.5,   4.2,   1.5,   0}

POSITION4_S = {0,   2,      4,      6,       8,       10,      15,      20,      30,      40}
POSITION4_T = {100,   53.5,   36,      25,      21.4,   14,      10,      6.4,   3.2,   0}

POSITION5_S = {0,   2,      4,      6,       8,       10,      15,      20,      30,      40,      50,      60}
POSITION5_T = {100,   100,   50,      45,      35.7,   21.4,   15,      11.4,   8.5,   5.7,   3.5,   0}

POSITION6_S = {0,   2,      4,      6,       8,       10,      15,      20,      30,      40,      50,      60,      70}
POSITION6_T = {100,   100,   92,      70,      50,      32,      24,      15.7,   11.4,   8.6,   5.7,   2.1,   0}

POSITION7_S = {0,   2,      4,      6,       8,       10,      15,      20,      30,      40,      50,      60,      70}
POSITION7_T = {100,   100,   100,   82,      66,      37,      30,      22.8,   15,      10.7,   7.7,   3,      0}

POSITION8_S = {0,   2,      4,      6,       8,       10,      15,      20,      30,      40,      50,      60,      70}
POSITION8_T = {100,   100,   100,   90,      67,      45,      35.7,   23.5,   17.1,   13.5,   10,      5,      0}

POS_S = {POSITION1_S, POSITION2_S, POSITION3_S, POSITION4_S, POSITION5_S, POSITION6_S, POSITION7_S, POSITION8_S}
POS_T = {POSITION1_T, POSITION2_T, POSITION3_T, POSITION4_T, POSITION5_T, POSITION6_T, POSITION7_T, POSITION8_T}
end

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

В ТЭМ2 8 позиций, поэтому здесь 8 пар массивов "скорость - тяга", по одной паре массивов на каждую позицию. Последние 2 таблицы (POS_S и POS_T) - это ссылки на конкретные массивы в зависимости от того, номер какой позиции был передан при вызове функции TractionValue(А, В).
Функция TractionValueTab() вставляется в скрипт ниже функции TractionValue(А, В).
Сильные люди - это не те, у которых всё хорошо, а те, у которых всё хорошо несмотря ни на что.
Света
 
Аватара пользователя
Разработчик
 
Сообщения: 565
Зарегистрирован:
Баллы репутации: 129

Re: Язык программирования LUA. Скрипты.

Сообщение Dmitryi JD » 09 июл 2016, 20:34

Да нет Светлана,всё нормально.Спасибо за наводку,я ещё раз немного почитал и понял где я совершал ошибки,там еще с бинарниками надо было разобраться.и привязка камеры к сценарию,а не просто тупо написать скрипт как я делал.Ну как говорится,на ошибках учатся.Просто это мои первые шаги,к познанию работы скриптов.
Обзор и поск дополнений в Railworks Youtube
Dmitryi JD
 
Аватара пользователя
Специалист
Специалист
 
Сообщения: 216
Зарегистрирован:
Откуда: Россия
Баллы репутации: 5
 
 

Re: Язык программирования LUA. Скрипты.

Сообщение djus » 10 июл 2016, 16:17

Dmitryi JD.С камерой в сценариях всё достаточно просто,ни каких скриптов писать не надо,достаточно скопировать 3 файла
(ScenarioScript.lua : ScenarioScript.luac : ScenarioScript.luac.MD5) в папку сценария.
Причём скрипты стандартные подходят для всех маршрутов,проверял сам на 10 сценах.
Скачать можно Тут

Далее ставишь камеру в сцене, и называешь её camera1
Изображение

Идёшь в меню расписания,выбираешь (Триггер инструкция. -1)
В меню инструкции находишь поле (триггер событие. -2) пишешь camcamera1
Изображение
Всё должно летать :)
Это пример вступления,вариантов много подробнее Вот.
Отдельный Респект автору статьи sergz692
djus
 
Аватара пользователя
Специалист
Специалист
 
Сообщения: 268
Зарегистрирован:
Откуда: Объект 19
Баллы репутации: 21
За это сообщение пользователю djus сказали "спасибо":
Dmitryi JD

Re: Язык программирования LUA. Скрипты.

Сообщение Dmitryi JD » 10 июл 2016, 16:29

djus писал(а):Dmitryi JD.С камерой в сценариях всё достаточно просто,ни каких скриптов писать не надо,достаточно скопировать 3 файла
(ScenarioScript.lua : ScenarioScript.luac : ScenarioScript.luac.MD5) в папку сценария.
Причём скрипты стандартные подходят для всех маршрутов,проверял сам на 10 сценах.
Скачать можно Тут

Далее ставишь камеру в сцене, и называешь её camera1
Изображение

Идёшь в меню расписания,выбираешь (Триггер инструкция. -1)
В меню инструкции находишь поле (триггер событие. -2) пишешь camcamera1
Изображение
Всё должно летать :)
Это пример вступления,вариантов много подробнее Вот.
Отдельный Респект автору статьи sergz692



Спасибо.Просто смотрел видео,а видео англоязычное и половина непонятно.Но всё равно скрипт по любому надо по изучать...Сейчас попробую и отпишусь.

--- добавлено позже в 10 июл 2016, 16:49 ---

Ещё раз отдельная благодарность,протестировал.Все работает на ура.С этим всё понятно,теперь осталось научится править камеру в кабине локомотива.
Обзор и поск дополнений в Railworks Youtube
Dmitryi JD
 
Аватара пользователя
Специалист
Специалист
 
Сообщения: 216
Зарегистрирован:
Откуда: Россия
Баллы репутации: 5
 
 
За это сообщение пользователю Dmitryi JD сказали "спасибо":
djus

Re: Язык программирования LUA. Скрипты.

Сообщение Света » 16 авг 2016, 15:44

Всем доброго дня :)

Представляю вниманию разработчиков функцию Timer, предназначенную для вставки в скрипт.

[+] Назначение
Функция предназначена упростить контроль временных интервалов в процессе выполнения кода. Каждый, кто писал скрипт, знает, что для того, чтобы сделать задержку, нужно создать переменную, поместить в неё значение задержки, потом периодически вычитать из этой переменной какое-то число, отслеживая, когда значение задержки станет равным или меньше нуля.
Дополнительное неудобство - если до окончания отсчета эту переменную заново перезапустить, отсчет начнется сначала. Чтобы этого избежать, приходится выдумывать новые защитные переменные.
Когда такой "таймер" использован, он продолжает опрашиваться ЦП, хотя в этом нет необходимости.
Каждый такой таймер (а их в скрипте локомотива предостаточно) - это дополнительный множитель всех неудобств, описанных выше.
Мне это надоело. Предлагаемая функция предназначена несколько упростить эту процедуру.

[+] Адаптация в скрипт
Функция вставляется в конец скрипта. Никакие подгонки/правки не нужны.

Для инициализации рабочей таблицы, вписываем её в функцию Initialise():
Код: Выделить всё
TabTimerData = {}

Для обеспечения счёта периодически делаем вызов из функции Update ( time ):
Код: Выделить всё
 Timer (time)

Всё, таймер прописан и готов к работе.

[+] Использование/вызов
Для того, чтобы создать канал таймер, надо придумать ему любое имя и отправить его в функцию (например, timer_1)вместе со значением нужной задержки в секундах (например, 15 сек):
Код: Выделить всё
Timer ("timer_1", 15)

Важно: пока таймер отсчитывает выдержку, его рестарт такой командой невозможен. Это сделано умышленно. Если нужно перезапустить отсчет сначала, применяется другая команда:
Код: Выделить всё
Timer ("timer_1", 15, "restart")

Контролировать окончание отсчета можно 2 способами. Первый способ - это контроль фактического окончания отсчета. Вариант использования:
Код: Выделить всё
   if Timer ( "timer_1" ) then
      -- блок операторов, если время вышло
   else
      -- блок операторов, если отсчет не завершен
   end

Обратите внимание - если опрашивается несуществующий канал таймера, функция также возвратит "false", как и при незавершенном отсчете.
Второй способ - контроль времени, которое осталось до окончания отсчета. Вариант использования:
Код: Выделить всё
   Pause = Timer ("timer_1", "ctrl")

В переменную Pause будет загружено оставшееся время (сек) в числовом формате. Если отсчет закончился, будет загружена строка "timeroff". В случае опроса несуществующего канала будет возвращено значение "nil".

Если необходимости в каком-либо канале таймера нет, его можно разрушить:
Код: Выделить всё
   Timer ("timer_1", "clear")

Такая команда уничтожит канал "timer_1". Это сэкономит время, затрачиваемое на обработку.
Автоматического удаления каналов с завершенным отсчетом нет.

Количество каналов ограничено объемом оперативной памяти.
Разрешающая способность (сек, грубо) - 1/fps.

Сам код:
Код: Выделить всё
function Timer (data_1, data_2, data_3)
   if type(data_1) == "number" then
      for k,v in pairs(TabTimerData) do
         if type(v) ~= "string" then
            v = v - data_1
            if v <= 0 then
               TabTimerData[k] = "timeroff"
            else
               TabTimerData[k] = v
            end
         end
      end
      return
   end

   if type(data_1) == "string" then
      if not data_2 then
         if TabTimerData[data_1] == "timeroff" then
            return true
         else
            return false
         end
      elseif data_2 == "ctrl" then
         return TabTimerData[data_1]
      elseif data_2 == "clear" then
         TabTimerData[data_1] = nil
      elseif not TabTimerData[data_1] or TabTimerData[data_1] == "timeroff" or data_3 == "restart" then
         TabTimerData[data_1] = data_2
      end
   end
end


Приветствуются пожелания по усовершенствованию. Также, несмотря на успешное тестирование, приветствуется любая информация по практическому использованию функции.
Сильные люди - это не те, у которых всё хорошо, а те, у которых всё хорошо несмотря ни на что.
Света
 
Аватара пользователя
Разработчик
 
Сообщения: 565
Зарегистрирован:
Баллы репутации: 129
За это сообщение пользователю Света сказали "спасибо":
Linx, taurus1016, Витя

Re: Язык программирования LUA. Скрипты.

Сообщение Света » 11 окт 2016, 20:08

Всем доброго дня :)

Представляю вниманию разработчиков скрипт, назначение которого - определять положение дополнительных секций локомотивов относительно секции игрока.
[+] зачем это?
Скриптеры знают, что обмен информацией между единицами ПС происходит пересылкой сообщений. Но у этого метода есть большой недостаток. Если наш локомотив получает сообщение, невозможно определить, на каком расстоянии находится отправитель и есть между локомотивами вагоны или локомотивы имеют прямой контакт.
Этот недостаток может проявится в том, что если сделать передачу, например, температуры масла из второй секции на первую для отображения на термометре, то при штатной сцепке локомотивов система будет работать корректно, а при добавлении вагона между ними (маловероятно) или третьей секции система даст сбой. Например, как определить, из какой секции ловить сообщения, если слать будут обе?
Одно из решений - заблокировать весь набор сообщений обмена в вагонах. Это решило бы проблему, если бы для этого не пришлось перелопатить скрипты всех(!) существующих вагонов.
Эта проблема побудила меня написать скрипт, который помогает определить секции, которые находятся непосредственно возле управляющего локомотива. При этом править сторонние дополнения нет необходимости, так как основным критерием является расстояние между секциями.


[+] подготовка модели
В функциях определения положения применен принцип вычисления расстояний между координатами ключевых точек локомотива. Соответственно, необходимо создать простые дочерние объекты и расположить их впереди и сзади модели.
Идеальный вариант - замки сцепок. На испытаниях использовались координаты лампочек АЛСН, сбоев также не было. Хотя, точность незначительно ухудшается. Координаты этих элементов и будут использоваться при расчете.

*Желательно, чтобы у сцепленных секций эти элементы находились как можно ближе друг к другу, иначе возможна ошибка, когда измерение произойдет в тот момент, когда они будут в разных тайлах. Событие редкостное, но возможное.


[+] Подключение скрипта
Файл "LOCOMOTIVES_LOCATION" размещается в папке Engine дополнения. В основном скрипте в функции Initialise необходимо сделать ссылку:
Код: Выделить всё
   require ("Assets/[...]/Engine/"LOCOMOTIVES_LOCATION.lua")

Если используется скомпилированный файл, .lua заменяется на .out.

Для инициализации скрипта в функции Initialise создается вызов:
Код: Выделить всё
   SetupControlLink ()


Также необходимо заменить имена дочерних элементов на имеющиеся у Вашей модели:
Код: Выделить всё
      XF, _, YF = Call("1-pointlight_alsn-white-l:getNearPosition")
      XR, _, YR = Call("2-pointlight_alsn-white-r:getNearPosition")

Соответственно "1-pointlight_alsn-white-l" заменить на дочерний элемент, расположенный спереди, а "2-pointlight_alsn-white-r" - сзади.

Для получения нужных данных добавляем обработчик сообщений в OnConsistMessage ( msg, argument, direction ):
Код: Выделить всё
   if msg == POSITION_DATA then
      ControlLink ("Update", argument)
      return
   end


Ну и надо передавать свои данные. Для этого я использую проверку длины состава - ведь это значение меняется при сцепке/расцепке, этого момента вполне достаточно, чтобы составить схему состава, которая не изменится пока снова не прицепить/отцепить что-нибудь. Нет смысла делать эти замеры чаще:
Код: Выделить всё
function Update ( time )
   local Length = Call("GetConsistLength")
   if Length ~= prevLength then
      prevLength = Length
      ControlLink ("Update")
   end
end

*Переменную prevLength необходимо проинициализировать в функции Initialise ()


[+] Использование
Управляющие коды для LOCOMOTIVES_LOCATION:
Код: Выделить всё
   ControlLink ("Update")

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

Код: Выделить всё
   ControlLink ("Update", argument)

Обновление, но без рассылки. Команда предназначена для установки в функцию OnConsistMessage ( msg, argument, direction ) (описано выше) и рассчитана на прием отформатированных данных. Поэтому в других местах не используется.

Код: Выделить всё
   ControlLink ("GetLocoPosition", data)

Самая ходовая команда. Передается имя ПС, расположение которого надо распознать. Именем является № ПС, заданный в свойствах сценария.
Результатом выполнения этой команды будет возврат 1 из 5 возможных ответов:
- false - если проверяемый ПС не сцеплен с нашим, ответ будет такой;
- ff - этот ответ означает, что локомотивы сцеплены передними частями;
- fr - перед нашего локомотива сцеплен с задом проверяемого;
- rf - зад нашего локомотива сцеплен с передом проверяемого;
- rr - локомотивы сцеплены штатно.
Например, если надо проверить, может ли ПС, передавший данные о температуре и свое имя (ID), проверка выглядит так:
Код: Выделить всё
      if ControlLink ("GetLocoPosition", "ID") == "rr" then
         -- Да, данные температуры можно использовать
      else
         -- Нет, ПС или далеко (не сцеплен с нашим локомотивом) или ориентирован неправильно
      end

Естественно, для правильной работы ПС, передающий данные температуры должен передать и своё имя, которое надо отделить.


В настройках заданы константы:
Код: Выделить всё
-- Constants
   POSITION_DATA = 1818190202
   MAX_DISTANSE = 10

POSITION_DATA - это метка сообщения обмена, которое инициирует запуск определителя. На данный момент не является стандартизированным.
MAX_DISTANSE - это максимальное расстояние. Если расстояние между самыми близкими точками ПС превышает это число, принимается решение, что эти ПС не сцеплены. Число "10" выбрано исходя из соображений, что длина самого короткого вагона больше 10 метров.

Скрипт оттестирован. Тем не менее, приветствуется информация по результатах практического применения этого кода :)
Сильные люди - это не те, у которых всё хорошо, а те, у которых всё хорошо несмотря ни на что.
Света
 
Аватара пользователя
Разработчик
 
Сообщения: 565
Зарегистрирован:
Баллы репутации: 129
За это сообщение пользователю Света сказали "спасибо":
Витя

Re: Язык программирования LUA. Скрипты.

Сообщение Света » 05 ноя 2016, 12:34

Всем доброго дня :)

Очередная заготовка, облегчившая мне написание скрипта, которой я хочу поделиться. Это скрипт-модуль, предназначенный для управления яркостью источниками света (ИС).

[+] назначение
Управлять яркостью ИС можно, воздействуя на параметры каналов цветности RGB. Если установить значение всех каналов в 0, источник будет полностью погашен, если же в значения, заданные в конфиге ИС - будет светить максимально заданной яркостью и цветом.
Установкой значений RGB в промежуточные значения можно изменять яркость ИС от 0 до максимума.

Основные, ИМХО, трудности в этом методе управления:
1. Значения каналов одной модели практически всегда различные. Для того, чтобы при изменении яркости ИС не потерять баланс (и цвет), все значения каналов нужно изменять синхронно и пропорционально.
2. Необходимо иметь точные данные о установленных в конфиге значениях RGB - это определяет максимальные уровни яркости и цветовой баланс.
3. Управление ИС таким методом подразумевает отсчет временных интервалов. А это автоматически требует создания счетчиков-переменных, их инкрементирование/декрементирование, слежение за результатом, разрешение/запрет перезапуска и другие "прелести" ручной таймеризации в программе.
4. Нельзя обойтись без защитных механизмов, которые заблокируют обработку ИС в случае серии однотипных команд (если, например, будет сформировано 10 команд "выключить ИС", то должна обработаться только первая, остальные должны игнорироваться, причем, чем раньше, тем оптимальнее.
5. Все вышеуказанное требует создания достаточно запутанной схемы, которая для одного ИС ещё приемлема, но с увеличением количества ИС сложность и запутанность растет в разы.

Эти моменты побудили меня разработать логически завершенный блок, который взял бы всю нагрузку на себя. Возможность изменять яркость ИС вызвала желание сделать этот процесс плавным и управляемым по времени. Это получилось. К тому же, мне хотелось сделать простым добавление новых ИС под его "опеку". Это мне также удалось.

[+] принцип работы
При запуске программы в функции StartSetupLight () происходит начальная инициализация всех переменных. Также, используя данные из таблицы TabNames (где перечислены имена конфигов ИС как дочерних элементов), производится поиск и загрузка ключевых данных (в данном случае значения RGB).
Также создаются таблицы, используемые в процессе работы.
Одна из таблиц - LampSpeed. Здесь размещены имена ИС и их время на включение (ig) и выключение (qu) в нормальных условиях.

Для того, чтобы сделать управление каналами ИС пропорциональным и синхронным, логично использовать один множитель, который изменял бы свое значение от 0 до 1 и на который в процессе обработки следует умножать максимальное значение каждого канала.
Это переменная factor. По сути, её значение (от 0 до 1) определяет состояние ИС от полностью выключенного до включенного на полную яркость. Это значение постоянно хранится в таблице LampData.Factor_c[_имя ИС_] (c = current = "текущий").

Для того, чтобы один блок мог обрабатывать неограниченное количество ИС и при этом был независим от их параметров, обработчик использует формулу, в которую подставляет все данные.

Логически блок обработчика состоит из двух веток: function Lamp_Set (name, level, time) (эта функция запускает процесс изменения яркости) и function LampUpdate (time) (обработка изменения ИС во времени).

Lamp_Set (name, level, time)
При вызове этой функции первым делом подгружается текущее состояние ИС и сравнивается с заданным при вызове. Если эти значения равны (дубль команды), происходит завершение запуска обработки. В противном случае производится перезапуск ИС.
Для того, чтобы перезапустить ИС, сначала сравниваются текущее состояние и заданное. Это указывает, в какую сторону надо изменять factor - увеличивать или уменьшать яркость. Затем создаются контрольные точки - текущее состояние сохраняется как начальная точка (LampData.Factor_a[ch_n]), а требуемый уровень (level) - как конечная (LampData.Factor_b[ch_n]). Далее запускается таймер - на время, заданное в команде, или, если время не задано - на время по умолчанию, указанное в таблице LampSpeed. Дефолтное время также будет загружено в том случае, если значением time будет "none".
Также сбрасывается флаг LampSet - это будет свидетельствовать, что есть ИС, требующий обработку.

LampUpdate (time)
В первую очередь проверяется состояние флага LampSet. Если он установлен, это значит, что все ИС в статичном состоянии. В обработке нет необходимости, поэтому выход.
Если же флаг сброшен, значит есть как минимум 1 ИС, требующий просчета. В таком случае первым делом флаг LampSet устанавливается (авансом, чтобы если это ложный сбой, то при следующем входе в эту функцию не отрабатывать её снова) и запускается цикл, который последовательно переберет все ИС, прописанные в таблице TabNames.
В процессе перебора для каждого ИС считывается его состояние, если ИС статичен (status = "on" или status = "off"), этот ИС не обрабатывается. Иначе флаг LampSet сбрасывается (подтверждая, что есть необработанные ИС), и, в зависимости от статуса ИС ("ignition" или "quenching", то есть увеличение или снижение яркости) выполняется необходимая ветка, где на основании состояния таймера и ключевых точек производится расчет нового значения множителя factor. Если нужная точка яркости достигнута, это отмечается в статусе ИС, а канал таймера уничтожается за ненадобностью.
Дальше максимальные значения каналов цвета умножаются на множитель и передаются движку на управление ИС. Новое состояние ИС сохраняется.

Примечания
1. Количество подконтрольных ИС ограничено только здравым смыслом;
2. Яркость ИС можно "сдвинуть" в любую сторону в пределах от 0 до 1 (от минимума к максимуму) независимо от текущего;
3. Яркость может изменяться с любой скоростью, а если скорость не задана (или = "none"), подхватывается дефолтное значение;
4. Если все ИС статичны, обрабатывается всего 2 строки функции LampUpdate (time) за кадр;
5. Время изменения яркости стабильно, не зависит от fps. Но на очень слабых ПК не исключено ступенчатое изменение яркости;
6. Главный недостаток обработчика - время изменения яркости не зависит от начального состояния ИС. То есть, при заданном по умолчанию времени на выключение 0.2 сек, ИС будет выключатся именно 0.2 секунды, независимо от того, включен он на полную яркость или на 50%. Мне это не показалось критичным. В то же время, это исправимо;
7. Все ИС совершенно независимы друг от друга.

[+] подключение к скрипту и подготовка к использованию
Модуль можно разместить в любом удобном месте. В основном скрипте делается его подключение:
Код: Выделить всё
require "Assets/[...]/light_driver_script_v21.lua"
Если модуль скомпилирован, *.lua заменить на *.out.

В функцию инициализации основного скрипта необходимо вписать вызов функции инициализации:
Код: Выделить всё
StartSetupLight ()

А в функцию Update (time) вписать вызов функций таймера и обработчика:
Код: Выделить всё
   LampUpdate (time)
   Timer (time)


Дальше необходимо заполнить таблицу TabNames информацией о используемых ИС. Первое поле таблицы - это имя ИС, которое будет использоваться в командах. Любое удобное. Второе поле - это имя чайлда, задаётся в блоке child в поле "ChildName" основного конфига.
Затем для всех перечисленых в TabNames ИС нужно указать время на розжиг и на гашение в таблице LampSpeed.

В качестве примера я привожу 2 ИС, которые имеют имена в конфиге "Light_1" и "Light_2", я их буду называть в скрипте как Lampa_1 и Lampa_2, время розжига у обеих 0.2 сек, гашения - 0.3.

[+] использование
Для управления ИС используется вызов
Код: Выделить всё
   Lamp_Set (name, level, time),
где
   name - имя ИС, заданное Вами;
   level - требуемый уровень яркости, от 0 до 1;
   time - время, отведенное на это.


Время задается в секундах, допускаются дробные значения. Если время не задано или указан параметр "none", будет использовано время, заданное по умолчанию.


В модуле использована функция Timer (data_1, data_2, data_3), описанная мной раньше. Если Вы уже использовали её у себя, из модуля её нужно удалить. Это строки 21, 131 - 168.
Использование таймера не ограничивается только управлением ИС, его можно применять для контроля времени в других частях скрипта. Подробнее здесь.

Скрипт оттестирован.
За помощь в разработке формулы искренне благодарю пользователя maestro.
Также за поддержку и тестирование благодарю пользователя Cross.

С благодарностью приму советы, отзывы и пожелания.
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Сильные люди - это не те, у которых всё хорошо, а те, у которых всё хорошо несмотря ни на что.
Света
 
Аватара пользователя
Разработчик
 
Сообщения: 565
Зарегистрирован:
Баллы репутации: 129
За это сообщение пользователю Света сказали "спасибо":
Cross, le Sandro, Гидростроитель, Витя

Re: Язык программирования LUA. Скрипты.

Сообщение Света » 04 дек 2016, 10:48

Всем доброго дня :)

Представляю вниманию разработчиков дополненную функцию TIMER v2.0, предназначенную для вставки в скрипт.

С назначением и общим описанием функции можно ознакомиться здесь.
Отличие от первой версии: добавлен режим остановки счета (пауза).

[+] Адаптация в скрипт
Функция вставляется в конец скрипта. Никакие подгонки/правки не нужны.

Для инициализации рабочих таблиц, вписываем их в функцию Initialise():
Код: Выделить всё
-- Data TIMER
TabTimerData = {}
TabTimerStatus = {}


Для обеспечения счёта периодически делаем вызов из функции Update ( time ):
Код: Выделить всё
 Timer (time)

Всё, таймер прописан и готов к работе.

[+] Использование/вызов
Для того, чтобы создать канал таймер, надо придумать ему любое удобное имя и отправить запрос в его функцию (например, timer_1) вместе со значением нужной задержки в секундах (например, 15 сек):
Код: Выделить всё
Timer ("timer_1", 15)

Важно: пока таймер отсчитывает выдержку, его рестарт такой командой невозможен. Это сделано умышленно. Если нужно перезапустить отсчет сначала (а также снять таймер с паузы с обновлением задержки), применяется другая команда:
Код: Выделить всё
Timer ("timer_1", 15, "restart")

Контролировать окончание отсчета можно 2 способами. Первый способ - это контроль фактического окончания отсчета. Вариант использования:
Код: Выделить всё
   if Timer ( "timer_1" ) then
      -- блок операторов, если время вышло
   else
      -- блок операторов, если отсчет не завершен
   end

Обратите внимание - если опрашивается несуществующий канал таймера, функция также возвратит "false", как и при незавершенном отсчете.
Второй способ - контроль времени, которое осталось до окончания отсчета. Вариант использования:
Код: Выделить всё
   Pause = Timer ("timer_1", "ctrl")

В переменную Pause будет загружено оставшееся время (сек) в числовом формате. Если отсчет закончился, будет загружена строка "timeroff". В случае опроса несуществующего канала будет возвращено значение "nil".

Если необходимости в каком-либо канале таймера нет, его можно разрушить:
Код: Выделить всё
   Timer ("timer_1", "clear")

Такая команда уничтожит канал "timer_1". Это сэкономит время, затрачиваемое на обработку.
Автоматического удаления каналов с завершенным отсчетом нет.

Если надо остановить отсчет, используем команду
Код: Выделить всё
   Timer ("timer_1", "pause")

Для продолжения отсчета используем команду
Код: Выделить всё
   Timer ("timer_1", "run")
или 
   Timer ("timer_1", время, "restart")

Количество каналов ограничено объемом оперативной памяти.
Разрешающая способность (сек, грубо) - 1/fps.

Сам код:
Код: Выделить всё
function Timer (data_1, data_2, data_3)
   if type(data_1) == "number" then
      for k,v in pairs(TabTimerData) do
         if type(v) ~= "string" and TabTimerStatus[k] then
            v = v - data_1
            if v <= 0 then
               TabTimerData[k] = "timeroff"
            else
               TabTimerData[k] = v
            end
         end
      end
      return
   end

   if type(data_1) == "string" then
      if not data_2 then
         if TabTimerData[data_1] == "timeroff" then
            return true
         else
            return false
         end
      elseif data_2 == "ctrl" then
         return TabTimerData[data_1]
      elseif data_2 == "clear" then
         TabTimerData[data_1] = nil
      elseif data_2 == "pause" then
         TabTimerStatus[data_1] = false
      elseif data_2 == "run" then
         TabTimerStatus[data_1] = true
      elseif not TabTimerData[data_1] or TabTimerData[data_1] == "timeroff" or data_3 == "restart" then
         TabTimerData[data_1] = data_2
         TabTimerStatus[data_1] = true
      end
   end
end



Приветствуются пожелания по усовершенствованию. Также, несмотря на успешное тестирование, приветствуется любая информация по практическому использованию функции.

Версия 2.0 успешно заменяет версию 1.0 без дополнительных правок скрипта :)
Сильные люди - это не те, у которых всё хорошо, а те, у которых всё хорошо несмотря ни на что.
Света
 
Аватара пользователя
Разработчик
 
Сообщения: 565
Зарегистрирован:
Баллы репутации: 129
За это сообщение пользователю Света сказали "спасибо":
RetroPaladin, taurus1016, Витя

Пред.

Вернуться в Внутриигровой редактор и разработка дополнений

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1