Программирование поведения объекта — различия между версиями

Материал из Deeptown Manual
Перейти к: навигация, поиск
(RpnJHdKtlUrsvrrU)
 
Строка 1: Строка 1:
0, http://www.americanbeergeekinparis.com/2010/10/10610.html more, http://pocobutton.com/post/667329663 pocobutton .com, http://pocobutton.com/post/515490915 Alligator alley, http://www.americanbeergeekinparis.com/2010/10/tonights-brew.html americanbeergeekinparis com, http://pocobutton.com/post/473033211 gokshura banyan,
+
Перейдем от теории к практике. Перед прочтением этого документа рекомендуется ознакомиться с предыдущими. Здесь приведены конкретные рецепты - как и что делать, с примерами и их разбором.
 +
 
 +
== Где хранить файлы? ==
 +
 
 +
Ядро Диптауна использует 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;
 +
* необходимые материалу текстуры.
 +
 
 +
Все это можно получить, воспользовавшись одним из конверторов, доступных на [http://www.ogre3d.org/index.php?option=com_content&task=view&id=413&Itemid=133 официальном сайте 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 объекта, которому будет передаваться ввод пользователя.

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

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

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