В A-Frame сцена представляет собой дерево сущностей
(entities), корневым элементом которого является
<a-scene>. Каждая сущность
(<a-entity>) может содержать компоненты, задающие
геометрию, материалы, поведение, события и взаимодействия. Динамическая
модификация сцены вне цикла рендера позволяет создавать, удалять и
изменять объекты на лету без необходимости перезагружать сцену или
вручную управлять рендерингом WebGL.
Для работы с сущностями используется стандартный DOM-API. Любой
элемент можно добавить через
document.createElement('a-entity') и установить для него
необходимые компоненты с помощью метода setAttribute.
Например:
const entity = document.createElement('a-entity');
entity.setAttribute('geometry', { primitive: 'box', height: 2, width: 2, depth: 2 });
entity.setAttribute('material', { color: '#FF0000' });
document.querySelector('a-scene').appendChild(entity);
В этом примере создается красный куб, который автоматически появляется в сцене без участия цикла рендера.
Каждый компонент в A-Frame можно изменять динамически через
setAttribute или removeAttribute. Это
позволяет обновлять свойства объектов в любой момент времени. Например,
изменение цвета материала:
const box = document.querySelector('#myBox');
box.setAttribute('material', 'color', '#00FF00');
Важно понимать различие между передачей объекта и строки при вызове
setAttribute:
box.setAttribute('material', { color: '#00FF00' }); —
передача объекта JavaScript.box.setAttribute('material', 'color: #00FF00'); —
передача строки, аналог CSS.Использование объектов предпочтительно при необходимости обновления нескольких свойств одновременно, а строки удобны для единичных изменений.
Для создания и удаления объектов вне цикла рендера применяются стандартные методы DOM:
appendChild(entity) — добавление объекта в сцену.removeChild(entity) — удаление объекта.replaceChild(newEntity, oldEntity) — замена сущности на
другую.Пример динамического удаления:
const entity = document.querySelector('#oldBox');
if (entity) {
entity.parentNode.removeChild(entity);
}
Такая модификация не требует перезапуска сцены и отражается мгновенно.
A-Frame предоставляет богатый набор событий (click,
mouseenter, mouseleave, loaded,
componentchanged), которые можно использовать для
модификации сцены. События позволяют менять свойства объектов или
добавлять новые сущности в ответ на действия пользователя или внешние
триггеры:
const button = document.querySelector('#spawnButton');
button.addEventListener('click', () => {
const sphere = document.createElement('a-entity');
sphere.setAttribute('geometry', { primitive: 'sphere', radius: 1 });
sphere.setAttribute('material', { color: '#0000FF' });
document.querySelector('a-scene').appendChild(sphere);
});
В данном примере при нажатии создается синий шар, что демонстрирует реактивность сцены без участия основного рендера.
Компоненты A-Frame позволяют инкапсулировать логику модификации сцены. Создание собственного компонента обеспечивает переиспользуемость и чистоту кода. Пример компонента, который периодически изменяет цвет объекта:
AFRAME.registerComponent('color-changer', {
schema: { interval: { type: 'int', default: 1000 } },
init: function () {
this.changeColor = this.changeColor.bind(this);
this.intervalId = setInterval(this.changeColor, this.data.interval);
},
changeColor: function () {
const colors = ['#FF0000', '#00FF00', '#0000FF'];
const color = colors[Math.floor(Math.random() * colors.length)];
this.el.setAttribute('material', 'color', color);
},
remove: function () {
clearInterval(this.intervalId);
}
});
Применение к сущности:
<a-entity geometry="primitive: box" material="color: #FFF" color-changer="interval: 500"></a-entity>
Этот компонент обновляет цвет объекта каждые 500 мс, полностью управляя состоянием вне основного цикла рендера.
Хотя A-Frame предоставляет <a-animation> и систему
animation-mixer, простые динамические изменения можно
выполнять напрямую через JavaScript. Пример плавного перемещения
объекта:
const box = document.querySelector('#myBox');
let position = { x: 0, y: 1, z: -5 };
function moveBox() {
position.x += 0.01;
box.setAttribute('position', position);
requestAnimationFrame(moveBox);
}
moveBox();
Использование requestAnimationFrame обеспечивает
синхронизацию с рендером браузера, но логика обновления все равно
находится вне стандартного рендер-цикла A-Frame.
При динамическом создании большого числа сущностей важно учитывать производительность:
visible для временного скрытия.<a-entity>
контейнеров для уменьшения числа DOM-операций.A-Frame использует систему systems для управления общими
ресурсами сцены. Динамическая модификация может взаимодействовать с
системами, например, управляя физикой через
aframe-physics-system:
const entity = document.createElement('a-entity');
entity.setAttribute('geometry', { primitive: 'sphere', radius: 0.5 });
entity.setAttribute('material', { color: '#FFFF00' });
entity.setAttribute('dynamic-body', {}); // компонент физики
document.querySelector('a-scene').appendChild(entity);
Это позволяет объекту сразу участвовать в симуляции физики после добавления, без повторной инициализации сцены.
A-Frame позволяет использовать как querySelector, так и
querySelectorAll для поиска объектов и массовой
модификации:
document.querySelectorAll('.interactive').forEach(el => {
el.setAttribute('material', 'opacity', 0.5);
});
Присваивание классов и идентификаторов делает динамическое управление более структурированным, особенно в больших сценах с сотнями объектов.
Для упрощения создания объектов можно хранить заранее определенные шаблоны в HTML или JSON и клонировать их:
const template = document.querySelector('#enemyTemplate');
const clone = template.content.firstElementChild.cloneNode(true);
document.querySelector('a-scene').appendChild(clone);
Использование шаблонов ускоряет добавление сложных объектов и поддерживает единообразие компонентов.