[Новости][Статьи] Как писать скрипты для Trainz. часть 2
Дополнительные файлы к статье Lesson1.cdp (18.5 kb) - пакет с учебным сценарием. Lesson1.gs (5 kB) - исходный текст сценария SP3S1DCC.gs (27.7 kB) - исходный текст сценария Highland Valley (DCC) WriteScript1.rar (90.6 kB) - архив с текстом статьи для печати в формате MS Word 97 |
Как писать скрипты для Trainz Как писать скрипты для Trainz Это первая версия статьи, рассчитанная в основном на тех, кто уже знаком с программированием, поскольку я не буду объяснять основных понятий. То есть, считается, что вы уже имеете представление о том, что такое типы данных, процедуры, функции, а также объектно-ориентированное программирование. Всех, кто впервые об этом услышал, я для начала отправляю к книгам по языкам программирования, где все эти термины объясняются. Скрипты для Trainz пишутся на внутреннем языке, который во многом похож на такие языки программирования как C++ или Java, хотя это свой собственный язык фирмы Auran. Исходный файл скрипта -обычный ASCII текстовый файл, которому по умолчанию даётся расширение .gs Из этого файла с помощью программы-компилятора gsc.exe получается исполняемый файл с расширением .gsc, который уже будет выполняться в среде Trainz. Насколько я смог понять, в Trainz встроен специальный многопоточный интерпретатор. Многопоточный означает, что можно параллельно запустить несколько процессов, которые будут выполняться независимо друг от друга. Например, можно написать для каждого поезда в вашем сценарии отдельный поток, который будет полностью управлять его поведением, дальше все эти потоки запустить на выполнение, и каждый из них будет выполняться независимо. Точнее, почти независимо, поскольку многопоточность в Trainz, насколько я выяснил, имитируется. То есть, если внутри одного из потоков начать выполнение какой-то длинной процедуры без вызова подпрограмм ожидания событий, например, создание составов, то все процессы, в том числе основной игры, приостанавливаются до завершения этой процедуры. Также хочется заметить, что получаемый на выходе файл .gsc содержит не команды процессора, а внутренний байт-код интерпретатора Trainz. Если заглянуть в каталог Scripts\Docs, то там можно найти файл index.chm и "TrainzScript Tutorial.doc" (для версии TRS2004). Первый содержит достаточно подробный help по языку и внутренним объектам игры. Без него серьёзно писать скрипты невозможно, поскольку только там можно найти подробное описание всего, что есть внутри Trainz (а есть там много чего). Сразу хочу отметить, что там всё на английском языке, так что, если кто собирается всерьёз писать скрипты, то учите английский язык хотя бы для общего понимания смысла. Хочется также добавить, что я технические тексты читаю сравнительно свободно, но всё равно частенько приходится прибегать либо к словарю, либо к услугам программы-переводчика (быстрее, чем по словарю лазить). Опять же, многие названия процедур, функций, классов и т.п. говорят сами за себя, когда хоть немного знаешь язык. В общем, было бы желание, остальное приложится. :) Также в этом каталоге лежит файл makescript.bat, который фирма Auran рекомендует скопировать в тот каталог, где вы будете писать скрипт, и запускать с его помощью компиляцию. Этот файл содержит следующие команды командного процессора ОС: @echo off set gsc=..\..\..\..\bin\gsc.exe set include=..\..\..\..\scripts\ for %%a in (*.gs) do %gsc% %%a -i%include% set gsc= set include= pause при этом считается, что ваш скрипт сценария лежит в каталоге world\custom\scenarios\<имя сценария>\ Другими словами, задаются две переменных, в которых сначала мы возвращаемся к исходному каталогу игры, а потом в первом случае идём к файлу компилятора gsc.exe, который лежит в каталоге bin, а во втором прописывается путь к папке scripts, тоже находящейся в каталоге игры, где лежат файлы заголовков ко всем внутренним объектам самой игры Trainz и на который мы будем ссылаться при написании собственных скриптов. Строка, которая начинается с for, повторяет вызов компилятора для всех файлов, которые перечислены в командной строке после самого makescript.bat В принципе, можно пользоваться этим файлом, скопировав его в папку со своим скриптом сценария, а можно и свой написать, если кому хочется. Если вызвать программу gsc.exe без параметров, то вы получите на экране следующий текст: AURAN GameScript Compiler V1.01 gsc.exe returns number of compile errors gsc.exe <option> <option>.. where <option> is one of the following <-d> print documentation, u might wanna pipe it to a text document =) <-s> silent <-bfilename> dump the build info (compile log) to file <-ppathname> output path <-ofilename> output library filename <filename> input source file <-ipathname> additional include path где приводится вполне исчерпывающее описание синтаксиса командной строки и тех ключей, которые можно задать программе. В данный момент нас больше всего интересует команда –d, которая позволяет получить документацию по языку программирования AURAN GameScript. Просто наберите в командной строке следующее: Gsc.exe –d >gsc.txt Нажмите enter, и вы получите в файле gsc.txt полное и подробное описание синтаксиса языка. Его желательно распечатать и первое время, пока освоитесь с языком, держать под рукой. Правда, как и следовало ожидать, это описание опять на английском языке. :) Но раз уж я начал писать стать на русском языке, то приведу краткое общее описание с некоторыми комментариями. Краткое описание синтаксиса языка AURAN GameScript Комментарии выделяются как в языке c++ \\ обратный двойной слэш – комментарий до конца строки /* многострочный комментарий */ Зарезервированные слова языка подробно описаны в gsc.txt, повторяться не буду, там всё и так понятно. Синтаксис основных операторов, в том числе операторы условия, циклов, выбора скопирован с языка C, включая фигурные скобки, которыми оформляются блоки кода. То есть, кто не может понять описание в файле gsc.txt берите книжку по языку C или C++ и разбирайтесь. Но сразу предупреждаю, что нужно всё-таки в первую очередь ориентироваться на файл gsc.txt, поскольку есть некоторые отличия. Идентификаторы задаются стандартно, как и во многих других языках программирования. Любой идентификатор должен начинаться с буквы латинского алфавита (A..Za..z_), либо символа подчёркивания, а дальше могут быть те же буквы или цифры. Сразу хочу отметить, что большие и маленькие буквы считаются РАЗНЫМИ! То есть, компилятор РАЗЛИЧАЕТ РЕГИСТР, в отличие от многих других языков программирования. Типы данных, которые поддерживаются языком Void - пустой тип данных, который используется только при описании функций Int - 32 битное знаковое целое число Float - 32 битное число с плавающей точкой Bool - 32 битный логический тип, 0 – false или НЕ 0 – true (в общем, как в C) String - текстовая строка Object - объект одного из объявленных в игре классов, при этом, когда объявляем переменную, то пишем, естественно, имя класса, а не object, поскольку object является базовым классом, от которого порождаются все остальные int[] - целочисленный массив float[] - массив чисел с плавающей точкой bool[] - массив логических переменных string[] - массив строк object[] - массив объектов Как можно заметить, набор типов данных небольшой, но на самом деле вполне достаточный для написания самых сложных скриптов. При этом, в отличие от универсальных языков программирования, в AURAN GameScropt мы не можем объявлять новые базовые типы данных, в том числе структуры или объединения, но можем объявлять новые классы, чего на практике вполне достаточно. Все основные операторы языка, которые можно использовать в выражениях, см в разделе 2.6 файла gsc.txt. Они во многом повторяют операторы языка C, а о некоторых важных отличиях я скажу чуть позже, когда будем разбирать примеры. Немного хочется остановиться на модели объектно-ориентированного программирования, которую AURAN реализовала в своём языке. Во-первых, все объявляемые внутри классов функции являются виртуальными. При этом, если вы объявляете в классе-потомке функцию с тем же именем, то она всегда автоматически перекрывает функцию в классе-предке. Никаких специальных указаний делать не нужно. Если же вам нужна независимая функция, то просто пишем её с новым именем. Также язык поддерживает множественное наследование, когда в качестве предка для нового класса указывается сразу несколько классов-родителей. При этом в новом классе будут доступны все поля и функции, которые были у всех предков вместе (производится объединение). Ну ладно, на этом вводную часть закончим и перейдём к непосредственной разработке сценариев. Необходимые файлы и предварительная подготовка В каталоге, куда была установлена игра Trainz или TRS2004 всегда есть каталог world, который содержит как стандартную библиотеку в файлах с расширением .ja, так и всевозможные пользовательские дополнения. То, что установлено с помощью программы ObjectDispatcher, лежит в каталоге world\dispatcher\downloads. Все создаваемые пользователем объекты, расширяющие стандартную библиотеку Trainz, должны располагаться в каталоге world\custom в котором для каждого типа объектов должен быть создан свой каталог. При запуске Trainz сканирует содержимое этих каталогов и всё, что удовлетворяет внутренним требованиям, появляется в игре. В world\custom могут быть следующие каталоги (которые я знаю): Bogeys - тележки для подвижного состава Engines - описание параметров двигателей для локомотивов, в том числе тяговые характеристики Enginesound - звуки работы двигателей локомотивов зависящие от текущей мощности Ground - текстуры поверхности Hornsound - звуки сигнала локомотивов Html - страницы с html, правда, в урезанной версии для внутреннего минибраузера. Именно с его помощью создаются сложные диалоги, позволяющие получать данные от пользователя. Maps - карты, которые создаются пользователем. Именно сюда попадает всё, что мы создаём с помощью редактора карт. При этом имя каталога с картой является именем карты в самой игре. Meshes - это новый раздел, который появился в TRS2004. Судя по названию, там должны хранится 3D формы объектов. Более подробно пока не разбирался. Pants - пантографы (токосъёмники) для электровозов Products - продукты для новых индустриальных объектов. То, что потом можно будет возить. Правда, там нужно достаточно много сделать, чтобы оно заработало, включая сами объекты производства и приёма продуктов, а также вагоны, которые их могут перевозить. Profiles - это так называемые профили игры – положение составов на карте. При этом каждый профиль в своём файле config.txt будет ссылаться на какую-то из карт, имеющихся в Trainz. Scenarios - ну а это как раз тот каталог, который нам нужен. :) Здесь лежат сценарии. Scenery - различные одиночные объекты, которые мы размещаем на карте. Splines - различные сплайны, которые мы можем разместить на карте. То есть дороги, мосты заборы, ЛЭП и т.д. за исключением тех, которые содержат ЖД-пути Track - а вот это уже сами ЖД-пути и всё, что содержит ЖД-пути. Trackside - объекты, которые расставляются вдоль ЖД-пути, типа стрелок, светофоров, знаков и т.д. Trains - подвижной состав, то есть локомотивы и вагоны Из всех вышеперечисленных разделов нас сейчас интересует в основном Scenarios, а также Maps, если сценарий делается для собственной карты. Заходим в каталог world\custom\scenarios (если его нет, то создаём) и внутри его создаём новый каталог, которому даём то имя, под которым мы хотим наш сценарий потом увидеть в самом Trainz. Например, Lesson1. Первое, что мы должны создать, это файл config.txt, который создаётся для любого объекта Trainz. Формат файла определяется фирмой Auran и подробно описан в Content Creators Guide (CCG), который можно свободно скачать с сайта TRS2004 (что рекомендую сделать всем разработчикам). Для сценария там должны быть следующие строки: kind activity username Lesson1 scriptlibrary Lesson1 scriptclass MyLesson1 kuid <kuid:131275:100010> region Russia category-region-0 RU category-era-0 1990s category-class YS kuid-table { city_and_country_usa <kuid:-1:100927> f7_sfred <KUID:-1:1> atsf_chair <KUID:-1:100160> atsf_baggage <KUID:-1:100159> } description "Lesson1 Trainz Script 2004 (c) Dmitry Mylnikov" теперь тоже самое, только с комментариями kind activity - указывается тип объекта. Activity по версии Auran является сценарием. username Lesson1 – пользовательское имя сценария, которое будет показано в игре scriptlibrary Lesson1 – имя файла с откомпилированным сценарием, которое должно иметь расширение .gsl scriptclass MyLesson1 – главный класс внутри сценария, которому будет передано управление при его запуске. Он должен быть объявелен как game и наследоваться от класса Scenario (подробности см. ниже) kuid <kuid:131275:100010> - это идентификатор самого сценария. Первая часть - это ваш собственный код, который можно свободно получить на сайте Auran, а вторая часть - это уникальный номер среди всех ваших объектов (имеющих тот же первый номер). За уникальностью номеров вы должны следить сами. Если будет совпадение номеров, то эти объекты в Trainz видны не будут. Удобно проверять с помощью программы TrainzObjectz, которая умеет выявлять все дубли в KUID, включая коды объектов в стандартной базе игры. region Russia - указывает название региона category-region-0 RU - код региона в соответствии с CCG, где приведён перечень всех возможных кодов category-era-0 1990s - временной период в 10 лет во время которого объект существовал. Таких строк, отличающихся цифрой и годом, может быть несколько. Например: category-era-0 2000s category-era-1 1990s category-era-2 1980s category-era-3 1970s category-class YS - более подробно указывает тип объекта, в данном случае YS указывает на то, что это сценарий. Перечень всех кодов см. CCG. kuid-table { - это начинается таблица объектов, которые используются в сценарии. При этом мы задаём имя объекта, через которое потом будем к нему обращаться в самой программе, а также его код в базе объектов (KUID). KUID, опять же, удобно смотреть с помощью TrainzObjectz, в том числе для карт. Таблица начинается с ключевого слова kuid-table, после которого следует открывающая фигурная скобка, и продолжается вплоть до закрывающей фигурной скобки. Да, сразу хочу предупредить, что программа чувствительна к большим/маленьким буквам, поэтому я для себя взял за правило все идентификаторы в таблице писать только маленькими буквами. И поскольку это идентификатор, то он должен начинаться только с буквы и не должен содержать пробелов. Вместо пробелов используется символ подчёркивания. city_and_country_usa <kuid:-1:100927> - это идентификатор карты, который потом будет использоваться в программе, а также её KUID. Для своих карт смотрите их в соответствующем файле config.txt, который будет лежать в каталоге world\custom\maps\<имя карты>. Ниже перечень KUID для встроенных карт, полученный при помощи программы TrainzObjectz:
f7_sfred <KUID:-1:1> - это строка и ещё три ниже служат для описания идентификаторов и KUID локомотива и вагонов. Их тоже можно получить с помощью TrainzObjectz. Для встроенных объектов их можно также посмотреть в приложении в конце CCG. Я использовал следующий способ. Сначала расставлял все необходимые локомотивы и выгоны на карте, потом сохранял её, выходил из Trainz и запускал TrainzObjectz. В TrainzObjectz, когда вызываешь описание карты (на закладке Maps выбираешь название карты в ComboBox), то в конце будет перечень всего подвижного состава, который был использован, с указанием их названия и KUID. atsf_chair <KUID:-1:100160> atsf_baggage <KUID:-1:100159> } - конец таблицы KUID description "Lesson1 Trainz Script 2004 (c) Dmitry Mylnikov" - строка описания. Описание может быть многострочным, если его заключить в двойные кавычки. Только следите за тем, чтобы внутри текста двойные кавычки случайно не встретились. Именно этот текст будет выведен слева в окне выбора сценариев, когда будет выделен ваш сценарий. Ну вот, с config.txt вроде разобрались. Теперь немного о специальных объектах карты, которые нужны как раз для написания скриптов. Если в редакторе карт открыть закладку с путями (где рельсы на ярлычке нарисованы), то в верхней части открывшегося окна будут три круглых кнопки. Первая даёт доступ к редактированию путей (tracks), вторая даёт доступ к редактированию путевых объектов (trackside), куда включаются стрелки, светофоры и семафоры, различные путевые знаки и т.п. Ну а третья даёт доступ к редактированию маркеров и триггеров. Вот они то нам и нужны. Маркеры (красная треугольная пирамидка, лежащая на боку) и триггеры (зелёная объемная буква Т) являются служебными объектами и видны только в редакторе карт. Маркер служит той точкой, на которую можно поставить поезд из нашей программы. При этом направление движения будет соответствовать направлению пирамидки. В принципе, каждому маркеру или триггеру нужно дать уникальное имя, причём такое, которое вам будет говорить о его назначении, чтобы потом не путаться во время написания программы. Также желательно присвоить осмысленные имена всем стрелочным переводам, или хотя бы тем, которые задействованы в программе. Для того, чтобы задать имя, нужно выделить кнопку со знаком вопроса, а потом выбрать нужный объект на карте. Триггер является служебным объектом, который может генерировать события в программе, связанные с движением поезда. При этом он может реагировать на вхождение поезда в зону триггера, на остановку поезда в зоне триггера и на выход поезда из зоны триггера. Зона триггера (радиус триггера) задаются с помощью специальной кнопки, которая находится на закладке advanced, на которой нарисована двухсторонняя стрелка. Можно также задать радиус триггера в числовой форме в метрах. Да, чтобы открыть страничку advanced, нужно нажать на надпись ”advanced” внизу открывшейся панели редактирования путей (см. рисунок).
Хочется отметить, что написание большого сценария дело достаточно кропотливое. При этом даже не рассчитывайте на то, что вы сможете сразу расставить на карте все необходимые маркеры и триггеры так, как оно должно быть. Придётся многократно запускать Trainz, грузить карту, устанавливать нужные триггеры и маркеры, потом снова выходить, писать очередную часть сценария, компилировать, снова загружать Trainz и смотреть, что получилось. После этого снова идти в редактор и поправлять триггеры или маркеры, либо добавлять новые. А после этого снова выходить из Trainz и повторять всё по новой. При этом многие идеи по поводу тех или иных событий в сценарии у меня появились как раз по ходу отладки сценария, что, опять же, повлекло его изменение с установкой новых триггеров и маркеров. :) Да, сразу хочу предупредить, что даже если у вас будет нормально работать переключение между Trainz и другими программами, в случае изменения сценария вы не увидите их в игре до тех пор, пока не перезагрузите Trainz, поскольку до выхода из программы сценарий будет лежать у Trainz во внутреннем кэше. С уважением, 4 Апреля 2004 года |
[Новости][Статьи]
Как писать скрипты для Trainz. часть 2