(A-Frame) How to stop a object intersect with cursor? - aframe

I use a-frame to do web-vr. I's good to use but I have some situation don't know how to implement.
First I put a Camera with cursor and set the raycaster intersect with object ".trigger".
<a-entity camera="" look-controls="" position="" rotation="" scale="" visible="">
<a-entity cursor="fuse: true; fuseTimeout: 1500" position="0 0 -1" geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03" material="color: cyan; shader: flat" raycaster="objects: .trigger" rotation="" scale="" visible="">
<a-animation begin="click" easing="ease-in" attribute="scale" fill="forwards" from="0.1 0.1 0.1" to="1 1 1" dur="150"></a-animation>
<a-animation begin="cursor-fusing" easing="ease-in" attribute="scale" fill="backwards" from="1 1 1" to="0.1 0.1 0.1" dur="1500"></a-animation>
</a-entity>
</a-entity>
And create a entity with class "trigger".
<a-entity class="tigger" id="clip01" clip01="on: click; conditionId: ShowClipTrigger" data-is-trigger="true" geometry="primitive: plane; width: 2; height: 3" material=" src: #clip01-pic; opacity: 0.99;" position="-5.913 -3.544 4.675" rotation="-82.048 122.222 11.345" scale="" visible="" animation__move="" animation__rotate=""></a-entity>
The ".trigger" object will trigger some action after on click event received. My question is how to disable the intersect after the trigger been click. I try remove the class "trigger" from the object after the click evnet, but it still can intersect with cursor.
I search the a-frame document raycaster but no clue.

After removing the whitelisted class, You need to refresh the raycaster:
var raycasterEl = AFRAME.scenes[0].querySelector('[raycaster]');
raycasterEl.components.raycaster.refreshObjects();
Also You can achieve this by making a simple switch in the event listener:
var switch=true;
el.addEventListener("click", function(evt) {
if(switch){
//doStuff
switch = false;
}
});
or remove the listener completely, like i did here:
//listener
this.doStuff = this.doStuff.bind(this);
el.addEventListener("click", this.doStuff());
//function
doStuff: function(){
this.el.removeEventListener("click",this.doStuff);
}

Related

How to trigger cursor fuse on specific entities only

I have my camera and cursor set up this way:
<a-camera>
<a-cursor
fuse="true"
animation__fusing="property: scale; startEvents: fusing; easing: easeInCubic; dur: 1500; from: 1 1 1; to: 0.1 0.1 0.1"
animation__mouseleave="property: scale; startEvents: mouseleave; easing: easeInCubic; dur: 500; to: 1 1 1">
</a-cursor>
</a-camera>
And a scene looking like this:
<a-entity id="scene1">
<a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9" onclick="changeLevel('scene1', 'scene2')"></a-box>
<a-sky src="background1.png"></a-sky>
</a-entity>
Now the cursor is always fusing, even when looking at the skybox. Is it possible to start the fusing animation only when looking at clickable entities?
Thanks
You can configure the cursor through the raycaster component. In your case:
<a-cursor fuse="true" raycaster="objects: a-box" ....
You can set a class for your interactive objects, to make it clear:
<a-box class="clickable"></a-box>
...
<a-cursor raycaster="objects: .clickable" ...
Check it out here.

Aframe - How to render HUD on top of everything else

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

In aframe, how do you make the property visible="false" ignore the raycaster?

I have some objects in aframe with visible="false" meaning they aren't visible but they are still interactable even though you can't see them. Is there a solution to this?
Found a few similar cases online but no clear solution.
https://github.com/aframevr/aframe/issues/3551
https://github.com/aframevr/aframe/issues/979
<!-- CURSOR ENTITY -->
<a-entity rotation="0 0 0" position="0 0 2">
<a-entity id="camera" far: 20; camera look-controls rotation="0 0 0" wasd-controls>
<!-- MAIN CURSOR -->
<a-entity raycaster="interval: 200; objects: .clickable" cursor="fuse: true; maxDistance: 500; timeout: 1500;" id="cursor-main" position="0 0 -1.5" geometry="primitive: ring; radiusOuter: 0.04; radiusInner: 0.03; thetaLength: 360; thetaStart: 90;" material="color: #439DC2;">
<a-animation begin="cursor-fusing" attribute="geometry.thetaLength" fill="forwards" from="360" to="0" easing="ease-in"></a-animation>
<a-animation begin="mouseleave" attribute="geometry.thetaLength" fill="backwards" from="0" to="360" dur="0"></a-animation>
</a-entity>
<a-entity id="cursor-loader" position="0 0 -1.51" geometry="primitive: ring; radiusOuter: 0.04; radiusInner: 0.03;" material="color: #2ADD2A;">
</a-entity>
</a-entity>
</a-entity>
<a-entity ui-modal="triggerElement:#selection;" visible="false">
<a-image position="-0.7 -1 1" class="clickable" src="#one" scale="0.7 0.7 0" link="href:location1.html; on: click; visualAspectEnabled: false" src-fit></a-image>
<a-image position="0 -1 1" class="clickable" src="#two" scale="0.7 0.64 0" link="href:location2.html; on: click; visualAspectEnabled: false" src-fit></a-image>
<a-image position="0.7 -1 1" class="clickable" src="#three" scale="0.7 0.7 0" link="href:location3.html; on: click; visualAspectEnabled: false" src-fit></a-image>
<a-image class="clickable" src="#close" id="closing" scale="0.3 0.3 0" position="-0.5 -0.35 1.1"></a-image>
</a-entity>
Ideally if an object is set to visible="false" the user shouldn't be able to interact with it.
As seen in the discussion, if you want to ignore certain objects, you should not rely on visibility. The proper way would be using the objects whitelist:
<a-scene cursor raycaster='objects: .clickable>
The whitelist uses typical CSS selectors, so in the above example the raycaster would only interact with elements which have a clickable class.
You can add / remove it with the visibility:
if (condition) {
el.setAttribute('visible', 'false')
el.classList.remove('clickable')
} else {
el.setAttribute('visible', 'true')
el.classList.add('clickable')
}
You can check it out in this fiddle. Click the sphere to make the box clickable / not clickable.
A hacky workaround could be also setting the scale to 0 0 0. The element won't be visible, and won't be clickable.

AFrame - Change controls type using setAttribute

I would like to remove the twoway-motion component from the entity player, and replace it with the progressive-controls component, using setAttribute.
While the removeAttribute works fine for removing the twoway-motion, the setAttribute does not add the progressive-controls.
<a-entity id="player" networked="template:#avatar-template;showLocalTemplate:false;"
camera spawn-in-circle="radius:3;"
position="0 1.3 0"
wasd-controls
look-controls
twoway-motion="speed: 35">
<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"
id="defaultCursor">
</a-entity>
</a-entity>
<script>
var playerEl = document.getElementById('player');
var cursorEl = document.getElementById('defaultCursor');
playerEl.removeChild(cursorEl);
playerEl.removeAttribute('twoway-motion');
playerEl.setAttribute('progressive-controls');
</script>
the setAttribute(name, value) requires a value.
To add the component, just use setAttribute('progressive-controls', '') to add it with the default schema

A-frame position animation passing in data as second argument

I am trying to get an animation to move the camera from the current position, to a position passed from the element clicked. The issue seems to be in proper syntax for passing the 'to' position into an animation. Here is what I have.
<a-entity id="cam-position" position="0 0 1.2" rotation="-0 0 0">
<a-camera look-controls wasd-controls>
<a-entity visible="true" cursor="fuse: true; fuse-timeout: 500"
position="0 0 -1"
scale="0.01 0.01 0.01"
geometry="primitive: sphere"
material="color: #6AD7FF; shader: standard">
<a-animation begin="click"
easing="ease-in"
attribute="scale"
dur="2000"
fill="backwards"
from="0.01 0.01 0.01" to="0.04 0.04 0.04">
</a-animation>
<a-animation begin="fusing"
easing="ease-in"
attribute="scale"
fill="forwards"
from="1 1 1" to="0.1 0.1 0.1" >
</a-animation>
</a-entity>
</a-camera>
<a-animation begin="move"
attribute="position"
dur="2000"
from="0 0 1.2"
>
</a-animation>
</a-entity>
document.querySelector('#cam-position').emit('move',{'to': { x: 0, y: 0, z: -88 } });
It works fine without the second argument and the 'to' specified in the a-animation. Any ideas? Thanks
When you are emitting move, the second argument is the event detail. Animations do have a feature to start an animation on an event trigger, but it doesn't look at the event detail.
You'd need to do a animation.setAttribute('to', {...}) rather than trying to have an event handle everything since that's not a feature.
document.querySelector('a-animation[begin="move"]').setAttribute('to', '0 0 -88');
document.querySelector('#cam-position').emit('move')

Resources