Основы программирования объектов — различия между версиями
Root (обсуждение | вклад) м (→Класс Sensor) |
Root (обсуждение | вклад) м (→Класс Sensor) |
||
(не показаны 3 промежуточные версии 1 участника) | |||
Строка 13: | Строка 13: | ||
<!-- ... --> | <!-- ... --> | ||
<externals> | <externals> | ||
− | <event_receiver url="gide:/media/scripts/cube_small_dynamic.gbc!CubeSmallDynamic" /> | + | <event_receiver url="gide:/media/scripts/cube_small_dynamic.gbc!cube_small_dynamic/CubeSmallDynamic" /> |
</externals> | </externals> | ||
</model> | </model> | ||
</source> | </source> | ||
− | Как видим, в адресе фигурирует имя DISS-файла с байткодом (расширение gbc) и имя класса, который будет обрабатывать события нашего объекта. | + | Как видим, в адресе фигурирует имя DISS-файла с байткодом (расширение gbc) и имя класса, который будет обрабатывать события нашего объекта. Обратите внимание, что имя класса - '''полное'''; оно состоит из имени модуля (слово после '''package'''), символа "/" и имени класса. |
Все примеры далее будут написаны на языке [[K++]]. | Все примеры далее будут написаны на языке [[K++]]. | ||
Строка 27: | Строка 27: | ||
package cube_small_dynamic; | package cube_small_dynamic; | ||
− | import | + | import World; |
+ | using World; | ||
class CubeSmallDynamic extends WorldObject | class CubeSmallDynamic extends WorldObject | ||
Строка 34: | Строка 35: | ||
</source> | </source> | ||
− | Т.е. это просто класс, унаследованный от класса WorldObject, объявленного в модуле | + | Т.е. это просто класс, унаследованный от класса WorldObject, объявленного в модуле World. |
== Обработка уведомлений == | == Обработка уведомлений == | ||
Все уведомления, которые приходят к объекту, по-умолчанию передаются методам нашего объекта-обработчика, имя которых строится из типа уведомления и имени события. Более подробно об этом будет рассказано в разделах, посвященных конкретным взаимодействиям; сейчас нам важно отметить одно: чтобы обработать какое-либо уведомление, все, что нужно сделать - это добавить в тело нашего класса функцию-обработчик со специальным именем. Никаких дополнительных манипуляций, как то регистрация этого обработчика где-либо, или вызов его в зависимости от каких-либо условий, делать не нужно. | Все уведомления, которые приходят к объекту, по-умолчанию передаются методам нашего объекта-обработчика, имя которых строится из типа уведомления и имени события. Более подробно об этом будет рассказано в разделах, посвященных конкретным взаимодействиям; сейчас нам важно отметить одно: чтобы обработать какое-либо уведомление, все, что нужно сделать - это добавить в тело нашего класса функцию-обработчик со специальным именем. Никаких дополнительных манипуляций, как то регистрация этого обработчика где-либо, или вызов его в зависимости от каких-либо условий, делать не нужно. | ||
− | |||
− | |||
Например, когда объект создается, ему высылается уведомление о состоянии объекта "init". Для того, чтобы обработать это уведомление, нужно определить в нашем классе метод State_init без параметров: | Например, когда объект создается, ему высылается уведомление о состоянии объекта "init". Для того, чтобы обработать это уведомление, нужно определить в нашем классе метод State_init без параметров: | ||
Строка 47: | Строка 46: | ||
class CubeSmallDynamic extends WorldObject | class CubeSmallDynamic extends WorldObject | ||
{ | { | ||
− | + | public: | |
+ | function void State_init() | ||
{ | { | ||
// Функция будет вызвана в момент создания объекта | // Функция будет вызвана в момент создания объекта | ||
Строка 98: | Строка 98: | ||
class MyObject extends WorldObject | class MyObject extends WorldObject | ||
{ | { | ||
− | + | public: | |
+ | function void State_init() | ||
{ | { | ||
// Создаем сенсор: | // Создаем сенсор: | ||
− | this.createSensor('type:address', | + | this.createSensor('type:address', :makaka); |
} | } | ||
// Функция-обработчик сигнала makaka, который будет послан сенсором | // Функция-обработчик сигнала makaka, который будет послан сенсором | ||
// в случае его срабатывания: | // в случае его срабатывания: | ||
− | + | function Signal_makaka(const bytea args) | |
{ | { | ||
// Реакция на сигнал... | // Реакция на сигнал... | ||
Строка 158: | Строка 159: | ||
public function array const paramNames(); // список параметров | public function array const paramNames(); // список параметров | ||
public function getParam(const string name); // получить параметр | public function getParam(const string name); // получить параметр | ||
− | public function void setParam(const string name, const | + | public function void setParam(const string name, const value); // установить |
} | } | ||
</source> | </source> | ||
Строка 175: | Строка 176: | ||
* строку. | * строку. | ||
− | В setParam() значение параметра нужно указывать в виде | + | В setParam() значение параметра нужно указывать в том же виде, в котором его вернула getParam(). Более подробно это описано в документации по конкретным сенсорам. |
Текущая версия на 14:01, 27 апреля 2008
Каждое уведомление, которое получает объект (а таких уведомлений бывает 5 типов - см. предыдущий раздел), он передает в свой обработчик событий (у одного объекта может быть несколько обработчиков, но использовать эту возможность не рекомендуется).
Сам обработчик может быть реализован либо в движке, либо в модуле-расширении - это просто некоторый объект, получающий события и выполняющий определенные действия на них. Но в данном разделе нас будет интересовать прикладное программирование объектов на гайд-совместимых языках.
Для того, чтобы это стало возможным, реализован обработчик gide, который все полученные события передает гайд-объекту, а также предоставляет ряд классов для работы с объектом из прикладного кода.
Содержание |
[править] Задание обработчика для объекта
Как уже было сказано в примере в предыдущем разделе, URL обработчика задается в файле описания объекта следующим образом:
<source lang="xml"> <model bxd="http://dao.deeptown.org/bxd/model.bxd">
<externals> <event_receiver url="gide:/media/scripts/cube_small_dynamic.gbc!cube_small_dynamic/CubeSmallDynamic" /> </externals>
</model> </source>
Как видим, в адресе фигурирует имя DISS-файла с байткодом (расширение gbc) и имя класса, который будет обрабатывать события нашего объекта. Обратите внимание, что имя класса - полное; оно состоит из имени модуля (слово после package), символа "/" и имени класса.
Все примеры далее будут написаны на языке K++.
Вот простейший код обработчика, который никак не реагирует на события, происходящие с объектом:
<source lang="kpp"> package cube_small_dynamic;
import World; using World;
class CubeSmallDynamic extends WorldObject { } </source>
Т.е. это просто класс, унаследованный от класса WorldObject, объявленного в модуле World.
[править] Обработка уведомлений
Все уведомления, которые приходят к объекту, по-умолчанию передаются методам нашего объекта-обработчика, имя которых строится из типа уведомления и имени события. Более подробно об этом будет рассказано в разделах, посвященных конкретным взаимодействиям; сейчас нам важно отметить одно: чтобы обработать какое-либо уведомление, все, что нужно сделать - это добавить в тело нашего класса функцию-обработчик со специальным именем. Никаких дополнительных манипуляций, как то регистрация этого обработчика где-либо, или вызов его в зависимости от каких-либо условий, делать не нужно.
Например, когда объект создается, ему высылается уведомление о состоянии объекта "init". Для того, чтобы обработать это уведомление, нужно определить в нашем классе метод State_init без параметров:
<source lang="kpp"> class CubeSmallDynamic extends WorldObject { public:
function void State_init() { // Функция будет вызвана в момент создания объекта }
} </source>
[править] Функции и классы модуля world
[править] Класс Object
Этот класс является прародителем всех классов, представляющих объекты виртуального пространства. В нем определены следующие методы:
<source lang="kpp"> class Object {
constructor connect(const uid UID); // создает объект по его UID public operator Object = (const Object obj); // оператор присваивания public function uid const getUID(); // возвращает UID объекта public function bool const isLocal(); // true если объект находится на текущем сервере
} </source>
Отдельного комментария заслуживает лишь метод isLocal(). Он возвращает true, если объект, с которым мы работаем, находится на том же сервере, на котором находится наш обработчик. Дело в том, что объекты в сети Диптауна могут передаваться от сервера к серверу в процессе существования, и если объект находится на другом сервере, общение с ним происходит по относительно медленному механизму событий сетевого движка.
[править] Класс WorldObject
Этот класс унаследован от Object и представляет собой интерфейс для объекта пространства. В нем определены следующие методы:
<source lang="kpp"> class WorldObject extends Object {
constructor connect(const uid UID); // аналогично public function WorldObject const guest(); // сброс привелегий public function array const motorNames(); // список моторов public function Motor const getMotor(const string name); // мотор по имени public function Sensor const createSensor(const string url, const string signal); // создать сенсор
} </source>
Функция guest возвращает копию данного объекта, не обладающую привелегиями управления своими моторами и сенсорами. На данный момент, просто не обращайте на нее внимания.
Функция motorNames() возвращает массив строк - имен моторов, которые установлены на объекте. Напоминаю, что сами моторы перечислены в файле описания объекта и не могут быть динамически добавлены или удалены.
Функция getMotor() возвращает мотор по его имени (см. описание класса ниже).
Функция createSensor() создает сенсор. Первый параметр - это URL сенсора, который, как обычно, состоит из типа и адреса, разделенных двоеточием. Второй параметр - имя сигнала, который будет передан нашему обработчику в случае срабатвания сенсора. В классе должен быть определен метод Signal_xxx, где xxx - это имя сигнала. Например:
<source lang="kpp"> class MyObject extends WorldObject { public:
function void State_init() { // Создаем сенсор: this.createSensor('type:address', :makaka); }
// Функция-обработчик сигнала makaka, который будет послан сенсором // в случае его срабатывания: function Signal_makaka(const bytea args) { // Реакция на сигнал... }
} </source>
Обратите также внимание, что в функцию-обработчик сигнала передается параметр типа bytea. Его значение зависит от конкретного сенсора, здесь могут быть произвольные параметры, упакованные в бинарную строку. Для их распаковки реализована вспомогательная функция parseArguments().
[править] Класс Scene
Пока не рассматриваем.
[править] Класс Motor
Данный класс предоставляет интерфейс мотора. Объекты этого класса создаются путем вызова метода getMotor() объекта-обработчика.
<source lang="kpp"> class Motor {
public operator Motor = (const Motor what); public function void enable(); // включить мотор public function void disable(); // выключить public function bool isEnabled(); // включен ли? public function array const paramNames(); // имена параметров public function real const getParam(const string name); // получить параметр public function void setParam(const string name, const real value); // установить параметр public function array const statusNames(); // имена статусов public function real const getStatus(const string name); // получить статус
} </source>
Для включения и выключения мотора служат функции enable() и disable(). По-умолчанию все моторы выключены. Функция isEnabled() возвращает текущее состояние мотора.
Функции paramNames(), getParam() и setParam() позволяют управлять параметрами мотора. Количество и смысл этих параметров зависит от конкретного типа мотора. Например, у уже рассмотренного нами в предыдущих разделах мотора linear_speed таких параметров два: speed и force. speed определяет скорость, до которой мотор разгоняет объект, а force - максимальную силу, которую мотор прикладывает к объекту.
Аналогично, statusNames() и getStatus() позволяют получать статусы мотора, которые также зависят от конкретного типа мотора.
[править] Класс Sensor
Данный класс предоставляет интерфейс сенсора. Объекты этого класса создаются путем вызова метода createSensor() объекта-обработчика. Обратите внимание, что сенсоры никак не проиндексированы в объекте, т.е. создав сенсор, невозможно потом получить его интерфейс по имени или еще каким-либо способом. Поэтому, если Вам требуется изменять какие-то параметры сенсора после его создания, сохраняйте его экземпляр в полях класса.
<source lang="kpp"> class Sensor {
public operator Sensor = (const Sensor what); public function void enable(); // включить сенсор public function void disable(); // выключить сенсор public function bool isEnabled(); // включен ли? public function void erase(); // удалить сенсор public function array const paramNames(); // список параметров public function getParam(const string name); // получить параметр public function void setParam(const string name, const value); // установить
} </source>
Функции enable() / disable() включают / выключают сенсор. В отличие от моторов, при создании сенсор по-умолчанию включен. isEnabled() возвращает текущее состояние.
Функция erase() удаляет сенсор. Все обращения к другим методам после erase() приведут к генерации исключения.
Функции paramNames() / getParam() / setParam() управляют параметрами сенсора. В отличие от параметров моторов, параметры сенсоров могут иметь произвольный простой тип. Функция getParam() может вернуть:
- целое число
- массив целых чисел
- вещественное число
- массив вещественных чисел
- uid
- массив из uid
- строку.
В setParam() значение параметра нужно указывать в том же виде, в котором его вернула getParam(). Более подробно это описано в документации по конкретным сенсорам.