Программирование поведения объекта — различия между версиями
Velaar (обсуждение | вклад) (→Где хранить файлы?) |
Raw mat (обсуждение | вклад) |
||
(не показаны 55 промежуточных версий 2 участников) | |||
Строка 32: | Строка 32: | ||
Пожалуйста, обратите внимание, что все размеры в файле 3d модели должны указываться '''в метрах'''. | Пожалуйста, обратите внимание, что все размеры в файле 3d модели должны указываться '''в метрах'''. | ||
− | Если конвертер создает несколько файлов материалов, нужно | + | Если конвертер создает несколько файлов материалов, нужно объединить их в один (в произвольном порядке). Кроме того, нужно '''переправить пути к текстурам''' в файлах материалов на абсолютные DISS-пути (т.е. '''/media/textures/...'''). |
Когда все это сделано, остается последний шаг - создать файл модели. Для этого нужно создать XML-файл объекта, который, в простейшем случае, выглядит следующим образом: | Когда все это сделано, остается последний шаг - создать файл модели. Для этого нужно создать XML-файл объекта, который, в простейшем случае, выглядит следующим образом: |
Текущая версия на 15:12, 13 июля 2013
Перейдем от теории к практике. Перед прочтением этого документа рекомендуется ознакомиться с предыдущими. Здесь приведены конкретные рецепты - как и что делать, с примерами и их разбором.
Содержание |
[править] Где хранить файлы?
Ядро Диптауна использует DISS для хранения файлов. По-умолчанию, в корень DISS монтируется директория, которая находится в подкаталоге storage архива media. Таким образом,
- в linux это директория, которая расположена в $DEEPTOWN_MEDIA/storage
- в windows - INSTALL_DIR/Media/storage
DISS при первом запуске индексирует рекурсивно все файлы своего каталога (это необходимо для выполнения сложных запросов к файловой системе). Поэтому, если Вы добавляете или удаляете какие-либо файлы где-либо в пределах этой директории, нужно удалить файл _index в ее корне, чтобы при следующем запуске DISS переиндексировал каталог заново, и "увидел" бы внесенные изменения.
Далее в документе, везде, где указан путь к файлу, имеется ввиду DISS-путь.
Для хранения объектов, в корне DISS есть подкаталог media, в котором есть следующие подкаталоги:
- materials - для хранения файлов материалов;
- meshes - для графических 3d моделей;
- models - для файлов объектов;
- scenes - для файлов сцен;
- scripts - для файлов скриптов;
- textures - для текстур.
Отметим, что это лишь рекомендованные пути; Вы можете использовать любые другие в пределах DISS.
[править] Создание простого объекта
Для того, чтобы создать объект, нужны
- файл материала;
- файл 3d модели в формате OGRE mesh;
- необходимые материалу текстуры.
Все это можно получить, воспользовавшись одним из конверторов, доступных на официальном сайте OGRE.
Пожалуйста, обратите внимание, что все размеры в файле 3d модели должны указываться в метрах.
Если конвертер создает несколько файлов материалов, нужно объединить их в один (в произвольном порядке). Кроме того, нужно переправить пути к текстурам в файлах материалов на абсолютные DISS-пути (т.е. /media/textures/...).
Когда все это сделано, остается последний шаг - создать файл модели. Для этого нужно создать XML-файл объекта, который, в простейшем случае, выглядит следующим образом:
<source lang="xml"> <model bxd="http://dao.deeptown.org/bxd/model.bxd">
<material_script node="путь к файлу материала" /> <body name="main_body"> <geometry> </geometry> <surfaces> <mesh name="cube" node="путь к файлу 3d модели" /> </surfaces> </body>
</model> </source>
Чтобы теперь сконвертировать этот файл в bxl, воспользуйтесь командой
bxd filename.model.xml -f filename.model
где filename.model.xml - имя исходного файла, filename.model - имя получаемого файла модели.
Для того, чтобы использовать объект локально, необходимо задать его UID, записав его в метаинформацию DISS. В той же директории, где находится этот файл, создайте файл .meta и напишите туда следующее:
[filename.model] version = 0.1 wso_node = 1 wso_uid = 0101-0001-00000001-0000000000000001
UID (последняя строчка) должен различаться для каждой копии объекта в пространстве. Если один и тот же объект нужно использовать в сцене несколько раз, можно задать ему несколько UID-ов в метаинформации - задав несколько записей wso_uid.
В самом UID-е можно менять только последний (самый длинный) блок цифр (это шестнадцатиричные цифры, т.е. от 0 до F).
Если в директории находится несколько объектов, дописывайте в .meta секции одну за другой. Файл .meta сканируется при создании индекса DISS, так что при внесении изменений нужно удалять .index.
[править] Создание динамического объекта
Объект, приведенный в примере выше, будет статичным, т.е. все время находиться в одном и том же месте пространства (обладать бесконечной массой). Если нужен динамический объект, следует добавить в описание модели информацию о массе и моменте инерции объекта:
<source lang="xml"> <body name="main_body">
<mass_data> <mass value="1" /> <inertia i11="1" i22="1" i33="1" i12="0" i13="0" i23="0" /> </mass_data>
</body> </source>
Масса указывается в килограммах.
Момент инерции - в единицах СИ. Параметры - элементы симметричной матрицы инерции:
| i11 i12 i13 | | i12 i22 i23 | | i13 i23 i33 |
Вы можете не указывать тег inertia для простых тестов, но в этом случае объект будет вести себя неестественно.
[править] Связывание объекта со скриптом
Для того, чтобы получить возможность программировать поведение объекта, нужно прописать в него адрес скрипта. Добавьте внутрь корневого XML-тега следующее:
<source lang="xml"> <externals>
<event_receiver url="gide:/media/scripts/my_object.gbc!MyObject" />
</externals> </source>
В этом случае объект будет передавать все свои события объекту гайд-класса MyObject, объявленного в файле /media/scripts/my_object.gbc.
В этом файле должен находиться скомпилированный код класса. Простейший, ничего не делающий код такого класса на K++ выглядит следующим образом:
<source lang="kpp"> package my_object;
import world;
class MyObject extends WorldObject {
export function State_init() { }
} </source>
Напишите этот код в файл my_object.kpp в той же директории. Компилируется он командой
kpp my_object.kpp
[править] Добавление мотора
Мотор - это интерфейс объекта, позволяющий контролировать его поведение.
Все моторы объекта должны быть описаны в его файле модели. Делается это добавлением тега motor в корневую секцию: <source lang="xml"> <motor name="engine" url="linear_speed:main_body:(0,1,0)" /> </source>
Такой тег создаст мотор engine с типом linear_speed, прикладывающий силу к телу main_body (параметр name в теге body) по вектору направления (0,1,0) - т.е. вверх.
Всевозможные типы моторов описаны (еще нигде не описаны, дать ссылку).
По-умолчанию, мотор будет выключен. Для того, чтобы его включить, добавим в наш код следующее:
<source lang="kpp"> export function State_init() {
var engine = this.getMotor('engine'); // получили интерфейс мотора // первый параметр - имя, указанное при создании мотора (см. выше) engine.setParam('speed', 100); // максимальная скорость, сообщаемая объекту engine.setParam('force', 100); // максимальная сила, которая будет приложена для разгона engine.enable(); // включаем мотор
} </source>
[править] Обработка пользовательского ввода
Теперь научим наш объект реагировать на команду пользователя.
Например, нам нужно, чтобы мотор был включен только пока нажата клавиша A на клавиатуре.
Для этого нужно научить наш объект понимать две команды - "включить" и "выключить", а в конфигурации движка ввода написать отправку команды "включить" на нажатие клавиши, а "выключить" - на ее отпускание.
В файл /etc/world/input.conf в контекст local_control нужно добавить следующие строки:
on key_press check(key=A) do send_event:start_engine on key_release check(key=A) do send_event:stop_engine
Таким образом, когда пользователь нажимает клавишу A, нашему объекту будет отправлено уведомление start_engine, а когда отпускает - stop_engine.
Для того, чтобы обработать эти уведомления, напишем следующие два метода в наш класс:
<source lang="kpp"> export function Control_start_engine(const bytea args) {
this.getMotor('engine').enable();
}
export function Control_stop_engine(const bytea args) {
this.getMotor('engine').disable();
} </source>
(предполагается, что параметры мотора были установлены при инициализации, т.е. в State_init).
[править] Создание сенсора
Предположим, нам нужно, чтобы объект как-то реагировал на происходящее в окружающей среде. Для этого существуют сенсоры - интерфейсы, передающие информацию о происходящем.
На данный момент реализован только сенсор высоты, покажем работу с сенсорами на его примере:
<source lang="kpp"> export function State_init() {
// создаем сенсор высоты this.createSensor('height:>100', 'too_high');
}
export function Signal_too_high(const bytea args) {
// метод будет вызван при срабатывании сенсора, т.е. когда абсолютная // высота объекта превысит 100 метров. this.getMotor('engine').disable();
} </source>
Имя функции-обработчика формируется из префикса Signal_ и второго параметра функции createSensor.
[править] Создание сцены
Для того, чтобы теперь посмотреть на созданные объекты, нужно создать сцену и разместить на ней эти объекты, и затем загрузить сцену в движок.
Сцена также описывается в формате BXL. XML-файл сцены выглядит довольно просто:
<source lang="xml"> <scene bxd="http://dao.deeptown.org/bxd/scene.bxd">
<model uid="0101-0001-00000001-0000000000000002" x="0.2" y="0" z="-5" qw="1" qx="0" qy="0" qz="0" />
</scene> </source>
Тегов model может быть сколь угодно много. В параметрах этого тега указываются координаты объекта на сцене и кватернион его поворота.
[править] Пуск!
И теперь остался последний момент - загрузить все это в движок.
Для этого нужно набрать консольную команду
world.local_start /media/scenes/filename.scene UID
Первый параметр - имя файла сцены, второй - UID объекта, которому будет передаваться ввод пользователя.