Доступ к системе из компонента

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


Системы и их назначение

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

  • Управления состоянием сцены (например, глобальная физика, освещение, звук).
  • Хранения общих ресурсов (текстуры, модели, шейдеры).
  • Синхронизации действий нескольких компонентов.

Пример регистрации системы:

AFRAME.registerSystem('score', {
  schema: { total: { type: 'int', default: 0 } },

  init: function () {
    console.log('Система Score инициализирована');
  },

  addPoints: function (points) {
    this.data.total += points;
    console.log('Общий счет:', this.data.total);
  }
});

Система score хранит общий счет и предоставляет метод addPoints для обновления.


Доступ к системе из компонента

Компоненты могут получать доступ к любой системе, используя метод this.el.sceneEl.systems. Это объект, где ключи — это имена зарегистрированных систем.

Пример использования системы в компоненте:

AFRAME.registerComponent('coin', {
  schema: { value: { type: 'int', default: 1 } },

  init: function () {
    this.scoreSystem = this.el.sceneEl.systems['score'];
  },

  collect: function () {
    if (this.scoreSystem) {
      this.scoreSystem.addPoints(this.data.value);
      this.el.parentNode.removeChild(this.el);
    }
  }
});

Здесь компонент coin при сборе монеты обращается к системе score и добавляет очки.

Важно: this.el.sceneEl.systems['имя_системы'] возвращает систему, уже инициализированную сценой, поэтому доступ к ней возможен после init компонента.


Жизненный цикл доступа

  1. init() — инициализация компонента; можно сохранять ссылку на систему.
  2. update() — обновление данных компонента; можно взаимодействовать с системой при изменении свойств.
  3. tick() — вызов на каждом кадре; допустимо постоянное обращение к системе.
  4. remove() — очистка ресурсов; можно уведомлять систему об удалении компонента.

Пример использования жизненного цикла:

AFRAME.registerComponent('health', {
  schema: { max: 100, current: 100 },

  init: function () {
    this.healthSystem = this.el.sceneEl.systems['health'];
    this.healthSystem.registerEntity(this.el);
  },

  tick: function (time, delta) {
    if (this.data.current <= 0) {
      this.healthSystem.deregisterEntity(this.el);
      this.el.parentNode.removeChild(this.el);
    }
  }
});

Взаимодействие нескольких компонентов с одной системой

Система может быть точкой синхронизации для множества компонентов. Например, несколько компонентов могут изменять один и тот же ресурс:

AFRAME.registerSystem('music', {
  init: function () {
    this.isPlaying = false;
  },
  play: function () { this.isPlaying = true; },
  stop: function () { this.isPlaying = false; }
});

AFRAME.registerComponent('button-play', {
  init: function () {
    this.musicSystem = this.el.sceneEl.systems['music'];
    this.el.addEventListener('click', () => {
      this.musicSystem.play();
    });
  }
});

AFRAME.registerComponent('button-stop', {
  init: function () {
    this.musicSystem = this.el.sceneEl.systems['music'];
    this.el.addEventListener('click', () => {
      this.musicSystem.stop();
    });
  }
});

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


Рекомендации по архитектуре

  • Использовать системы для глобального состояния и ресурсов, которые должны быть доступны нескольким компонентам.
  • Компоненты должны хранить только ссылку на систему, избегая дублирования логики.
  • Проверять существование системы перед обращением (if (this.el.sceneEl.systems['имя'])).
  • Для сложных взаимодействий применять методы системы, а не напрямую изменять свойства данных.

Доступ к системе через AFRAME.systems

Помимо обращения через el.sceneEl.systems, можно использовать глобальный объект A-Frame:

const scoreSystem = AFRAME.scenes[0].systems['score'];
scoreSystem.addPoints(10);

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


Итоговые принципы

  • Системы — это единые менеджеры данных и поведения.
  • Компоненты обращаются к системам через this.el.sceneEl.systems.
  • Ссылку на систему обычно сохраняют в init().
  • Система может обслуживать несколько компонентов, обеспечивая централизованное управление.
  • Проверка существования системы обязательна для избежания ошибок при динамическом создании компонентов.

Эти подходы обеспечивают чистую архитектуру сцены и позволяют создавать масштабируемые VR-приложения на A-Frame.