A-Frame中文教程

实体(Entity)

A-Frame使用<a-entity>元素来表示一个实体。如同在 实体-组件-系统模式中定义的,实体是占位符对象以便我们插入组件来提供其外观、行为和 功能。

在A-Frame中,位置(position)旋转(rotation)尺寸(scale)是实体的固有组件。

例子

考虑下面的实体。就其本身而言,它没有外表、行为或功能.它什么也不做:

<a-entity>

我们可以将给它附加组件,使它呈现某事或做某事。为了使它具有形状和外观,我们可以加上几何模型(geometry)材料(material)组件:

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

或者为了使它发光,我们可以进一步附加光照(light)组件:

<a-entity geometry="primitive: box" material="color: red"
light="type: point; intensity: 2.0">

获得一个实体

我们可以使用简单的DOM应用程序接口来得到一个实体。

<a-entity id="mario"></a-entity>
var el = document.querySelector('#mario');

一旦我们得到了一个实体,我们就可以访问它的属性和方法了。

属性(Properties)

components

<a-entity>.components是连接到实体的组件对象。这使得我们能够访问实体的组件,包括每个组件的数据,状态和方法。

例如,如果我们想获得一个实体的three.js相机或者材料对象,我们可以通过它的组件来实现:

var camera = document.querySelector('a-entity[camera]').components.camera.camera;
var material = document.querySelector('a-entity[material]').components.material.material;

或者,如果某个组件公开了一个API,我们可以调用它的方法:

document.querySelector('a-entity[sound]').components.sound.pause();

isPlaying

该属性表示这个实体是否处于活动状态中。如果我们暂停该实体,那么isPlaying 将变为 false

object3D

<a-entity>.object3D是对实体的three.js Object3D对象的引用。准确的说,object3D是一个THREE.Group对象,其中包含了各种THREE.Object3D对象,如相机(cameras), 网孔(meshes), 光照(lights)或者声音:

// Gaining access to the internal three.js scene graph.
var groupObject3D = document.querySelector('a-entity').object3D;
console.log(groupObject3D.parent);
console.log(groupObject3D.children);

We can access the different types of Object3Ds through object3DMap.

object3DMap

一个实体的object3DMap是一个对象,它允许访问组件所设置的不同类型的THREE.Object3D,如相机(cameras), 网孔(meshes), 光照(lights)或者声音。

对于一个附有geometrylight组件的实体,object3DMap可能看起来如下:

{
light: <THREE.Light Object>,
mesh: <THREE.Mesh Object>
}

我们可以使用getOrCreateObject3DsetObject3D,以及removeObject3D来管理实体的THREE.Object3D集合。

sceneEl

实体包含一个对其所在场景元素的引用。

var sceneEl = document.querySelector('a-scene');
var entity = sceneEl.querySelector('a-entity');
console.log(entity.sceneEl === sceneEl); // >> true.

方法(Methods)

addState (stateName)

addState给实体添加状态,该方法将发出stateadded事件,而且我们可以通过.is来检查状态是否存在:

entity.addEventListener('stateadded', function (evt) {
if (evt.detail.state === 'selected') {
console.log('Entity now selected!');
}
});
entity.addState('selected');
entity.is('selected'); // >> true

emit (name, detail, bubbles)

emit在实体上发出自定义DOM事件。例如,我们可以触发一个动画

// <a-entity>
// <a-animation attribute="rotation" begin="rotate" to="0 360 0"></a-animation>
// </a-entity>
entity.emit('rotate');

我们也可以使用第二个参数来传递事件细节或数据:

entity.emit('collide', { target: collidingEntity });

默认情况下该事件将冒泡(向父级对象上溯)。我们可以禁止事件冒泡:

entity.emit('sink', null, false);

flushToDOM (recursive)

flushToDOM将手动序列化实体组件的数据并更新DOM。阅读更多:component-to-DOM序列化

getAttribute (componentName)

getAttribute获取解析组件数据(包含mixins和defaults)。

// <a-entity geometry="primitive: box; width: 3">
entity.getAttribute('geometry');
// >> {primitive: "box", depth: 2, height: 2, translate: "0 0 0", width: 3, ...}
entity.getAttribute('geometry').primitive;
// >> "box"
entity.getAttribute('geometry').height;
// >> 2
entity.getAttribute('position');
// >> {x: 0, y: 0, z: 0}

如果componentName不是一个已注册组件的名称,getAttribute会按正常情况工作:

// <a-entity data-position="0 1 1">
entity.getAttribute('data-position');
// >> "0 1 1"

getDOMAttribute (componentName)

getDOMAttribute仅获取显式定义在DOM中或通过setAttribute方法设置的解析组件数据。如果componentName是一个已注册组件的名称,getDOMAttribute将以一个解析对象返回定义在HTML中的组件数据。对于组件,getDOMAttribute只是getAttribute的部分形式,因为返回的组件数据不包括被应用的混合(mixins)或默认值(defauls):

比较上述getAttribute示例的输出:

// <a-entity geometry="primitive: box; width: 3">
entity.getDOMAttribute('geometry');
// >> { primitive: "box", width: 3 }
entity.getDOMAttribute('geometry').primitive;
// >> "box"
entity.getDOMAttribute('geometry').height;
// >> undefined
entity.getDOMAttribute('position');
// >> undefined

getObject3D (type)

getObject3Dobject3DMap上按type引用来查找一个子THREE.Object3D

AFRAME.registerComponent('example-mesh', {
init: function () {
var el = this.el;
el.getOrCreateObject3D('mesh', THREE.Mesh);
el.getObject3D('mesh'); // Returns THREE.Mesh that was just created.
}
});

getOrCreateObject3D (type, Constructor)

当该实体在type下没有注册一个THREE.Object3D时,getOrCreateObject3D方法将使用传入的Constructor来注册一个实例化的THREE.Object3D。如果实体在type下已有一个注册的THREE.Object3DgetOrCreateObject3D方法效果和getObject3D一样:

AFRAME.registerComponent('example-geometry', {
update: function () {
var mesh = this.el.getOrCreateObject3D('mesh', THREE.Mesh);
mesh.geometry = new THREE.Geometry();
}
});

pause ()

pause()将停止任何动画和组件所定义的动态行为。当我们暂停某个实体时,它将停止其动画并在其每个组件上调用Component.pause()。组件决定执行暂停时要发生的事情,通常是删除事件侦听器。当我们暂停一个实体时,它将在其所有子实体上调用pause()

// <a-entity id="spinning-jumping-ball">
entity.pause();

For example, the look-controls component on pause will remove event handlers that listen for input.

play ()

play()将启动任何动画和组件所定义的动态行为。DOM附加实体时会自动调用它。当一个实体调用play(),该实体将在其所有子实体上调用play()

entity.pause();
entity.play();

例如,当sound组件调用play方法时,将播放声音。

setAttribute (attr, value, componentAttrValue)

如果attr不是一个注册组件的名称或者这个组件是一个单属性组件,setAttribute会按正常情况工作:

entity.setAttribute('visible', false);

但是,如果attr是一个注册组件的名称,它可能会对该值进行特殊解析处理。比如position组件是一个单属性组件,但是它的属性类型解析器允许它接受一个对象(object):

entity.setAttribute('position', { x: 1, y: 2, z: 3 });

设置多属性组件数据

若要设置或替换多属性组件的组件数据,我们可以通过attr参数来传递一个注册组件的名称,并通过value传递一个属性对象:

// All previous properties for the light component will be removed and overwritten.
entity.setAttribute('light', {
type: 'spot',
distance: 30,
intensity: 2.0
});

更新多属性组件数据

若要更新多属性组件的单个属性,可以通过attr传递已注册组件的名称,通过第2个参数传递一个属性名称,第3个参数传递要设置的属性值:

// 材料组件的所有之前的属性(除了颜色)都不会受到影响。
entity.setAttribute('material', 'color', 'crimson');

setObject3D (type, obj)

setObject3D将注册传递的obj对象,这是一个THREE.Object3D,作为该实体的object3DMap下面的一个type。A-Frame添加obj为实体根object3D对象的子对象。

AFRAME.registerComponent('example-orthogonal-camera', {
update: function () {
this.el.setObject3D('camera', new THREE.OrthogonalCamera());
}
});

removeAttribute (attr, propertyName)

如果attr是一个注册组件的名称,除了从DOM中删除属性之外,removeAttribute将从实体中去除该组件,并触发该组件的remove生命周期方法。

entity.removeAttribute('goemetry'); // Detach the geometry component.
entity.removeAttribute('sound'); // Detach the sound component.

如果给定propertyNameremoveAttribute将重置由propertyName所指定的属性值为默认值:

entity.setAttribute('material', 'color', 'blue'); // The color is blue.
entity.removeAttribute('material', 'color'); // Reset the color to the default value, white.

removeObject3D (type)

removeObject3D通过type从该实体的THREE.Group以及场景中删除该对象。这将更新该实体的object3DMap,设置type键值为null。这通常是从组件的删除处理程序中调用。

removeState (stateName)

removeState将从实体中去除一个状态。这将发出stateremoved事件,而且我们可以使用.is来检查该状态是否已被去除:

entity.addEventListener('stateremoved', function (evt) {
if (evt.detail.state === 'selected') {
console.log('Entity no longer selected.');
}
});
entity.addState('selected');
entity.is('selected'); // >> true
entity.removeState('selected');
entity.is('selected'); // >> false

事件(Events)

事件名称 描述
child-attached 一个子实体被附加到实体上。
child-detached 一个子实体被从实体中分离出去。
componentchanged 实体的一个组件被修改了。
componentinit 实体的一个组件被初始化了。
componentremoved 实体的一个组件被初删除了。
loaded 实体已经添加并初始化了它的组件。
object3dset THREE.Object3D被通过setObject3D(name)方法设置在实体上。事件细节将包含用来设置在object3DMap中的name
实体现在处于非活动状态(或暂停)。
play 实体现在处于活动状态(或播放)。
stateadded 实体收到一个新的状态。
stateremoved 实体不再具有某种状态。
schemachanged 组件的模式已更改。

事件细节

下面是每个事件所包含的细节:

事件名称 属性 描述
child-attached el 所附加子元素的引用。
componentchanged name 被修改数据的组件的名称。
id 被修改数据的组件的ID。
newData 组件被修改后的新数据。
oldData 组件被修改前的旧数据。
componentinitialized name 被初始化的组件的名称。
id 被修改数据的组件的ID。
data 组件数据
componentremoved name 被删除的组件的名称。
id 被删除的组件的ID。
stateadded state 被附加的状态(字符串)。
stateremoved state 被分离(去除)的状态(字符串)。
schemachanged component 被修改模式的组件的名称。

侦听组件变更

我们可以使用componentchanged事件来侦听实体的变更:

entity.addEventListener('componentchanged', function (evt) {
if (evt.detail.name === 'position') {
console.log('Entity has moved from', evt.detail.oldData, 'to', evt.detail.newData, '!');
}
});

倾听子元素的添加和去除

我们可以使用child-attachedchild-detached事件来侦听什么时候场景添加和去除了一个实体:

entity.addEventListener('child-attached', function (evt) {
if (evt.detail.el.tagName.toLowerCase() === 'a-box') {
console.log('a box element has been attached');
};
});