Основы программирования объектов

Материал из Deeptown Manual

Перейти к: навигация, поиск

Каждое уведомление, которое получает объект (а таких уведомлений бывает 5 типов - см. предыдущий раздел), он передает в свой обработчик событий (у одного объекта может быть несколько обработчиков, но использовать эту возможность не рекомендуется).

Сам обработчик может быть реализован либо в движке, либо в модуле-расширении - это просто некоторый объект, получающий события и выполняющий определенные действия на них. Но в данном разделе нас будет интересовать прикладное программирование объектов на гайд-совместимых языках.

Для того, чтобы это стало возможным, реализован обработчик gide, который все полученные события передает гайд-объекту, а также предоставляет ряд классов для работы с объектом из прикладного кода.

Содержание

[править] Задание обработчика для объекта

Как уже было сказано в примере в предыдущем разделе, URL обработчика задается в файле описания объекта следующим образом:

<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>

Как видим, в адресе фигурирует имя DISS-файла с байткодом (расширение gbc) и имя класса, который будет обрабатывать события нашего объекта. Обратите внимание, что имя класса - полное; оно состоит из имени модуля (слово после package), символа "/" и имени класса.

Все примеры далее будут написаны на языке K++.

Вот простейший код обработчика, который никак не реагирует на события, происходящие с объектом:

package cube_small_dynamic;
 
import World;
using World;
 
class CubeSmallDynamic extends WorldObject
{
}

Т.е. это просто класс, унаследованный от класса WorldObject, объявленного в модуле World.

[править] Обработка уведомлений

Все уведомления, которые приходят к объекту, по-умолчанию передаются методам нашего объекта-обработчика, имя которых строится из типа уведомления и имени события. Более подробно об этом будет рассказано в разделах, посвященных конкретным взаимодействиям; сейчас нам важно отметить одно: чтобы обработать какое-либо уведомление, все, что нужно сделать - это добавить в тело нашего класса функцию-обработчик со специальным именем. Никаких дополнительных манипуляций, как то регистрация этого обработчика где-либо, или вызов его в зависимости от каких-либо условий, делать не нужно.

Например, когда объект создается, ему высылается уведомление о состоянии объекта "init". Для того, чтобы обработать это уведомление, нужно определить в нашем классе метод State_init без параметров:

class CubeSmallDynamic extends WorldObject
{
public:
    function void State_init()
    {
        // Функция будет вызвана в момент создания объекта
    }
}

[править] Функции и классы модуля world

[править] Класс Object

Этот класс является прародителем всех классов, представляющих объекты виртуального пространства. В нем определены следующие методы:

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 если объект находится на текущем сервере
}

Отдельного комментария заслуживает лишь метод isLocal(). Он возвращает true, если объект, с которым мы работаем, находится на том же сервере, на котором находится наш обработчик. Дело в том, что объекты в сети Диптауна могут передаваться от сервера к серверу в процессе существования, и если объект находится на другом сервере, общение с ним происходит по относительно медленному механизму событий сетевого движка.

[править] Класс WorldObject

Этот класс унаследован от Object и представляет собой интерфейс для объекта пространства. В нем определены следующие методы:

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); // создать сенсор
}

Функция guest возвращает копию данного объекта, не обладающую привелегиями управления своими моторами и сенсорами. На данный момент, просто не обращайте на нее внимания.

Функция motorNames() возвращает массив строк - имен моторов, которые установлены на объекте. Напоминаю, что сами моторы перечислены в файле описания объекта и не могут быть динамически добавлены или удалены.

Функция getMotor() возвращает мотор по его имени (см. описание класса ниже).

Функция createSensor() создает сенсор. Первый параметр - это URL сенсора, который, как обычно, состоит из типа и адреса, разделенных двоеточием. Второй параметр - имя сигнала, который будет передан нашему обработчику в случае срабатвания сенсора. В классе должен быть определен метод Signal_xxx, где xxx - это имя сигнала. Например:

class MyObject extends WorldObject
{
public:
    function void State_init()
    {
        // Создаем сенсор:
        this.createSensor('type:address', :makaka);
    }
 
    // Функция-обработчик сигнала makaka, который будет послан сенсором
    // в случае его срабатывания:
    function Signal_makaka(const bytea args)
    {
        // Реакция на сигнал...
    }
}

Обратите также внимание, что в функцию-обработчик сигнала передается параметр типа bytea. Его значение зависит от конкретного сенсора, здесь могут быть произвольные параметры, упакованные в бинарную строку. Для их распаковки реализована вспомогательная функция parseArguments().

[править] Класс Scene

Пока не рассматриваем.

[править] Класс Motor

Данный класс предоставляет интерфейс мотора. Объекты этого класса создаются путем вызова метода getMotor() объекта-обработчика.

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); // получить статус
}

Для включения и выключения мотора служат функции enable() и disable(). По-умолчанию все моторы выключены. Функция isEnabled() возвращает текущее состояние мотора.

Функции paramNames(), getParam() и setParam() позволяют управлять параметрами мотора. Количество и смысл этих параметров зависит от конкретного типа мотора. Например, у уже рассмотренного нами в предыдущих разделах мотора linear_speed таких параметров два: speed и force. speed определяет скорость, до которой мотор разгоняет объект, а force - максимальную силу, которую мотор прикладывает к объекту.

Аналогично, statusNames() и getStatus() позволяют получать статусы мотора, которые также зависят от конкретного типа мотора.

[править] Класс Sensor

Данный класс предоставляет интерфейс сенсора. Объекты этого класса создаются путем вызова метода createSensor() объекта-обработчика. Обратите внимание, что сенсоры никак не проиндексированы в объекте, т.е. создав сенсор, невозможно потом получить его интерфейс по имени или еще каким-либо способом. Поэтому, если Вам требуется изменять какие-то параметры сенсора после его создания, сохраняйте его экземпляр в полях класса.

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); // установить
}

Функции enable() / disable() включают / выключают сенсор. В отличие от моторов, при создании сенсор по-умолчанию включен. isEnabled() возвращает текущее состояние.

Функция erase() удаляет сенсор. Все обращения к другим методам после erase() приведут к генерации исключения.

Функции paramNames() / getParam() / setParam() управляют параметрами сенсора. В отличие от параметров моторов, параметры сенсоров могут иметь произвольный простой тип. Функция getParam() может вернуть:

  • целое число
  • массив целых чисел
  • вещественное число
  • массив вещественных чисел
  • uid
  • массив из uid
  • строку.

В setParam() значение параметра нужно указывать в том же виде, в котором его вернула getParam(). Более подробно это описано в документации по конкретным сенсорам.

документация