在AFrame中处理GearVR控制器事件



所以,我应该从警告我刚接触AFrame开始(尽管不是编程,游戏编程或Javascript)。我目前正在尝试将一个简单的场景与基本的GearVR控制器交互放在一起。

当我说"基本交互"时,我的意思是我有一个当你遵循官方教程时得到的小入门场景,我只是想把它扩展出来,这样当你按下触发器时(特别是触发器,而不仅仅是任何按钮),小文本组件的文本值发生了变化。

长话短说 - 我的代码不起作用。尽管我在组件 init 函数中添加了事件侦听器(并且我已经确认正在调用 init),但侦听器回调似乎从未被调用过。如果我必须猜测,我会说我附加的"激光控制"实体没有发出"触发"事件,但我不确定如何确认这一点。 以下是相关内容:

AFRAME.registerComponent('gearvr-trigger', {
schema: {
textValue: {
default: "Hello WebVR!"
}
},
init: function() {
var message_box = document.querySelector('#message');
var el = this.el;
el.addEventListener('triggerdown', function(evt) {
message_box.setAttribute('value', this.data.textValue);
});
}
});
<a-text id='message' value="Hello, A-Frame!" color="#BBB"
position="-0.9 0.2 -3" scale="1.5 1.5 1.5">
</a-text>
<a-box gearvr-trigger='textValue: "New Text Value";' src='#boxTexture' position='0 2 -5' rotation='0 45 45' scale='2 2 2'>
<a-animation attribute='position' to='0 2.5 -5' direction='alternate' dur='2000' repeat='indefinite'></a-animation>
<a-animation attribute="scale" begin="mouseenter" dur="300" to="2.3 2.3 2.3"></a-animation>
<a-animation attribute="scale" begin="mouseleave" dur="300" to="2 2 2"></a-animation>
<a-animation attribute="rotation" begin="click" dur="2000" to="360 405 45"></a-animation>
</a-box>
<a-entity raycaster='far: 100; showLine: true;' line='color: red;' laser-controls></a-entity>

如果比我更有经验的人看到我做错了什么,那就太好了,但如果你能指出我一些响应GearVR控制器事件的体面代码示例,我也很高兴。

正如其他人所指出的,您没有在自定义组件中选取'triggerdown'事件的原因是这些事件是由控制器实体发出的(在本例中a-entity[laser-controls]),并且它们就像在标准 DOM 中一样冒泡(在这种情况下,它将紧挨着a-scene),因此a-box看不到它们。

当您将有关控制器按钮的信息以及控制器与场景中其他实体的关系(例如,用激光指向或碰撞)结合起来时,我喜欢将其称为手势。laser-controls组件提供基本的手势解释,但我为丰富的手势解释创建了super-hands包,包括您需要的:按钮识别。

<html>
<head>
<script src="https://aframe.io/releases/0.7.1/aframe.min.js"></script>
<script src="https://unpkg.com/super-hands/dist/super-hands.min.js"></script>
<script>
AFRAME.registerComponent('gearvr-trigger', {
schema: {
textValue: {
default: "Hello WebVR!"
}
},
init: function() {
var message_box = document.querySelector('#message');
var el = this.el;
var triggerResponse = function (evt) {
if (evt.detail.state === 'clicked') {
message_box.setAttribute('value', this.data.textValue);
}
}
el.addEventListener('stateadded', triggerResponse.bind(this));
}
});
</script>
</head>
<body>
<a-scene>
<a-assets>
<a-mixin id="point-laser" raycaster='far: 100; showLine: true;' line='color: red;'></a-mixin>
</a-assets>
<a-text id='message' value="Hello, A-Frame!" color="#BBB"
position="-0.9 0.2 -3" scale="1.5 1.5 1.5">
</a-text>
<a-box clickable="startButtons: triggerdown, mousedown; endButtons: triggerup, mouseup" gearvr-trigger='textValue: "New Text Value";' src='#boxTexture' position='0 2 -5' rotation='0 45 45' scale='2 2 2'>
<a-animation attribute='position' to='0 2.5 -5' direction='alternate' dur='2000' repeat='indefinite'></a-animation>
<a-animation attribute="scale" begin="hover-start" dur="300" to="2.3 2.3 2.3"></a-animation>
<a-animation attribute="scale" begin="hover-end" dur="300" to="2 2 2"></a-animation>
<a-animation attribute="rotation" begin="grab-end" dur="2000" to="360 405 45"></a-animation>
</a-box>
<a-entity progressive-controls="maxLevel: point; pointMixin: point-laser" ></a-entity>
</a-scene>
</body>
</html>

对于控制器,progressive-controls自动检测控制器并像laser-controls一样设置激光指示器,但使用super-hands手势解释(它还为桌面/纸板用户提供类似光标的输入)。

<a-entity progressive-controls="maxLevel: point; pointMixin: point-laser"></a-entity>

对于目标实体,clickable将其激活为手势接收组件,并定义它将接受哪些按钮事件(如果您不需要跨平台支持,可以删除鼠标事件)。动画触发器事件也已更新 aa 以与super-hands一起使用。

<a-box clickable="startButtons: triggerdown, mousedown; endButtons: triggerup, mouseup" gearvr-trigger='textValue: "New Text Value";' ...>
...
<a-animation attribute="scale" begin="hover-start" dur="300" to="2.3 2.3 2.3"></a-animation>
<a-animation attribute="scale" begin="hover-end" dur="300" to="2 2 2"></a-animation>
<a-animation attribute="rotation" begin="grab-end" dur="2000" to="360 405 45"></a-animation>

对于您的自定义反应组件,我将其更改为对状态更改做出反应,这就是clickable通信方式,该响应已收到可接受的手势。我还解决了一个范围界定问题,一旦事件触发了这个问题,您就会发现这个问题。

var triggerResponse = function (evt) {
if (evt.detail.state === 'clicked') {
message_box.setAttribute('value', this.data.textValue);
}
}
el.addEventListener('stateadded', triggerResponse.bind(this));

试试 setAttribute('text', 'value, 'whatyou wanted') ?

如果它不是触发器代码,则可能是范围问题: "this"指的是处理程序中的元素,而不是组件,因此this.data在事件期间是未定义的

。一个可能的修复:

AFRAME.registerComponent('gearvr-trigger', {
schema: {
textValue: {
default: "Hello WebVR!"
}
},
init: function() {
var message_box = document.querySelector('#message');
var el = this.el;
var self = this;
el.addEventListener('triggerdown', function(evt) {
message_box.setAttribute('value', self.data.textValue);
});
}
});

或使用箭头函数

AFRAME.registerComponent('gearvr-trigger', {
schema: {
textValue: {
default: "Hello WebVR!"
}
},
init: function() {
var message_box = document.querySelector('#message');
var el = this.el;
el.addEventListener('triggerdown', (evt) => {
message_box.setAttribute('value', this.data.textValue);
});
}
});

triggerdown事件在具有激光控制属性的实体上触发。

我的代码使用click事件并响应任一按钮按下(与您想要的不同),但实现此模式可能会推动您前进。(它也更多地是跨设备操作的路径。click事件可能包含按下了哪个按钮。

在场景中,我有:

<a-entity laser-controls="hand: right"></a-entity>

在脚本中,我注册

AFRAME.registerComponent('cursor-listener', {
init: function () {
var lastIndex = -1;
var COLORS = ['purple', 'orange', 'white'];
this.el.addEventListener('click', function (evt) {
lastIndex = (lastIndex + 1) % COLORS.length;
this.setAttribute('material', 'color', COLORS[lastIndex]);
console.log('I was clicked at: ', evt.detail.intersection.point);
});
}
});

然后我在目标框上设置cursor-listener属性:

boxEl.setAttribute('cursor-listener', true);

最新更新