实体(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></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 Object3D
s through object3DMap
.
object3DMap
一个实体的object3DMap
是一个对象,它允许访问组件所设置的不同类型的THREE.Object3D
,如相机(cameras), 网孔(meshes), 光照(lights)或者声音。
对于一个附有geometry 和 light组件的实体,object3DMap
可能看起来如下:
{ light: <THREE.Light Object>, mesh: <THREE.Mesh Object>} |
我们可以使用getOrCreateObject3D
,setObject3D
,以及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;// >> 2entity.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):
比较上述getObject3D (type)
getObject3D
在object3DMap
上按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.Object3D
,getOrCreateObject3D
方法效果和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>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. |
如果给定propertyName
,removeAttribute
将重置由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'); // >> trueentity.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-attached
和child-detached
事件来侦听什么时候场景添加和去除了一个实体:
entity.addEventListener('child-attached', function (evt) { if (evt.detail.el.tagName.toLowerCase() === 'a-box') { console.log('a box element has been attached'); };}); |