Событийная модель компонентов

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

Сущности и события

В A-Frame сущность (<a-entity>) — это контейнер для компонентов. События могут быть двух типов:

  1. DOM-события — стандартные события браузера (click, mouseenter, mouseleave и т.д.), которые A-Frame расширяет для работы с 3D-сценой.
  2. Пользовательские события — создаются компонентами для передачи информации между сущностями или для внутренней логики компонента (hit, spawn, activated и др.).

Каждое событие имеет имя и может содержать объект detail с произвольными данными.

<a-entity id="box" geometry="primitive: box" material="color: red"></a-entity>

<script>
  const box = document.querySelector('#box');

  box.addEventListener('click', event => {
    console.log('Событие click на кубе', event);
  });

  box.addEventListener('custom-event', event => {
    console.log('Пользовательское событие:', event.detail);
  });

  box.emit('custom-event', { info: 'Данные события' });
</script>

В примере выше emit используется для генерации пользовательского события с объектом detail. Событие может быть перехвачено любым компонентом или сущностью в иерархии сцены.

Обработка событий внутри компонентов

Компоненты A-Frame позволяют подписываться на события прямо внутри объекта init или других методов жизненного цикла.

AFRAME.registerComponent('interactive-box', {
  init: function () {
    this.el.addEventListener('mouseenter', () => {
      this.el.setAttribute('material', 'color', 'green');
    });

    this.el.addEventListener('mouseleave', () => {
      this.el.setAttribute('material', 'color', 'red');
    });

    this.el.addEventListener('activate', e => {
      console.log('Событие activate с данными:', e.detail);
    });
  }
});

Ключевые моменты:

  • this.el всегда ссылается на сущность, к которой прикреплён компонент.
  • Методы addEventListener и removeEventListener позволяют динамически управлять подпиской на события.
  • События можно инициировать как из компонентов, так и извне с помощью метода emit.

Всплытие и делегирование событий

A-Frame поддерживает всплытие событий, аналогично DOM-модели:

  • Событие, вызванное на дочерней сущности, может быть перехвачено родительской сущностью, если указано bubbles: true при вызове emit.
  • Это позволяет создавать делегированную обработку, когда родитель реагирует на действия дочерних компонентов без их прямого вмешательства.
childEl.emit('jump', { height: 2 }, true); // true включает всплытие
parentEl.addEventListener('jump', e => {
  console.log('Родительская сущность перехватила событие', e.detail);
});

Жизненный цикл событий

События можно использовать для синхронизации состояния компонентов:

  • init — инициализация компонента. События могут подписываться здесь.
  • update — вызывается при изменении атрибутов компонента. Можно отправлять события об изменении состояния.
  • remove — отписка от событий при удалении компонента, чтобы избежать утечек памяти.
AFRAME.registerComponent('color-changer', {
  init: function () {
    this.onCl ick = () => this.el.setAttribute('material', 'color', 'blue');
    this.el.addEventListener('click', this.onClick);
  },
  remove: function () {
    this.el.removeEventListener('click', this.onClick);
  }
});

Передача данных через detail

Объект detail — основной способ передачи данных в событиях. Он может содержать любые структуры: числа, строки, объекты.

el.emit('health-changed', { current: 80, max: 100 });
el.addEventListener('health-changed', e => {
  console.log(`Здоровье: ${e.detail.current} / ${e.detail.max}`);
});

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

Практические паттерны

  1. Компонент-коммуникатор — центральный компонент, который слушает и перенаправляет события между объектами сцены.
  2. События для анимаций — запуск анимации при получении события, например, open-door, explode.
  3. События для логики игры — активация триггеров, сбор предметов, изменение состояния персонажа.

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

Рекомендации по организации событий

  • Использовать описательные имена событий (enemy-hit, item-collected).
  • Всегда передавать важные данные через detail.
  • Отписываться от событий в remove или при завершении действия компонента.
  • Разделять события визуальные и логические, чтобы не смешивать рендер и игровую логику.

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