Purpose
This file registers a state using the aframe-state-component to provide a mechanism to have global numeric variables on the scene.
Usage
Import the JavaScript files on the <head>
of the html with the following tags:
<script src="https://unpkg.com/aframe-state-component@7.1.0/dist/aframe-state-component.js"></script>
<script src="https://raw.githubusercontent.com/jdjuli/vr-programming/main/static/js/variables-system.js"></script>
To access the variables in your code, you’ll need a reference to the state system, which can be obtained inside your component by doing this:
let scene = this.el.sceneEl
//Or document.querySelector('a-scene') if your code isn't inside a component
let state = this.el.sceneEl.systems['state'];
Once you have a reference to the system, you can do the following
-
Declare a variable:
scene.emit('createVariable',{name:'nameOfTheVariable',value:123.45});
The value is optional and if not defined, it will be 0.0.
If there’s already a variable with the specified name, it won’t be overwritten and the console will display a warning like this:
Variable with name: 'nameOfTheVariable' already exists, use 'setVariable' event to change it's value
-
Read a variable’s value:
let value = scene.systems['state'].state.variables['nameOfTheVariable'];
It’s recommended to check first if the variable accessed exists, as if it doesn’t exist, an exception will be thrown.
-
Change a variable’s value:
scene.emit('setVariable',{name:'nameOfTheVariable',value:123.45});
If the variable doesn’t exists, it won’t be created and the console will display a warning message like this:
Variable with name: 'nameOfTheVariable' doesn't exist, use 'createVariable' event first to create it
-
Delete a variable:
scene.emit('deleteVariable',{name:'nameOfTheVariable'});
This operation doesn’t fail nor shows anything through the console, even if the variable didn’t exist previously.
-
Check if a variable exists:
let value = scene.systems['state'].state.variables.hasOwnProperty('nameOfTheVariable');
Don’t try to access the variable directly, as they are stored as object properties and accessing an undefined property will lead to an exception
Idea: how to create unique ID’s
To create unique ID’s you can use the following code snippets among others:
//Ideal if you need to generate ID's fast.
//Math.round() is used to get rid of the decimal separator
Math.round(Math.random()*Number.MAX_SAFE_INTEGER)).toString(36)
//Ideal to create ID's on user demand.
//uniqueness not guaranteed if called very frequently (don't use it on loops)
Date.now().toString(36)
Implementation
The initial state is defined as a single empty object called variables
that will be used as a dictionary.
The actions described on the previous section are implemented as state handlers (just those that doesn’t return anything), and the actions that need to return a value, should be performed by the programmer on their code.
Adding a variable is done by creating a new property on the variables
object
Examples
This example shows a text whose value can be modified by pressing the keys +
and -
on the keyboard (play with it here)
<html>
<head>
<script src="https://aframe.io/releases/1.2.0/aframe.js"></script>
<script src="https://unpkg.com/aframe-state-component@7.1.0/dist/aframe-state-component.js"></script>
<script src="https://raw.githubusercontent.com/jdjuli/vr-programming/main/static/js/variables-system.js"></script>
</head>
<body>
<a-scene>
<!-- With the component 'bind', we can map a property to a variable -->
<a-text position="0 1.6 -1" color="black" side="double" bind="value:variables.textValue"></a-text>
</a-scene>
<script>
let scene = document.querySelector('a-scene');
//Create the variable
scene.emit('createVariable',{name:'textValue'});
//Define a handler to change it's value
document.addEventListener('keypress',(evt)=>{
let currentValue = scene.systems['state'].state.variables['textValue'];
switch(evt.key){
case '+':
scene.emit('setVariable',{name:'textValue',value:currentValue+1.0});
break;
case '-':
scene.emit('setVariable',{name:'textValue',value:currentValue-1.0});
break;
}
});
</script>
</body>
</html>
Using this state doesn’t create or delete elements on the DOM, only changes their attributes