What's wrong with my camera collision in A-Frame - aframe

I'm copying straight from the A-Frame documentation on RayCaster but I'm still not getting it right. I want the collider to occur when the camera connects with the cube.
Here's the github link for context.
<a-entity geometry="primitive: box" class="collidable"
position="1 2.5 0"></a-entity>
AFRAME.registerComponent('collider-check', {
dependencies: ['raycaster'],
init: function () {
this.el.addEventListener('raycaster-intersected', function () {
console.log('Player hit something!');
});
}
});

raycaster-intersected event is a ray from camera to cursor position, if the ray hit something, it will trigger raycaster-intersected event. collider event is more like checking distance between camera and something collidable, you can look at this component sphere-collider.js then, register your own collider-check component.

Related

A-frame click event doesn't work for object intersecting cursor when entering VR

I have created an A-frame scene, and I am using a large invisible sphere to catch any mouse click to change an image. This works perfectly before entering VR mode, however, on entering VR mode, the click events are not caught until you look away from the object and look back.
From reading the documentation my guess is that this isn't counting the cursor as intersecting the object if it starts the scene in that position?
<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
<script>
AFRAME.registerComponent('clickhandler', {
init: function () {
this.el.addEventListener('mousedown', function (evt) {
document.querySelector("#sky").setAttribute("src", "photo1.jpg");
});
}
});
</script>
<a-scene embedded background="color: black">
<a-entity camera look-controls position="0 0 0">
<a-cursor visible="false"></a-cursor>
</a-entity>
<a-sky id="sky" src="photo-initial.jpg"></a-sky>
<a-entity id="circle" cursor-listener geometry="primitive: circle; radius: 25" visible="false" material="color: blue" clickhandler position="-2.5 0.25 -1.5" rotation="0 15 0"></a-entity>
</a-scene>
So when this scene starts, the image is in front of the view, a large invisible sphere fills the whole view - from the browser, I can immediately click to trigger the click event. But if I reload the page and go straight into VR and click, nothing happens until I click to look 180 degrees away, and then look back. Then if I click, the event triggers.

How can I auto walk in A-Frame?

For my A-Frame project I want the player to move forward without depending on any controllers or keyboards. The player should always be moving forward, and should be able to decide the direction by looking around (without changing the z value). Using look-controls on the camera and movement-controls (from aframe-extras) on the rig gives this behavior, apart from the fact that it still depends on a controller. How can I implement auto walk in A-Frame?
<a-entity id="rig" movement-controls>
<a-entity id="camera" position="0 1.7 0" camera look-controls>
</a-entity>
If you are using the movement-control component, you can add your own "controls". As the doc say, all you have to do is to name it with a "-controls" suffix (see https://github.com/n5ro/aframe-extras/tree/master/src/controls#customizing-movement-controls ). This is the code for a simple "autowalk" custom controls component for "movement-controls":
AFRAME.registerComponent('autowalk-controls', {
isVelocityActive: function () {
return true;
},
getVelocityDelta: function () {
return new THREE.Vector3(0, 0, -1);
}
});
And you can simply use it by adding it to the controls proprety of "movement-controls" like that:
movement-controls="controls: autowalk"

A-Frame: parent's raycaster-intersected-cleared triggered if no intersection with children

I'm implementing a feature to get coordinate of an a-sky while moving the VR controller.
<a-scene scenelistener>
<a-sky
id="map-sky"
color="#222"
radius="700"
rotation="0 45 0"
rotation-control
raycaster-listen
class="ray-castable"
>
<a-entity
id="country-tiles"
country-tiles
scale="1 1 1"
rotation="0 90 0"
></a-entity>
</a-sky>
... // Oculus entities
</a-scene>
a-sky and its children is listening for raycasting, and print out the console logging
AFRAME.registerComponent("raycaster-listen", {
init: function() {
this.el.addEventListener("raycaster-intersected", evt => {
console.log(`raycaster ${this.el.id} intersected!!!`);
});
this.el.addEventListener("raycaster-intersected-cleared", evt => {
console.log(`raycaster ${this.el.id} cleared!!!`);
});
}
});
RESULT: while moving in and out the children country-tiles, raycaster-intersected-cleared event is triggered from the children and also its parent map-sky, mean A-Frame cannot get the intersections between a-sky and the raycasting VR controller.
raycaster intersected!!!
raycaster map-sky intersected!!!
// Moving out the tile
raycaster cleared!!!
raycaster map-sky cleared!!!
You can check on this Glitch
NOTE: since I am developing for VR controller, therefore please use the WebXR emulator extension for interaction
It turns out that raycaster-intersected-cleared event from parent element is fired but it does not mean that it is not intersected anymore. To confirm if it has been still intersected I have to check if getIntersection result is NULL.
AFRAME.registerComponent("raycaster-listen", {
init: function() {
this.el.addEventListener("raycaster-intersected", evt => {
console.log(`raycaster ${this.el.id} intersected!!!`);
this.raycaster = evt.detail.el;
});
this.el.addEventListener("raycaster-intersected-cleared", evt => {
if (this.raycaster) {
const intersection = this.raycaster.components.raycaster.getIntersection(this.el);
if (!intersection) {
console.log(`raycaster ${this.el.id} cleared!!!`);
}
}
});
}
});

A-frame laser pointer wrong angle

I've just added the laser pointer to the right hand in my A-Frame scene and it's pointing in the wrong direction.
A-frame Laser pointing 45deg to the left
In this image I am pointing at the blue box above the tower using an Oculus Touch controller. As you can see the hand is pointing correctly and feels like it matches my real life hand position quite well but the laser is going about 45deg to the left.
Here is my code:
<a-entity id="cameraRig" position="-25 -10 138" rotation="0 -25 0">
<a-entity id="head" camera="near: 0.1; far: 10000" wasd-controls look-controls></a-entity>
<a-entity id="teleHand" hand-controls="left" teleport-controls="cameraRig: #cameraRig; teleportOrigin: #head; type: parabolic; button: trigger; collisionEntities: #terrain, #bridgeFull"></a-entity>
<a-entity id="pointerHand" hand-controls="right" laser-controls></a-entity>
Is there a way I can reposition the laser? Ideally to come out of the pointing fingure but if not then just pointing in the right direction will do?
Update: I just tried raycaster="showLine: true" instead and this does point in the correct direction so it appears to be a bug with the laser component. I could use the raycaster and write my own collision logic but would much prefer to use the mouse events that you get with the laser.
Second Update: Just discovered if I add both the raycaster and cursor component I get the exact same functionality as adding the laser component but with the raycast pointing in the correct direction.
This has solved the problem I have but will leave this here as I'm sure others will run into this problem until the laser component is fixed.
I've filed an issue here https://github.com/aframevr/aframe/issues/3396
For clarity I was using v0.7.1 of A-frame
Okay, so to post the answer here. hand-controls and laser-controls aren't meant to mix. Hand controls is more for 6DoF and laser-controls is more if you want to support both 3DoF and 6DoF. Laser-controls will set its own raycaster properties on controllerconnected event.
To set your own raycaster properties:
AFRAME.registerComponent('force-raycaster', {
schema: {
direction: {type: 'vec3'},
origin: {type: 'vec3'}
},
init: function () {
this.el.addEventListener('controllerconnected', {
// Wait for laser-controls to set its raycaster properties.
setTimeout(() {
this.el.setAttribute('raycaster', this.data);
}, 50);
});
}
});
<a-entity laser-controls hand-controls force-raycaster="direction: 0 0 -1; origin: 0 -0.1 0">

How can I make my entity spin when the user hovers over it?

I am using the event-set-component to cause my obj model under to increase scale when the cursor hovers over it.
This is working correctly.
But how would I make it spin as well as increase size?
I found the following code on AFrame docs but I do not know how to implement it so it triggers when the mouse is over the entity.
<a-animation attribute="material.opacity" begin="fade" to="0"></a-animation>
As you have asked for a different method in your comment I suggest to use a multi use component like the one I have written:
AFRAME.registerComponent('event-animate', {
schema: {
target: {type: 'selector'},
aevent: {default: 'animation1'},
triggeraction: {default: 'click'}
},
init: function () {
var data = this.data;
this.el.addEventListener(data.triggeraction, function () {
data.target.emit(data.aevent);
});
}
});
So in HTML it would look something like this:
<a-entity id="object1"
event-animate="target:object1;
triggeraction:mouseenter;
aevent:eventstart">
<a-animation attribute="scale"
dur="5000"
begin="eventstart"
from="1"
to ="5"
direction="alternate">
</a-animation>
<a-animation attribute="rotation"
dur="5000"
begin="eventstart"
from="0 0 0"
to="0 360 0"
direction="alternate">
</a-animation>
</a-entity>
The direction="alternate" should bring it back to its original position.
The quoted animation will work, if You set the begin event properly:
<a-animation attribute="rotation"
dur="2000"
begin="mouseenter"
to="0 360 0"
repeat="1"><a-animation>
On mouseenter, the animation triggers, and rotates the entity once.
To gain more control over what You do, You would need to get deep into making components.
1. The Easiest way i can think of, is using both the animation component, and Your own. You would need to set up a component listening for the mouseenter/mousexit, and trigger the animation:
AFRAME.registerComponent('mouseenterhandler', {
init: function () {
let el = this.el; //Your element reference
el.addEventListener('mouseenter, function () {
// get the rotation, by getAttribute, or by accessing the
//object3D.rotation
let rotation = el.getAttribute('rotation');
//lets rotate it to the same position
rotation.y += 360;
//set the animation component accordingly:
el.children[0].setAttribute('to',rotation);
//emit the 'begin' event:
el.emit('startrotating');
});
}
});
Quick Improvement if necessary: disable the listener, when the animation is triggered. Made with a boolean switched on the mouseenter event, and the animationend event.
2. You can choose not to use the animation component, and check on tick() if the cursor is over. If so, rotate the element by the actualRotation.y+0.1 ( or any other desired rotation ).
As noted before, You can access the rotation by getAttribute() or el.object3D.rotation.
As for the scale, You if You need to rotate + rescale the object on the mouseenter event, just add another animation, and use it like i did with the rotation.I'm not sure how it's usually done, in my experience animations are good, when there are not that many interactions, because they sometimes do unexpected things, which You have to predict/find out, and prevent.
On the other hand, making any animation manually ( changing properties on tick ) may seem laggy if the rotation delta is too big. You need to play with it, and find out which suits You best.

Resources