Consejos y Trucos de JavaScript
Overte's robust JavaScript API provides the tools for you to build great content and experiences in VR and on Desktop. We've compiled some advanced JavaScript tips you can use while scripting for Overte.
You can use the Scripting Console in Interface to try out the examples on this page. The output will be visible in the console itself.
Realizar Operaciones Matemáticas 3D
When you script for virtual worlds like Overte, you need 3D math operations to compute the position and orientation of 3D objects and avatars in-world. We cannot simply add two vectors. To script 3D math operations and to determine position and orientation information of avatars, you can use the following namespaces in our JavaScript API:
Vec3: The Vec3 API has facilities for generating and manipulating 3-dimensional vectors.
Quat: The Quat API provides facilities for generating and manipulating quaternions.
MyAvatar: The MyAvatar API provides facilities for manipulating your avatar.
Obtener la Posición de Tu Avatar
Cuando se crean objetos en el mundo, a menudo es muy útil saber dónde se encuentra tu avatar actualmente.
Overte uses a 3D Cartesian coordinate system where the position vector of an entity or avatar looks like this:
{ x: 0, y: 0, z: 0 }
To get your avatar's current position, use the MyAvatar namespace. MyAvatar contains properties with information related to your avatar. Use the position property, MyAvatar.position, which returns an object.
In the following example, we are using the JSON.stringify method to convert the JavaScript object (returned by MyAvatar.position) to a data string that can be sent over the server.
Open your Scripting Console and find your avatar's position
JSON.stringify(MyAvatar.position);
// {"x":-10.349810600280762,"y":-9.55379867553711,"z":11.861204147338867}
Obtener la Orientación de Tu Avatar
Si deseas que un objeto aparezca frente a ti, necesitas saber cómo está orientado tu avatar en el mundo.
Rotations are handled by a number-system called Quaternions. Quaternions help simplify calculations in three dimensional space. They add an extra dimension of 'w' and the values are normalized (-1,1).
Quaternions are represented in the form:
{ x: 0, y: 0, z: 0, w: 1 }
Get your avatar's orientation in the Scripting Console by using the MyAvatar.orientation property:
JSON.stringify(MyAvatar.orientation);
// {"x":0,"y":-0.4974651634693146,"z":0,"w":0.8674839735031128}
Obtener la Dirección en la que Mira Tu Avatar
You can use the Quat namespace to get the direction which your avatar is facing. Pass your avatar's orientation to Quat.getForward to get a vector describing which direction you are facing on the world axis.
{ x: 0, y: 0, z: 1 } // Backward
{ x: 0, y: 0, z: -1 } // Forward
{ x: -1, y: 0, z: 0 } // Left
{ x: 1, y: 0, z: 0 } // Right
Hacer que una Entidad Aparezca Frente a Tu Avatar
Puedes hacer que una entidad aparezca frente a tu avatar y también controlar la distancia a la que aparece.
Use the Vec3 namespace and the direction your avatar is facing to return the position at which you can make your entity appear. This position is 1m away from your avatar:
Vec3.sum(MyAvatar.position, Quat.getForward(MyAvatar.orientation)); // This will add your position vector to the direction vector returned from Quat.getForward. This will represent a position that is 1 meter in front of your avatar.
You can also control the distance at which an entity appears rather than using the default distance of 1m. First, multiply the vector representing the direction your avatar is facing and the distance:
Vec3.multiply(Quat.getForward(MyAvatar.orientation), 2.0); // if we are facing forward, that means our vector { x: 0, y: 0, z: -1 }, get's multiplied by 2.0 giving us a vector of { x: 0, y: 0, z: -2 }
Use Vec3.sum to return a new vector representing how far away an entity will appear from your avatar:
Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getForward(MyAvatar.orientation), 2.0)); // this will give us a final vector representing where in the world a point 2 meters directly in front of our avatar is
Hemos incluido las operaciones anteriores en una función a continuación para que puedas guardarla y ejecutarla como un script.
"use strict"
const myPosition = MyAvatar.position;
const myOrientation = MyAvatar.orientation;
const myDirection = Quat.getForward(myOrientation);
const distanceInFrontOfMe = 2.0;
const distanceVectorOfObjectInFrontOfMe= Vec3.multiply(myDirection, distanceInFrontOfMe);
const positionOfObjectInFrontOfMe = Vec3.sum(myPosition, distanceVectorOfObjectInFrontOfMe);
// we can even wrap this all up in a function to help simplify this any time we want the position of an object to appear in front of us
function getPositionInFrontOfMe(distanceInFrontOfMe){
const myPosition = MyAvatar.position;
const myOrientation = MyAvatar.orientation;
const myDirection = Quat.getForward(myOrientation);
const distanceVectorOfObjectInFrontOfMe= Vec3.multiply(myDirection, distanceInFrontOfMe);
const positionOfObjectInFrontOfMe = Vec3.sum(myPosition, distanceVectorOfObjectInFrontOfMe);
return positionOfObjectInFrontOfMe;
}
getPositionInFrontOfMe(4.0); // { x: 0, y: 0, z: -4 }
getPositionInFrontOfMe(8.0); // { x: 0, y: 0, z: -8 }
Incluir Archivos JS y JSON Externos
When writing a script in Overte, you might need to access the methods or objects in an external JS file or get information from a JSON file. For example, if you're writing a script to make your avatar wave, you might need to use some methods that already exist in an external JS file. You can do this using the require method in the Scripts namespace of our API.
Cualquier script que intentes recuperar usando este método debe exportar una función u objeto. Probémoslo usando un ejemplo.
Crea un script JS al que desees acceder desde tu script principal.
module.exports = {
sayHello: function () {
print("Hello!");
},
sayGoodbye: function () {
print("Goodbye!");
}
};
In example.js, you are exporting two functions that print either Hello or Goodbye, depending on which function you call, to the console. Now, let's use require in your main script.
Create a JS script called main.js:
const greet = Script.require(Script.resolvePath("example.js"));
greet.sayHello(); // prints Hello to the console
When you use the require method, you are making any function or object exported from example.js available to main.js. This means that main.js now has access to functions that will print either Hello or Goodbye to the console. In the above example, we are printing Hello to the console when we run main.js.
Nota
We recommend using relative paths in your development so that you can easily move content without having to update absolute paths.
Equipar un elemento
Puedes equipar un elemento al tomar y sostener una entidad sin presionar continuamente el botón de agarre o el gatillo. Por ejemplo, podrías equipar un pincel en la mano de tu avatar y soltarlo solo cuando termines de pintar.
Puedes equipar un elemento usando un script:
Messages.sendLocalMessage('Hifi-Hand-Grab', JSON.stringify({hand: 'XXX', entityID: 'YYY'})); // where XXX is either the 'left' or 'right' hand and YYY is entityID to equip
Para soltar la entidad de la mano de tu avatar:
Messages.sendLocalMessage('Hifi-Hand-Drop', 'XXX'); // where XXX is either the 'left' or 'right' hand
Nota
In order for an entity to be equipped it must be equippable . A user must be able to grab an entity before they can equip it, however a script does not need the entity to be grabbable before it can equip it with the 'Hifi-Hand-Grab' message.
Below is an example of a complete Interface script which will first create an equippable entity, and then equip it
"use strict"
// Create the entity, note that it is marked as equippable
const entityID = Entities.addEntity({
type: "Box",
position: Vec3.sum(MyAvatar.position, Quat.getFront(MyAvatar.orientation)),
grab: {
equippable: true,
},
});
// Equip the entity to your avatar's "left" hand
Messages.sendLocalMessage('Hifi-Hand-Grab', JSON.stringify({hand: 'left', entityID: entityID}));
Nota
A user can unequip all of their equiped items by pressing u on their keyboard.
Conectar una señal a una función
Las señales se pueden conectar a funciones. Esto significa que cada vez que se activa una señal, se ejecuta una función. Por ejemplo, si tu avatar cambia al activar o desactivar las colisiones, puedes conectar una función para que reaccione a este evento específico, como:
function collisionChanged(enabled) {
if(enabled) {
console.log("avatar collision is enabled");
} else {
console.log("avatar collision is disabled")
}
}
MyAvatar.collisionsEnabledChanged.connect(collisionChanged);
Each signal usually gets passed in arguments, and you can refer to the API documentation to see what a signal will provide you, such as the enabled property passed into collision changed.
It's good practice to disconnect from signals, but you can only do that if you name your function:
MyAvatar.collsionEnabledChanged.disconnect(collsionChanged);
Ver también