A-Frame строится на архитектуре Entity-Component-System (ECS), что является ключевой концепцией для создания гибких и масштабируемых 3D-приложений на основе WebVR и WebXR. ECS обеспечивает модульность и разделение ответственности между объектами сцены, их поведением и данными.
Entity в A-Frame — это базовый объект сцены, который
сам по себе практически не имеет функциональности. Сущность выступает
как контейнер для компонентов и служит идентификатором, к которому
привязываются данные и поведение. Каждая сущность в DOM представлена
тегом <a-entity>.
Примеры свойств сущности:
<a-entity id="boxEntity" position="0 1 -3"></a-entity>
id — уникальный идентификатор сущности.position — положение в трехмерном пространстве.Сущности могут быть вложенными, образуя иерархию сцены, что упрощает управление сложными объектами, например, моделями с множеством частей.
Component — это модуль, который добавляет функциональность сущности. Компонент содержит данные (properties) и поведение (methods), влияющие на отображение или логику объекта. В A-Frame компоненты могут быть встроенными (built-in) или пользовательскими.
Пример встроенного компонента:
<a-entity geometry="primitive: box" material="color: red"></a-entity>
geometry задаёт форму объекта.material управляет визуальными характеристиками.Компоненты могут обновлять состояние сущности на каждом кадре с
использованием tick-функции:
AFRAME.registerComponent('spin', {
schema: { speed: { type: 'number', default: 1 } },
tick: function (time, timeDelta) {
this.el.object3D.rotation.y += this.data.speed * timeDelta / 1000;
}
});
Добавление компонента к сущности:
<a-entity spin="speed: 2"></a-entity>
System управляет группой компонентов и обеспечивает централизованное управление логикой на уровне всей сцены. Системы полезны для задач, требующих координации нескольких сущностей, например, управление физикой, звуком или сетевым взаимодействием.
Пример системы:
AFRAME.registerSystem('gravity', {
init: function () {
this.gravity = -9.8;
},
tick: function (time, deltaTime) {
this.el.querySelectorAll('[dynamic-body]').forEach(function(entity) {
let body = entity.body;
body.velocity.y += this.gravity * deltaTime / 1000;
}, this);
}
});
Такое разделение позволяет:
Каждый компонент имеет schema, определяющую типы данных, значения по умолчанию и способы их обработки. Это обеспечивает строгую типизацию и упрощает валидацию:
AFRAME.registerComponent('color-changer', {
schema: {
color: { type: 'color', default: '#FFF' },
interval: { type: 'number', default: 1000 }
},
init: function () {
this.time = 0;
},
tick: function (time, timeDelta) {
this.time += timeDelta;
if (this.time > this.data.interval) {
this.el.setAttribute('material', 'color', '#' + Math.floor(Math.random()*16777215).toString(16));
this.time = 0;
}
}
});
tick всех
компонентов, позволяя обновлять состояние.setAttribute автоматически синхронизируется с
компонентами.A-Frame использует систему событий для взаимодействия между сущностями и компонентами:
el.addEventListener('collide', function (event) {
console.log('Столкновение с', event.detail.body.el);
});
Компоненты могут слушать события сущности, системы могут реагировать на события всех компонентов определённого типа. Это повышает модульность и позволяет строить сложное поведение без жесткой привязки к конкретной сущности.
ECS в A-Frame обеспечивает гибкость, масштабируемость и чистоту архитектуры, позволяя создавать динамичные и интерактивные VR/AR-сцены с легко поддерживаемым кодом.