RSS
[ Главная ] [ Скрипт сценария - FORUM ] [ Регистрация ] [ Вход ]
· Среда, 23.08.2017, 12:49 · Вы вошли как Гость Новые сообщения · Участники · Правила форума · Поиск ·
Страница 1 из 6123456»
FORUM » FORUM » КАРТОСТРОЕНИЕ » Скрипт сценария (Обсуждаем скрипт сценария к карте "Крым")
Скрипт сценария
ДобрыйДата: Воскресенье, 22.12.2013, 17:27 | Сообщение # 1
Чеширский кот
Группа: администраторы
Сообщений: 2246
Статус: Offline
Для желающих освоить написание собственного скриптованного сценария, открываю новую тему.
Итак, основной цикл сценария построен на простом принципе: изначально станциям на карте присваиваются порядковые номера, а входные (или выходные) стрелки станций используются в качестве триггеров, при проезде которых поездом происходит изменение счётчика пройденных станций на единицу. При достижении последней станции цикл подсчёта прекращается, сценарий заканчивается.
Для примера рассмотрим участок Владиславовка-Крым. Владиславовка имеет номер 0, Крым - 9. При выборе поезда сразу же ему присваивается станция отправления (переменная st) и станция прибытия (переменная im). То есть для поезда из Крыма во Владиславовку st=9, im=0, а из Владиславовки в Крым st=0, im=9.
Дальше запускается цикл движения. Для его правильной работы необходимо заранее программе пояснить, в каком направлении (на увеличение или уменьшение) надо считать станции.
Пишем if (st<im) nap=true; else nap=false; ii=st;
В переводе на человеческий язык это означает: если номер станции отправления меньше номера станции прибытия, то направление нечётное (на увеличение), иначе - чётное (на уменьшение). Поскольку цикл будет изменять переменную ii, то присваиваем ей значение номера станции отправления (ii=st).
Дальше запускаем цикл
while(ii!=im) {                          // пока номер станции в переменной ii не сравняется с номером конечной станции im, цикл не закончится
        if (nap==true) ++ii; else --ii;  // если направление нечётное, увеличиваем значение ii на единицу, иначе - уменьшаем на единицу
                    }
Вот, собственно, и вся идея такого скрипта. Всё остальное - это вспомогательные действия по отношению к основному циклу.


Вечным двигателям - вечные тормоза!
 
ДобрыйДата: Воскресенье, 22.12.2013, 19:13 | Сообщение # 2
Чеширский кот
Группа: администраторы
Сообщений: 2246
Статус: Offline
Теперь ответ на вопрос, как действует механизм отслеживания движения поезда. Очень просто.
Внутрь уже написанного нами цикла вставляем Navigate.OnJunction (me,Mytrain,junout,4); Получиттся:
while (ii!=im) {
            Navigate.OnJunction (me, Mytrain, junout, 4);

            if (nap==true) ++ii; else --ii;
                    }
Это работает так.  Navigate.OnJunction - это дефолтная команда языка Трайнза, означает, что программа будет ждать проследования определённым поездом определённой стрелки, какой именно - пишем в скобках. Там Mytrain - заранее заданное имя поезда (любое сочетание букв и цифр по вкусу автора), junout - имя переменной (можно придумать самому), которой будет присваиваться значение очередной стрелки. Последний знак в выражении - это цифры от 0 до 4, нам потребуются только 0 (наезд локомотива на стрелку) или 4 (поезд полностью проследовал стрелку).
То есть, фактически у нас в течении цикла будет меняться только значение переменной junout, ведь на каждой станции своя нумерация стрелок. Для того, чтобы максимум упростить скрипт, необходимо уже при строительстве карты сделать так, чтобы первая входная стрелка в нечётном направлении имела в названии 1, а первая с чётного - 2.
В конкретном примере скрипта заранее создан массив, перечисляющий буквенное значение стрелок соответствующих станций
string [] jun  = new string [10];
jun [0]="e";  jun [1]="p"; jun [2]="s"; jun [3]="t"; jun [4]="u"; jun [5]="v"; jun [6]="w"; jun [7]="z"; jun [8]="n"; jun [9]="r";
Напомню, что 0 - это Владиславовка и далее по порядку все станции до Крыма (9).
Для того, чтобы программе было понятно имя стрелки, за проездом которой надо следить, присваиваем значение переменной junout:


Вечным двигателям - вечные тормоза!
 
ДобрыйДата: Воскресенье, 22.12.2013, 19:36 | Сообщение # 3
Чеширский кот
Группа: администраторы
Сообщений: 2246
Статус: Offline
If (nap==true) junout=jun[ii]+"2"; else junout=jun[ii]+"1"; опять в зависимости от того, в каком направлении мы едем, и будет задаваться имя стрелки. Например, если мы едем в чётном направлении и подъезжаем к 4 станции, переменная junout примет значение jun[4]+"1", то есть получится имя стрелки "u1", которая действительно существует на карте. Вставляем наше дополнительное условие в ранее написанный цикл вот так:
while (ii!=im) {
            If (nap==true) junout=jun[ii]+"2"; else junout=jun[ii]+"1";
            Navigate.OnJunction (me, Mytrain, junout, 4);
            if (nap==true) ++ii; else --ii;
                        }

Теперь алгоритм работы выглядит так (по строкам):
1) запускаем цикл;
2) присваиваем переменной junout имя последней (по нашему ходу) стрелки на станции, где сейчас находимся (переменная ii);
3) ждём проезда поездом заданной стрелки;
4) после проезда стрелки изменяем значение переменной ii на единицу - получаем номер следующей станции;
5) цикл повторяется, пока переменная ii не станет равной номеру последней станции (im).


Вечным двигателям - вечные тормоза!
 
kukaДата: Вторник, 24.12.2013, 15:01 | Сообщение # 4
Группа: модераторы
Сообщений: 1386
Статус: Offline
Я так понимаю, что состав находящийся на станции (на которой я хочу отправиться) и есть станция 0. А как быть со светофором, который может быть закрыт...  Т.е. как заставить его открыть движение на разрешающий сигнал... И отклонение по стрелкам не понял (в четном направлении + а в нечетном -)...
 
ДобрыйДата: Вторник, 24.12.2013, 17:13 | Сообщение # 5
Чеширский кот
Группа: администраторы
Сообщений: 2246
Статус: Offline
Если сигнализация z7, то светофор должен открыться, если перед ним стоит состав с машинистом в том же направлении и собран маршрут (этот светофор видит следующий). Для надёжного открывания светофора (скажем, после маневров), есть такая фишка:
PostMessage (Router.GetGameObject ("10ss"), "CTRL", "MayOpen^true", 40);
где: "10ss" - имя светофора. который реально есть на карте (имя объекта как триггера, а не как светофора z7!!!), вместо имени в кавычках может быть переменная типа string; "CTRL", "MayOpen^true" - переводит светофор в предоткрытое состояние (вместо этого может быть задано "CTRL", "MayOpen^false" - отключает режим предоткрытия или "CTRL", "ShuntMode.true" - переводит светофор в маневровый режим); 40 - это просто количество секунд, на которые нужно задержать исполнение команды (может быть и 0).
Если прописать в эту строку несуществующее имя светофора, Трайнз начнёт зависать, так что аккуратнее!
По стрелкам. В начале класса задаём функцию переключения стрелки
void ChangeJunc (string jName, int dir) {Navigate.LockJunction (jName, dir, true);}
что позволяет в дальнейшем в по мере надобности двигать стрелки, вызывая эту функцию. Например, ChangeJunc ("ff107",0);
Здесь "ff107" - имя стрелки (тут можно писать переменную типа string), 0 - переключение стрелки влево (если написать 2, будет вправо).
При унивесализации скрипта вместо цифры можно писать переменную типа int, соответственно меняя её значение в случае необходимости.


Вечным двигателям - вечные тормоза!
 
toltekДата: Вторник, 24.12.2013, 22:45 | Сообщение # 6
Группа: участники
Сообщений: 70
Статус: Offline
Добрый, ещё в начале скрипта у тебя есть интересная нить JunThread(). В принципе я уже почти полностью разобрался, хочу просто уточнить. Получается, что переменная puin - это в любом случае первая горловина станции в нечётном направлении? Просто раньше я думал что она будет первая в зависимости от значения nap.
А puvs, puvsw и pupop получается ты прописывал отдельно для каждой станции и в зависимости от ситуации на ней?


Если тело пердит, значит оно живое!
Trainz 2010 build 49933
 
ДобрыйДата: Среда, 25.12.2013, 11:24 | Сообщение # 7
Чеширский кот
Группа: администраторы
Сообщений: 2246
Статус: Offline
toltek, не знаю, как сейчас, а раньше у дежурного по станции на пульте были кнопки установки стрелок в + или -, а под ногой - педаль, которая разом собирала весь маршрут (переводила стрелки в натуре). Аналогичным образом работает и скрипт.
Нить JunThread() запускается для переключения стрелок "в натуре", когда маршрут уже задан (то есть аналог педали дежурного). А вот задание маршрута гораздо сложнее.
puin - это номер пути для прибывающего поезда, puout - это номер пути для уходящего поезда (т.е. входные/выходные стрелки собирают маршрут на этот путь). Если у нас поезд идёт на проход, puin = puout. Но ведь поездов много, как их всех расставить по путям? Вот для этого существуют переменные:
pu - путь, на который прибудет поезд игрока (Mytrain);
puvs - путь, на который прибудет первый встречный (train1);
puvsw - путь, на который установится второй встречный (train2);
pupop - путь, на который прибудет попутный поезд (train3).
В зависимости от количества поездов скрипт присваивает значение этим переменным в пределах общего количества путей на станции (т.е. при четырёх путях, если ни один из них не занят отстоем, все четыре поезда получат свои пути прибытия). Далее, в зависимости от того, какой поезд должен прибыть или отправиться, переменным puin и puout присваивается значение pu или  puvs или puvsw или pupop и запускается нить JunThread() - переводятся стрелки.


Вечным двигателям - вечные тормоза!
 
toltekДата: Среда, 25.12.2013, 16:39 | Сообщение # 8
Группа: участники
Сообщений: 70
Статус: Offline
Ага, значит puin - это всё таки путь для пребывающего поезда игрока независимо от направления... или нет?.. Всё таки я запутался. К примеру такая ситуация. 
Допустим я по однопутке, независимо в каком направлении  прибываю на станцию. За мной едет попутный. Для меня puin=1. Мне нужно остановиться на станции и дождаться прибытия встречного, для которого puvs=2, которому в свою очередь, тоже надо остановиться и пропустить попутный, для которого pupop=3. Когда встречный прибыл, puout=pu и я уехал. Для попутного тоже, puout=pupop. А вот когда проехал попутный, то тогда как собрать маршрут на выход встречному, puin=puvs или puout=puvs?..  uhm


Если тело пердит, значит оно живое!
Trainz 2010 build 49933
 
ДобрыйДата: Среда, 25.12.2013, 17:17 | Сообщение # 9
Чеширский кот
Группа: администраторы
Сообщений: 2246
Статус: Offline
toltek, да, puin - независимо от направления движения входной маршрут на путь с этим номером. В зависимости от направления puin двигает стрелки чётной или нечётной горловины в нити JunThread():
        if (puin==2 and nap==false)  ChangeJunc("ff107",0), ChangeJunc("ff1",0);
else if (puout==2 and nap==true) ChangeJunc("ff3",0), ChangeJunc("ff21",0), ChangeJunc("ff5",2);
То есть, направление движения мы задали однократно (есть в первом сообщении) и все нити скрипта в последующем используют значение переменной nap для различных действий.
По поводу второго вопроса - всё просто.  "Когда встречный прибыл, puout=pu и я уехал. Для попутного тоже, puout=pupop". Нет, в этом случае puout не может быть равно pupop. Если на станции два поезда в одном направлении, то выходной маршрут собирается только для одного, т.е. или puout=pu или puout=pupop. Я для себя ввёл дополнительную переменную order, которая случайным образом принимает значение true или false. true - если попутный нас обгоняет, тогда puout=pupop, а если false, то puout=pu.
Если попутный нас не обгоняет - он просто остаётся позади, когда мы уехали, и удаляется. А если обгоняет (puout=pupop), то мы ждём наезда этого попутного на триггер, установленный на перегоне впереди  Navigate.OnTrigger(me,train3,trigw,0); где trigw - переменная, которой присваивается значение триггера, после чего puout=pu; JunThread(); (собираем маршрут нашему поезду на тот же перегон).
Когда проехал попутный и надо собрать выходной маршрут встречному, будет puin=puvs (или puin=puvsw если надо отправить второй встречный) , потому что для нашего поезда входная горловина puin является выходной горловиной для встречного (думаю, это ясно).


Вечным двигателям - вечные тормоза!
 
toltekДата: Четверг, 26.12.2013, 14:02 | Сообщение # 10
Группа: участники
Сообщений: 70
Статус: Offline
Теперь ясненько, большое спасибо! Есть ещё один вопросик.   cry
Не могу понять назначение массива bool [] stand = new bool [13]. В твоей организации назначения путей для встречных переменные этого массива используется очень часто, но для чего не понятно и из-за этого не получается понять всю схему


Если тело пердит, значит оно живое!
Trainz 2010 build 49933
 
ДобрыйДата: Четверг, 26.12.2013, 18:32 | Сообщение # 11
Чеширский кот
Группа: администраторы
Сообщений: 2246
Статус: Offline
Опять-таки возвращаемся к реальной ЖД. На станции несколько путей, один из них занят (на табло будет обозначен красным), поэтому на него нельзя собрать маршрут, кроме маневрового. Как дать понять скрипту, что путь занят и на него нельзя собрать маршрут? Да так же, как и в реале - обозначить его "красным".
bool [] stand = new bool [13]; for (it=1; it<13; ++it) stand[it]=true;
создали массив из 13 ячеек (станций с большим количеством путей на карте нет) и для перестраховки изначально всем им дали значение true - путь свободен (хотя по идее они итак true).
Мы приближаемся к станции, где 4 пути. Программа первым делом ставит (рандомно) состав на отстой на какой-то путь (кроме первого и главного), например, 3. Чтобы потом скрипт ни в коем случае не создавал маршрут на этот путь, вешаем на него "красный флаг": stand[3]=false;
Теперь, когда программе надо найти свободный путь для, например, встречного, вот такой цикл:
while (stand[puvs]==false and puvs>0) --puvs; if (puvs<1) vstr=false; else stand[puvs]=false;


Вечным двигателям - вечные тормоза!
 
ДобрыйДата: Четверг, 26.12.2013, 18:33 | Сообщение # 12
Чеширский кот
Группа: администраторы
Сообщений: 2246
Статус: Offline
Переводим: пока проверяемые ячейки в false (соответствующие им пути заняты) и номер пути больше 0, уменьшаем номер проверяемой ячейки на 1 и проверяем её. То есть, как только найдём свободную ячейку, цикл останавливается и puvs останется равным номеру свободного пути. На него и будем принимать встречный. Если при этом puvs стал меньше единицы (все пути заняты), мы запрещаем создание встречного (vstr=false), а иначе вешаем "красный флаг" и на это путь (stand[puvs]=false) - нам же ещё может понадобится искать пути для попутного. Тут надо отметить, что puvs изначально принимает значение номера последнего пути на этой станции (количество путей на каждой станции прописано в массиве int [] stanput), поэтому поиск начинается с, например, 4 и заканчивается 1.
Уезжая со станции, обязательно повторяем for (it=1; it<13; ++it) stand[it]=true; потому что этот массив тут же начинает работать для следующей станции, а изначально на ней все пути свободны. smile


Вечным двигателям - вечные тормоза!
 
toltekДата: Среда, 08.01.2014, 21:32 | Сообщение # 13
Группа: участники
Сообщений: 70
Статус: Offline
Большое спасибо! Я как раз думал над тем, каким же образом обозначать в скрипте занятость путей.
Буду химичить дальше beer

Добавлено (08.01.2014, 21:32)
---------------------------------------------
Добрый, в скрипте есть формула

fTime=(iHours/24.0)+(iMins/1440.0)+(iSecs/86400.0);

,переводит понятное нам время во время, понятное игре.
А можно ли какой нибудь формулой наоборот перевести, к примеру, 0.176386575... в часы, минуты и секунды? Если есть такая, напиши пожалуйста. Целый день пытаюсь её выдумать, но ничего не получается.
И ещё. За полгода я несколько раз пытался до конца проехать сценарий грузовой из крыма, но ни разу не удалось, тк в джанкое, не успев полностью заехать на путь(не помню какой), раньше времени собирается маршрут на выход встречному и под моим составом переводится стрелка(у43, помоему), после чего мой состав сходит с рельс. Проверь у себя, пожалуйста.


Если тело пердит, значит оно живое!
Trainz 2010 build 49933
 
ДобрыйДата: Четверг, 09.01.2014, 16:42 | Сообщение # 14
Чеширский кот
Группа: администраторы
Сообщений: 2246
Статус: Offline
toltek, обратной формулы не встречал и как-то не задумывался... будет время - обдумаю wink
Насчёт грузового - у меня ни разу такого не случалось, но раз проблема существует, задержу отправку встречного до остановки нашего.


Вечным двигателям - вечные тормоза!
 
TRam_Дата: Пятница, 10.01.2014, 01:22 | Сообщение # 15
Группа: проверенные
Сообщений: 14
Статус: Offline
toltek, функция перевода времени в минуты:

float GetNormalTimeInMin()
{
float h = World.GetGameTime()+0.5;
if (h>1) h=h-1;
h=h*24*60;
return h;
}

чтобы из минут выделить часы, надо:

int hours = (int)(Min_sum/60);
int mins = (int)(Min_sum - 60*hours);
int sec = (int)( (Min_sum -  (int)Min_sum)*60 );
 
FORUM » FORUM » КАРТОСТРОЕНИЕ » Скрипт сценария (Обсуждаем скрипт сценария к карте "Крым")
Страница 1 из 6123456»
Поиск:

Copyright Dobry © 2017