SkyRiver Forum
http://skyriver.ru/forum/

Основы модосоздания для Механоидов - Пишем скрипты!
http://skyriver.ru/forum/viewtopic.php?f=21&t=3783
Страница 1 из 1

Автор:  mrSigma [ Вс 4 апр 2010 0:36 ]
Заголовок сообщения:  Основы модосоздания для Механоидов - Пишем скрипты!

Вступление

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

Дабы не возвращаться к этому позже, сразу предупреждаю, что я НЕ ОТВЕЧАЮ на вопросы о том "Как правильно подключить локацию?" или "Почему игра вылетает, когда я пытаюсь запустить мод?". Если вы решились прочесть эту статью, то будьте добры, знайте как локацию подключить. Это - минимальные необходимые для вас знания.


Создадим локацию.

Начнем мы, как ни странно, с создания самой локации. Я не буду вдаваться в подробности, дам лишь пару советов.

    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 знак = и пишите название цвета.

Изображение
Обращаю ваше внимание, что бестолку раскрашивать заголовки текстов, они все равно в итоге будут иметь стандартный цвет.

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

Автор:  Панцирь [ Вс 4 апр 2010 6:40 ]
Заголовок сообщения: 

mrSigma писал(а):
Я так и не понял почему, но лучше не созраняйте crash.mpj, в случае, если все же редактор лег.

Потому-что этот крэш наверняка впоймает глюк.
З.Ы (Во всем виноваты тени) Уж с ними сохранять свои проекты вообще не рекомендуетя и тем более Crash.mpj.
Вылеты игры обеспечены...

Автор:  Krogoth [ Вс 4 апр 2010 19:21 ]
Заголовок сообщения: 

mrSigma писал(а):
это, очевидно, стандартный обработчик
Совсем нет. Просто мы запускаем процедуру "OnEnterLocation" в скрипте "Events\EnterLocation.src".

Добавлено спустя 2 минуты 51 секунду:

mrSigma писал(а):
Обязательно поместите на локацию одно здание, и один объект типа "Указатель" (Хелперы -> Позиции), назвать можете как хотите.
Скажем так, как минимум одно из двух.

Автор:  mrSigma [ Пн 20 июн 2011 23:51 ]
Заголовок сообщения: 

Решил, вот, перечитать свои некогда бесполезные труды... И своей же глупости удивляюсь)

void proc Double(int i)
{
return i*2;
}

Страница 1 из 1 Часовой пояс: UTC + 4 часа
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/