I want to use fernandojsg's teleport controls on my A-Frame project, but the way I want to use them is with shake.js, one shake to make the teleport line appear and another one to actually teleport where you selected.
I've seen the documentations and came across the startEvents and endEvent properties, and I want to map them into the shake event... for me it sounds like I have to create a custom component to do this, but I wanted to seek help first, to see if this is possible without doing it.
So far I've made this (glitch.com/ link) but it doesn't work so far (please note that I've got some other libraries there that make use of shake, mousedown, and similar events... my plan is to activate or deactivate them depending on how the user wants to move)
<a-entity id="player" wasd-controls tap-to-walk>
<a-camera id="eyes" position="-.5 1.5 0" camera="" look-controls="" mouse-cursor="">
<a-entity id="cursor" cursor="fuse: false;"
position="0 0 -1"
geometry="primitive: ring; radiusInner: 0.015; radiusOuter: 0.019"
material="color: white; shader: flat"
raycaster="far: 5; interval: 1000; objects: .clickable">
</a-entity>
<a-entity id="texto" text="value:Hola;align:center" position="0 -.3 -0.5"></a-entity>
<a-plane position="0 .7 -1" material="transparent: true; opacity: 0.5; color: #ffec04; shader:flat;" scale="1 0.2 1"></a-plane>
</a-camera>
<a-entity
teleport-controls="cameraRig: #player; teleport-origins: #eyes; startEvents:['shake','mousedown']"> </a-entity>
<a-entity id="step" sound="src: #step1"></a-entity>
</a-entity>
Thanks...
Yes you will need a some JS or a custom component to get shake.js and teleport controls to work together for two reasons:
shake.js emits its events outside the A-Frame scene on window where teleport-controls is not listening
shake.js only emits one event type, and you need to differentiate for startEvents and endEvents
But it doesn't need to be very complicated:
AFRAME.registerComponent('shake-listener', {
init: function () {
var targetEl = this.el
var count = 0
// you could also initialize the shake instance here
window.addEventListener('shake', function () {
if (++count % 2) {
targetEl.emit('shakestart')
} else {
targetEl.emit('shakeend')
}
})
}
})
Then add shake-listener to the same entity as teleport-controls="startEvents: shakestart; endEvents: shakeend"
Related
The A-Frame camera docs say to create a HUD like this:
<a-entity camera look-controls>
<a-entity geometry="primitive: plane; height: 0.2; width: 0.2" position="0 0 -1"
material="color: gray; opacity: 0.5"></a-entity>
</a-entity>
However, this causes the HUD element to be clipped by in-game objects. Normally HUDs are rendered on a separate layer above all the other game objects. Is there a simple way to fix this?
You have to:
Set renderer.sortObjects = true;
Set a the render order of the entity this.el.object3D.renderOrder = 100;
Disable the material depth test material.depthTest = false;
I created a simple overlay component that easily applies the above to any entity.
AFRAME.registerComponent("overlay", {
dependencies: ['material'],
init: function () {
this.el.sceneEl.renderer.sortObjects = true;
this.el.object3D.renderOrder = 100;
this.el.components.material.material.depthTest = false;
}
});
<a-entity camera look-controls wasd-controls position="0 1.6 0">
<a-plane id="hud" overlay rotation="0 0 0" position="0 0 -2" width="1" height="1" color="purple" shadow></a-plane>
</a-entity>
Example on glitch
I am using the a-frame components for a WebVR application. The camera has look-controls with a cursor to let the user pick an object. And when the event is fired I wish to change the camera position. This is what I have done. A camera is defined in the scene.
<a-entity id="cam" camera="userHeight: 1.6" look-controls>
<a-entity cursor="fuse: true; fuseTimeout: 500" position="0 0 -1" geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03" material="color: black; shader: flat">
</a-entity>
</a-entity>
I have a box with a listener as follows
<a-box box-listener color="tomato" position="1 0 3" depth="1" height="1" width="1"></a-box>
When the user moves the cursor to the box and holds for half a second, the event gets fired. The event script is as follows:
AFRAME.registerComponent('box-listener', {
init: function() {
this.el.addEventListener('click', function(evt) {
var cam = document.getElementById("cam");
var campos = cam.getAttribute("position");
campos.x = 1; // some random change.
var camrot = cam.getAttribute("rotation");
camrot.x = 0;
camrot.y = 0;
camrot.z = 0; // setting it back to looking straight ahead
var look = cam.getAttribute("look-controls");
look.enabled = false;
cam.setAttribute('look-controls',look);
cam.setAttribute("position", campos);
cam.setAttribute("rotation", camrot);
look.enabled = true;
cam.setAttribute('look-controls',look);
});
}
});
By putting logs I find that the values are getting updated in the camera element however nothing changes on the screen.
where am I going wrong? Does the camera element need to be refreshed?
Thanks,
Raj
I am trying to detect collision of two boxes in A-FRAME v. 0.5.0. I use raycaster example:
https://aframe.io/docs/0.5.0/components/raycaster.html#whitelisting-entities-to-test-for-intersection
but for me it only works with cursor intersecting one of the meshes.
As it is written, raycaster detects when line created from a starting point to a certain direction intersects desired mesh (here marked with a collidable class). It appears that start of this collision-detecting line is somehow set on the camera or on a cursor but not on one of the boxes. How to reassign this starting point?
Before initializing scene I added component:
AFRAME.registerComponent('collider-check', {
dependencies: ['raycaster'],
init: function () {
console.log("we have component");
this.el.addEventListener('raycaster-intersected', function () {
console.log('Player hit something!');
});
},
});
and then A-FRAME entities
<a-entity id="player" collider-check >
<a-entity id="rc"
raycaster="objects: .collidable"
geometry="primitive: box; width: 0.5; height: 4; depth: 0.5"
material="shader: flat; color:gray"
position="0 -0.9 0"
rotation="90 0 0" ></a-entity>
</a-entity>
<a-entity id="inmotion" class="collidable"
geometry="primitive: box; width: 0.5; height: 4; depth: 0.5"
position="1 0 0"
material="shader: flat; color: #00CCDD">
<a-animation id="canim"
attribute="position"
dur="2000"
from ="-2 -1 0"
to="2 0 0.5"
fill="forwards"
direction="alternate"
repeat="indefinite">
</a-animation>
</a-entity>
Here is jsfiddle with the example;
https://jsfiddle.net/Suiseki/9ggs6x4m/2/
Using the raycaster is one way to check for collisions in 3D space, but it's best if one of those shapes is a ray/line. If you have two 3D objects, it's easier to use bounding box or bounding sphere collisions, without a raycaster. Here are example implementations of each:
aabb-collider
sphere-collider
Both will file hit events on the elements when they collide. Example usage, for a slightly different case.
Does anyone know how to create a button in aframe
One way to create a button with A-Frame would be to use the <a-box> primitive combined with a cursor. The following is a simple demo:
<a-scene>
<a-entity position="0 .6 4">
<a-camera>
<a-entity id="mycursor" cursor="fuse: true; fuseTimeout: 500; max-distance: 30;"
position="0 0 -5"
geometry="primitive: ring"
material="color: blue; shader: flat">
</a-entity>
</a-camera>
</a-entity>
<!-- "button" -->
<a-entity id="refresh-button" geometry="primitive: box" material="color: red" position="0 0 -2"></a>
</a-scene>
<script>
document.querySelector('#refresh-button').addEventListener('click', function() {
// Refresh stuff would go here!
});
</script>
When the cursor focuses on the "button", the click event would fire. To add text to the button, you can use this component:
https://github.com/ngokevin/aframe-text-component
Lastly, if you're looking for a more traditional "button", you could simply float a <button> element over the canvas or Iframe if you're embedding.
i like https://www.npmjs.com/package/aframe-event-set-component for the hover event. And i give my cursor an attribute (data clickable) and then i say the raycaster he should just trigger entities with the attribute. If you want to let something just be clickable if you for example enter the vr-mode simply remove the dataclickable attribute. Scene looks like this:
<a-scene cursor="rayOrigin: mouse" raycaster="objects: [data-clickable]">
<a-image id="button" data-clickable visible="true" position="2 1.75 -0.2" height="0.5" width="0.5" rotation="0 90 0" onclick="dosomething()" event-set__enter="_event: mouseenter; width: 0.53; height: 0.53;"
event-set__leave="_event: mouseleave; width: 0.5; height: 0.5;"></a-image>
<a-camera>
<a-cursor id="curseid" raycaster="objects: [data-clickable]"</a-cursor>
</a-camera>
</a-scene>
If you want that a button works just if something happend give him the attribute later:
document.getElementById('button').setAttribute('data-clickable', '');
If you done with the button use:
document.getElementById('button').setAttribute('visible', 'false');
document.getElementById('button').removeAttribute('data-clickable');
If you want that the cursor just triggers button if you for example enter vr-mode, change the raycaster="objects: .notclickable" and then give him later with this line his attribute back:
document.getElementById('curseid').setAttribute('raycaster', 'objects: [data-clickable]');
This is for now my way to do buttons, maybe there is a smarter way. I hope this helped a bit :D
I have an app where the user has to answer a question by clicking the correct area on a collada model - there are 2 options and the user knows that an area is selectable when the cursor turns blue (mouse enters the cylinder, which has visible=false).
The mouse turns blue fine, however where the mouse leaves the cylinder, the cursor color should return to black, but instead it stays blue.
Thanks in advance for your help.
<a-cursor id="myCursor" color="black"></a-cursor>
<a-entity id='questionA' geometry="primitive: cylinder; height: .01; radius: 2.5" material="color:green; opacity: 1" correctAnswer > </a-entity>
var cursorVar = document.getElementById('myCursor');
var questionVar = document.getElementById('questionA');
questionVar.addEventListener('mouseenter', function() {
cursorVar.setAttribute('color', 'blue');
});
questionVar.addEventListener('mouseleave', function() {
cursorVar.setAttribute('color', 'black');
});
The cursor side also emits the event. Try listening to the event from the cursor as a workaround:
cursorEl.addEventListener('mouseleave');
0.3.0 which should be releasing tomorrow or in two days has improvements on the cursor, raycaster, and raycasting against COLLADA models. This includes the ability to limit what the raycaster tests against which would be ideal in the workaround above.
Could be several factors in your bug, I think once 0.3.0 is out, I'd be able to say with more clarity what's happening.
Does this CodePen perform as you expect?
I can't see the problem looking at your code (maybe it's something to do with the cursor primitive). Try replacing the cursor primitive with a manually defined one used in the CodePen link above:
<!-- Camera with gaze cursor -->
<a-entity position="0 1.8 5">
<a-entity camera look-controls wasd-controls>
<a-entity cursor
geometry="primitive: ring; radiusOuter: 0.025;
radiusInner: 0.015; segmentsTheta: 32"
material="color: #283644; shader: flat"
raycaster="far: 30"
position="0 0 -0.75"
id='cursor'>
</a-entity>
</a-entity>
</a-entity>
That said, the raycasting does seem a bit inaccurate (with 0.2.0 at least).