Глобальное состояние через системы

В A-Frame системы используются для управления глобальным состоянием приложения, обеспечивая централизованное хранение данных, которые могут использоваться компонентами на разных сущностях. Системы создаются аналогично компонентам, но они не привязаны к конкретной сущности и живут на уровне сцены. Основная задача системы — инкапсулировать логику и состояние, доступное для компонентов, обеспечивая единый источник правды.


Создание системы

Система определяется через метод AFRAME.registerSystem(name, definition). Параметр name задает уникальное имя системы, а definition — объект, содержащий свойства и методы. Стандартная структура системы включает:

  • schema — описание конфигурации с типами данных и значениями по умолчанию.
  • init() — инициализация системы при загрузке сцены.
  • update(oldData) — реагирование на изменения конфигурации.
  • tick(time, timeDelta) — вызов на каждом кадре рендеринга.
  • Дополнительные методы для работы с состоянием.

Пример создания системы для управления глобальным светом:

AFRAME.registerSystem('lighting', {
  schema: {
    intensity: { type: 'number', default: 1.0 },
    color: { type: 'color', default: '#ffffff' }
  },

  init: function () {
    this.lights = [];
  },

  addLight: function (lightEl) {
    this.lights.push(lightEl);
    lightEl.setAttribute('light', {
      intensity: this.data.intensity,
      color: this.data.color
    });
  },

  update: function (oldData) {
    this.lights.forEach(lightEl => {
      lightEl.setAttribute('light', {
        intensity: this.data.intensity,
        color: this.data.color
      });
    });
  }
});

В этом примере система хранит массив всех источников света сцены и обеспечивает синхронизацию их свойств с глобальным состоянием.


Использование системы в компонентах

Компоненты могут обращаться к системе через объект сцены: this.el.sceneEl.systems['systemName']. Это позволяет компонентам получать и изменять глобальное состояние, не дублируя логику.

Пример компонента, который регистрирует себя в системе света:

AFRAME.registerComponent('dynamic-light', {
  init: function () {
    const lightingSystem = this.el.sceneEl.systems['lighting'];
    lightingSystem.addLight(this.el);
  }
});

Такой подход обеспечивает единую точку управления и исключает необходимость хранения состояния на каждой отдельной сущности.


Глобальные события и реактивность

Системы могут создавать и обрабатывать собственные события, чтобы компоненты реагировали на изменения состояния. Для этого используется emit и addEventListener на объекте сцены:

AFRAME.registerSystem('game', {
  init: function () {
    this.score = 0;
  },

  increaseScore: function (points) {
    this.score += points;
    this.el.sceneEl.emit('score-changed', { score: this.score });
  }
});

AFRAME.registerComponent('score-display', {
  init: function () {
    const gameSystem = this.el.sceneEl.systems['game'];
    this.el.addEventListener('score-changed', evt => {
      this.el.setAttribute('text', 'value', `Score: ${evt.detail.score}`);
    });
  }
});

Такой подход делает систему реактивной, позволяя компонентам автоматически обновлять своё состояние при изменении глобальных данных.


Паттерны управления состоянием

  1. Централизация данных — все ключевые состояния приложения хранятся в системах, а компоненты только читают или инициируют изменения.
  2. Методы управления — система предоставляет интерфейс для работы с состоянием, предотвращая прямое изменение данных компонентами.
  3. Событийная синхронизация — компоненты подписываются на события системы, что обеспечивает реактивное обновление без постоянной проверки состояния.
  4. Инициализация сущностей — при создании сущности компонент может автоматически регистрироваться в системе, получая нужное состояние.

Особенности и рекомендации

  • Системы живут на уровне сцены, поэтому они доступны всем компонентам независимо от их расположения в иерархии сущностей.
  • Дублирование состояния следует избегать: если данные есть в системе, компоненты должны ссылаться на них, а не хранить копии.
  • Асинхронные операции внутри систем (например, загрузка моделей или данных с сервера) следует управлять через промисы или колбэки, уведомляя компоненты через события.
  • Система как сервис: лучше воспринимать её как сервисный слой, который инкапсулирует логику и предоставляет API для компонентов.

Встроенные системы A-Frame

A-Frame предоставляет встроенные системы, которые управляют общим состоянием сцены:

  • camera — глобальная настройка камеры.
  • renderer — рендеринг и настройка WebGL.
  • physics (если подключён физический плагин) — управление физикой всех объектов.
  • audio — управление глобальным звуком сцены.

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