Вступление
Итак, доброго времени суток, читатели. Пишу эту статью как один из тех, кто совсем недавно совершенно не понимал как это все работает, что для чего нужно и что с этим всем делать, что вызывало у меня справедливое возмущение, ведь ни одной статьи о том, как это использовать так и не появилось! Вот я и решил восполнить этот пробел, и собрать всю необходимую информацию в одной статье. Если вы мечтаете начать заниматься созданием модов, то эта статья для вас. Сегодня мы рассмотрим некоторые основы написания скриптом для механоидов, некоторые приемы работы с редактором текстов и редактором локаций.
Дабы не возвращаться к этому позже, сразу предупреждаю, что я НЕ ОТВЕЧАЮ на вопросы о том "Как правильно подключить локацию?" или "Почему игра вылетает, когда я пытаюсь запустить мод?". Если вы решились прочесть эту статью, то будьте добры, знайте как локацию подключить. Это - минимальные необходимые для вас знания.
Создадим локацию.
Начнем мы, как ни странно, с создания самой локации. Я не буду вдаваться в подробности, дам лишь пару советов.
1) Создавайте погоду после того, как окончили работу с ландшафтом. Если вы открываете проект для редактирования, но уже подключали локацию, то можете создать специальную погоду для удобного редактирования. Я делал это так: Создавал новую погоду и устанавливал Цвет общего освещения на белый и цвет солнца на белый. Теперь с локацией будет работать удобнее.
2) Поосторожнее с редактором погоды, он очень любит крашить редактор локаций. Особенно будьте внимательны, когда погоды удаляете.
3) Я так и не понял почему, но лучше не созраняйте crash.mpj, в случае, если все же редактор лег.
4) Не вздумайте сохранить проект карты со сгенерированными тенями. До добра это не доведет, уж поверьте.
Вот и все советы по созданию ландшафта. Помните, что между вами и идеально-красивой локацией стоит лишь ваше воображение.
Когда вы все же создали локацию, заполнили ее всякими объектами типа деревьев и кустов, закрасили текстурами, то самое время построить здания. В моем примере я использовал "Выход из лифта", что находится в папке "туннели". Он не показывает вам никаких текстов, не стремится с вами поздароваться или рассказать о себе, как это любят делать базы, поэтому нам не нужно будет копаться в скриптах, чтобы убрать эти разговорчики, если они нам не нужны и мы делаем мод про внешний мир (как я).
Расположив здание на локации лучше сразу дать ему имя. Вот вам небольшой совет: Для всех объектов, которым вы даете имя, лучше добавлять к имени какой-нибудь префикс, чтобы потом можно было собрать их в отдельную папку в редакторе текстов. (Я например использовал префикс L8_).
ВАЖНО: Обязательно поместите на локацию одно здание, и один объект типа "Указатель" (Хелперы -> Позиции), назвать можете как хотите. Сразу предупреждаю что в моем примере они были L8_LIFT и L8_QUEST соответственно, поэтому в скриптах я буду использовать эти имена. Вы просто поменяете их на свои.
(Все это будет необходимо в моем примере, который вы сможете чрочесть дальше. Впрочем, вы можете просто ознакомиться с этой статьей и захотеть написать квест не с примера, который я приведу ниже. Как бы то ни было, на работу локации это не повлияет.)
Script it!
Наша локация готова, после того как мы подключили ее к игре, и убедились что все работает, мы можем приступать к собственно написанию квеста. Для этого мы будем использовать Script Editor.
В папке Data\Scripts мы найдем множество файлов с расширением *.src*. это - исходники скриптов, в которых мы и будем писать. По сути это самые обычные текстовые файлы, и их можно очень даже успешно править блокнотом, но скомпилировать в готовые скрипты их удастся лишь с помощью Sript Editor'а.
Для удобства в папке Scripts\Locations создадим папку для скриптов нашей локации. Я назвал ее L8 (что и следовало ожидать). В этой папке будем хранить исходники скриптов нашей локации.
Итак, создадим новый скрипт. Как правило, первый скрипт в этой папке - обычно скрипт, обрабатывающий вход на локацию. Он имеет следующий вид:
Код: #include "include\AIM.cpp" \\Подключаем функции Механоидов. Эта строчка должна быть обязательной для всех ваших скриптов.
void proc OnEnterLocation(char item) \\Функция, обрабатывающая вход на локацию. item в нашем случае id этой локации. { StartScriptEvent("Events\EnterLocation.src", "OnEnterLocation", item); \\это, очевидно, ВОВСЕ НЕ стандартный обработчик, хоть это и написано в скрипте-примере по подключеннию локации, что идет в комплекте с СДК. Это ни-что иное как запуск скрипта "Events\EnterLocation.src". }
Это - должно быть у всех лоакаций. Ну или не у всех, воообщем лучше напишите. Кстати, в этом скрипте можно добавить, например, инициализации переменных, которые будут что нибудь считать. Кстати, для присвоения значений глобальным (я их так называю) переменным можно использовать SetVar("Любое название", "значение"); Сразу скажу, что глобальные переменные для того чтобы их использовать, не нужно инициализировать достаточно один раз присвоить им значение, и потом можно будет эти значения читать с помощью GetVar("Название переменной"); Можно так-же использовать этот скрипт для добавления чего-нибудь в начале игры, например денег: AddAmount(AMOUNT_ENERGY, количество);
Признаюсь честно, я пошел по иному, нежели разработчики, пути. Этот самый скрипт я использовал и для всех событий, что происходили с глайдером на локации, например влет в сенсор. (OnEnterSensor) А в другой скрипт, я поместил все события, что происходили с механоидом в здании, например залет в него, действия с квестами внутри зданий и так далее.
Неоторые примеры использования скриптов.
Я просто не знаю что написать далее, поэтому приведу некоторые примеры реализации той или иной задачи, а заодно ознакомлю читателя с некоторыми функциями, которые используются в Механоидах. Итак...
Использование конструкции "if-then-else". Название этой конструкции говорит само за себя. Дословно ее можно перевести как "если-то-иначе". Положим, у вас есть два строения. Для обоих строений вы используете один и тот-же скрипт, но при залете в каждое из них вам нужно делать совершенно разные действия. Тут то нам и поможет конструкция if-then-else. После подстановки ее в код, эта функция будет проверять истино ли утверждение, подставленое в блок "if". Если оно истино, то совершаются действия в блоке "then (то)", если же оно ложно, то совершаются действия в блоке "else (иначе)". Ниже следует пример использования этой самой конструкции. Скрипт проверяет является ли здание, в которое залетел игрок "Зданием 1". Если да, то он выводит текст "Вы влетели в здание 1" Иначе "Вы влетели НЕ в здание 1". (Почему именно так? Потому что будь у нас не два, а больше зданий, три например, то то, что игрок НЕ залетел в здание 1 еще не занчит, что он залетел в здание 2, потому что есть вероятность что он залетел в здание 3.)
Код: #include "include\AIM.cpp" void proc OnEnterBuild(char item) \\Эта процедура будет срабатывать всякий раз, как игрок залетает в какое либо здание, связанное с данным скриптом. В результате переменная item примет значение здания, в которое игрок залетел. { if (item == "Здание1") \\Собственно сама проверка. (блок "if") { \\Первая пара скобок - блок "then" Text("Вы залетели в здание 1"); } else { \\Вторая пара скобок после слова else - блок "else" Text("Вы залетели не в здание 1"); }
}
Использование конструкции "case". Если вы уже немного знакомы с программированием, то знаете, что если вариантов развития событий при использовании программы много (под много я понимаю боле двух), то if-then-else использовать не удобно. Именно для этого и существует конструкция case. Пусть на сей раз в нашем секторе есть не два строения, а три, и при залете в каждое из них - свои действия. Чтобы реализовать подобную схему с помощью if-then-else, вам придется проверять не равно ли строение в которое игрок залетел зданию 1. Если же не равно, что в блоке else снова проверять, не равно ли оно зданию 2, и только если оно не равно зданию 2, то мы можем заключить, что это - здание 3. Однако, данная схема очень громоздка и сложна при восприятии (когда смотрите на скрипт - тяжело понять что из чего к какой проверке относится). А если бы таких строений было не 3, а 20? Следующий пример покажет вам, как использовать конструкцию case с тремя зданиями.
Код: void proc OnEnterBuild(char item) { switch(item) ..Начало конструкции case объявляется словом switch, в скобках - переменная, которую мы проверяем. Все проверки и действия в switch берутся в отдельные фигурные скобки. { //Вот такие. case "Здание1": //В случае, если item = Здание1, делать { //Действие в этих фигурных скобках. Text("Это - здание 1"); } case "Здание2": //В случае, если item = Здание2, делать { //Действие в этих фигурных скобках. Text("Это - здание 2"); } case "Здание3": //То же и с третьей проверкой. { Text("Это - здание 3"); }
} //Окончание Switch //Примечание: После case "Значение" и перед действияем ставится двоеточие *:*
}
Использование сенсоров Для указания на некоторые места на локации (например для создания квестов) можно использовать сенсоры. Их можно, например, использовать, чтобы реализовать квесты наподобии "Разведки у базы Фантомов" или "Исследование озера" в Секторе Скал. Насчет того, какие объекты можно делать сенсорами, а какие нет - я не уверен. Знаю точно, что можно установить сенсор, который не будет виден игроку на локации. Для этого можно использовать объект типа "Указатель" (Хелперы -> Позиции). Это именно тот объект, что я просил вас поставить на локацию, так как он будет использован в моем примере квеста. Чтобы объявить этот объект сенсором, необходимо где либо в скриптах написать SetSensor("Имя объекта");. (лучше всего это делать либо в скрипте, который запускается при входе на локацию, либо когда игрок берет квест, который связан с данным сенсором.) После того, как эта операция будет проделана, пролет в этот сенсор будет запускать процедуру OnEnterSensor(char item);, если она прописана в скрипте. Обращаю ваше внимание, ЧТО СЕНСОР - ТАК-ЖЕ ИГРОВОЙ ОБЪЕКТ, И СКРИПТЫ, ЧТО С НИМ СВЯЗАНЫ НУЖНО УКАЗЫВАТЬ В OBJECTS.INI!
Вот простой пример использования сенсоров. Пролет на месте одного из них вызовет текст "Сенсор X". Обращу ваше внимание, что в данном скрипте я использовал две процедуры. ту, что инициализирует сенсор при влете в здание, и ту, что отвечает за пролет над сенсором.
Код: #include "include\AIM.cpp" void proc OnEnterBuild(char item) { SetSensor("SEN1"); //Инициализируем сенсоры SetSensor("SEN2"); SetSensor("SEN3"); }
void proc OnEnterSensor(char item) { switch (item); { case "SEN1": Text("Сенсор 1"); //Если после case нужно выполнять только одно case "SEN2": //Действие, то пару фигрных скобок ставить не Text("Сенсор 2"); //обязательно. case "SEN3": Text("Сенсор 3"); } }
Использование таймеров Иногда случается так, что нам нужно произвести какое-то действие не сразу, а с некоторой задержкой. Вспомним, например, общение с набллюдателем из "М2", где текст при подлете к его месту расположения выводился не сразу. Я думаю, что таймер - не сложная вещь, поэтому примера его использования я выкладывать не буду. Скажу лишь, что таймер используется так: SetTimer("Имя функции", Задержка); На месте имени функции вы ставите имя функции ^_^, которую ваш таймер должен запускать при окончании задержки. На месте задержки - время, которое должно пройти, прежде чем таймер запустит указанную функцию. Время имеет формат Ч:ММ, притом часы и минуты ИГРОВЫЕ.
Объявление и использование функций Функция, это часть кода, которая имеет свое имя, может принимать какие-либо параметры, а так же какие либо параметры возвращать. По сути, библиотека AIM.cpp, что мы подключаем перед написанием скриптов, содержит список стандартных функций механоидов, котоыре принимают какие либо параметры, и какие либо параметры возвращают. Мы так-же можем создать свои функции и использовать их в коде, как и Механоидовские. Синтаксис функций таков:
Код: void proc Имя функции (тип принимаемых параметров название переменной) {
...Действия, совершаемые функцией...
}
Возможно вам не совсем это понятно, но я поясню. Когда мы хотим вызвать какую либо функцию, мы указываем ее имя, и передаем ей какие-либо параметры. Иногда, мы получаем параметры в результате, но эт ововсе не обязательно. Так-же функция не обязательно может эти параметры принимать. Так-вот. Например, нам нужна функция, которая будет умножать число на два. Можно заносить это число в отдельную глобальную переменную, после чего вызывать эут самую функцию, которая число из глобальной переменной будет умножать на два, а потом записывать результат в другую глобальную переменную, и мы уже потом сможем использовать результат. Все это будет работать, однако это крайне громоздко и неудобно. То-ли дело функции. Мы можем написать функцию, которая будет принимать параметр типа int (целое число) и его же возвращать. Выглядеть все это счастье будет так:
Код: void proc Double (int i) //Свою функцию мы назвали Double, Она принимает параметр типа Целое число (int). Внутри функции, параметр, который она приняла будет иметь имя i. { return i*2; //Return возвращает указанное значение. Если после return не указать никаких параметров, то функция просто остановит свое выполнение. Я не знаю, как можно использовать это в механоидах, но в программировании это очень даже юсефулл. }
Так-же можно использовать функции, котоыре ни принимают никаких параметров, например для совершения однотипных действий.
Код: void proc primer () //Чтобы ничего не принимать, просто оставьте скобки пустыми. { Text("12132"); Text("fdjask"); }
Всякий раз, как мы вызовем эту функцию, она выведет нам на экран указанные тексты.
Так-же функции можно использовать в редакторе текстов (например для создания интерактивных диалогов, о чем будет расказано позже) и в таймерах.
Примечание: На самом деле, то что я так усердно называл функциями - не функции а процедуры. Функция отличается от процедуры тем, что она не возвращает никаких параметров, а просто совершает какие либо действия. Впрочем, если вы назовети их функциями, они сильно не обидятся. ^_^
Заключение раздела "Примеры использования скриптов"
Многие опытные модостроители думают, зачем же я все это делаю, ведь список функций и процедур можно заспросто найти в include\AIM.cpp. там даже комментарии есть, однако порой человеку, чтобы понять, нужно более подробное объяснение и конкретный пример использования. Если вы все усердно читали и вникали в суть, то у вас уже должно хватить знаний, чтобы написать несложные квесты. Если же у вас есть какие-либо вопросы - то их всегда можно задать в разделе "Редактор скриптов". Что-ж. Пишите, учитесь, а мы вам будем помогать.
Редактор текстов. What's that about.
Введение в редактор Итак, редактор текстов! Просто замечательная штука! Она позволит вам создать из механоидов полноценную РПГ (во всяком случае по части диалогов), если вы только умеете им пользоваться (Ну и редактором скриптов, разумеется). Я расскажу вам как им пользоваться, что с его помощью можно сделать, и как это будет выглядеть в игре. А начнем, мы пожалуй, с того, что назовем саму локацию. Чтобы это сделать, создайте новый текст через редактор, и назовите его так-же, как назвали свою локацию при генерировании. Теперь в поле "заголовок" впишите то название, которое вы хотите видеть в игре. Если вы не использовали один из стандартных префиксов, (например префикс B_ означает, что этот текст отвечает за название здания.) то вы найдете свой текст в папке Other. Чтобы объединить свои тексты с каким-либо особым префиксом, найдите в папке с игрой файл Settings.ini В разделе TreeGroups добавьте новый префикс следующим образом: Префикс=Название раздела. Обратите внимание, что если вы назвали свои тексты, например, MY_TEXTNAME, то на месте префикса ставите не MY_, а MY.
Что касается использования текстов, то в будущем вы сможете скриптово вывести их на экран, если будете использовать их ID (название, НЕ ЗАГОЛОВОК, А НАЗВАНИЕ).
Цвета и форматирование. Вы можете раскрасить свои тексты в множество разных цветов. делается это с помощью команды Код: <color>ТЕКСТ<color> . Ниже приведены различные названия цветов и их названия в редакторе (это то, как они выглядят в игре. Заголовок написан стандартным цветом (серым):
Внутри первой пары скобок ставьте после слова color знак = и пишите название цвета.
Обращаю ваше внимание, что бестолку раскрашивать заголовки текстов, они все равно в итоге будут иметь стандартный цвет.
Продолжение следует... Остальную часть статьи допишу чуть позже, ибо нет времени. Пока можее оценивать саму идею, а не статью, потмоу как она не дописана)
|