Программирование поведения объекта

Материал из Deeptown Manual
Версия от 15:12, 13 июля 2013; Raw mat (обсуждение | вклад)

(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

Перейдем от теории к практике. Перед прочтением этого документа рекомендуется ознакомиться с предыдущими. Здесь приведены конкретные рецепты - как и что делать, с примерами и их разбором.

Содержание

Где хранить файлы?

Ядро Диптауна использует 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 объекта, которому будет передаваться ввод пользователя.

Персональные инструменты
Пространства имён

Варианты
Действия
Навигация
информация
документация
Инструменты