JavaScriptのヒントとコツ

Vircadiaの堅牢なJavaScriptAPIは、VRで優れたコンテンツとユーザーエクスペリエンスを構築するためのツールを提供します。Vircadiaのスクリプト作成中に使用できる高度なJavaScriptのヒントをいくつかまとめました。

インターフェイスのスクリプトコンソールを使用して、このページの例を試すことができます。出力はコンソール上に表示されます。

コンテンツ

3次元数学演算の計算

VircadiaのようなVRワールドでスクリプトを書く場合、インワールドの3Dオブジェクトやアバターの位置や向きを計算するために、3Dの数学演算が必要になります。単純に2つのベクトルを足すだけでは不十分です。3D数学演算のスクリプトや、アバターの位置や向きの情報を求めるには、JavaScript API の以下の名前空間を利用できます。

  • Vec3:Vec3 APIには、3次元ベクトルを生成および操作するための機能があります。

  • Quat: Quat APIは、四元数を生成・操作するための機能を提供します。

  • MyAvatar: MyAvatar APIは、アバターを操作するための機能を提供します。

アバターの位置を取得する

Vircadia世界でオブジェクトを作成するとき、アバターが現在どこにあるかを知ることはしばしば非常に役に立ちます。

Vircadiaは3次元直交座標系を使用しており、エンティティやアバターの位置ベクトルはこのようになります。

{ x: 0, y: 0, z: 0 }

アバターの現在の位置を取得するには、名前空間を使用MyAvatarします。MyAvatarには、アバターに関連する情報を含むプロパティが含まれています。オブジェクトを返すpositionプロパティMyAvatar.positionを使用します。

次の例では、JSON.stringifyメソッドを使用して、JavaScriptオブジェクト( MyAvatar.positionによって返される)をサーバー経由で送信できるデータ文字列に変換しています。

スクリプトコンソールを開き、アバターの位置を見つけます。

JSON.stringify(MyAvatar.position);
// {"x":-10.349810600280762,"y":-9.55379867553711,"z":11.861204147338867}

アバターの向きを取得する

物体を目の前に表示させるには、自分のアバターが現在どのような向きでインワールドにいるか知る必要があります。

回転は、クォータニオンと呼ばれる数体系で処理されます。四元数とは、3次元空間での計算を簡単にするためのものです。四元数では、[w]という次元が追加され、値は(-1,1)に正規化されます。

クォータニオンは次の形式で表されます。

{ x: 0, y: 0, z: 0, w: 1 }

MyAvatar.orientationプロパティを使用して、スクリプトコンソールでアバターの向きを取得します。

JSON.stringify(MyAvatar.orientation);
// {"x":0,"y":-0.4974651634693146,"z":0,"w":0.8674839735031128}

アバターが向いている方向を取得する

Quat 名前空間を使って、アバターが向いている方向を取得することができます。アバターの向きを Quat.getForward に渡すと、世界軸のどの方向に向いているかを表すベクトルを得ることができます。

{ 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

アバターの前にエンティティを表示させる

エンティティをアバターの前に表示させたり、表示される距離を制御したりできます。

Vec3名前空間とアバターが向いている方向を使用して、エンティティを表示できる位置を返します。この位置はアバターから1m離れています。

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.

また、エンティティを表示する際の距離をデフォルトの1mではなく、コントロールすることができます。まず、アバターが向いている方向と距離を表すベクトルを掛け合わせます。

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 }

Vec3.sumを使用して、エンティティがアバターからどれだけ離れているかを表す新しいベクトルを返します。

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

上記の操作を以下の関数にまとめましたので、スクリプトとして保存し、実行してください。

var myPosition = MyAvatar.position;   
var myOrientation = MyAvatar.orientation;
var myDirection = Quat.getForward(myOrientation);
var distanceInFrontOfMe = 2.0;
var distanceVectorOfObjectInFrontOfMe= Vec3.multiply(myDirection, distanceInFrontOfMe);
var 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){
  var myPosition = MyAvatar.position;
  var myOrientation = MyAvatar.orientation;
  var myDirection = Quat.getForward(myOrientation);
  var distanceVectorOfObjectInFrontOfMe= Vec3.multiply(myDirection, distanceInFrontOfMe);
  var 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 }

外部JSおよびJSONファイルを含める

Vircadiaでスクリプトを書くとき、外部のJSファイルにあるメソッドやオブジェクトにアクセスしたり、JSONファイルから情報を取得する必要がある場合があります。例えば、アバターを振るスクリプトを書く場合、外部のJSファイルにすでに存在するいくつかのメソッドを使用する必要があるかもしれません。このような場合は、API の Scripts ネームスペースにある require メソッドを使用します。

このメソッドを使って取得しようとするスクリプトは、関数かオブジェクトのどちらかをエクスポートする必要があります。例として、これを試してみましょう。

メインスクリプトからアクセスするJSスクリプトを作成します。

example.js

module.exports = {
    sayHello: function () {
        console.log("Hello!");
    },
    sayGoodbye: function () {
        console.log("Goodbye!");
    }
};

** example.js **では、呼び出す関数に応じて、HelloまたはGoodbyeのいずれかを出力する2つの関数をコンソールにエクスポートしています。それでは、メインスクリプトでrequireを使用しましょう。

main.jsというJSスクリプトを作成します。

var greet = Script.require(Script.resolvePath("example.js"));
greet.sayHello(); // prints Hello to the console

requireメソッドを使用すると、example.jsからエクスポートされた関数またはオブジェクトをmain.jsで使用できるようになります。これは、** main.js が、HelloまたはGoodbyeをコンソールに出力する関数にアクセスできるようになったことを意味します。上記の例では、 main.js **を実行すると、コンソールにHelloが出力されます。

Note

We recommend using relative paths in your development so that you can easily move content without having to update absolute paths.

アイテムの装備

グラブボタンやトリガーを連続して押さなくても、エンティティをつかんで保持することでアイテムを装備できます。たとえば、アバターの手にペイントブラシを装備し、ペイントが完了したときにのみドロップすることができます。

スクリプトを使用してアイテムを装備できます。

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

アバターの手からエンティティをドロップするには:

Messages.sendLocalMessage('Hifi-Hand-Drop', 'XXX'); // where XXX is either the left or right hand

シグナルを関数に接続する

シグナルは関数に接続することができます。これは、シグナルがトリガーされるたびに関数が実行されることを意味します。例えば、衝突が有効または無効になったときにアバターが変化する場合、この特定のイベントに反応するように次のような関数を接続することができます。

function collisionChanged(enabled) {
  if(enabled) {
    console.log("avatar collision is enabled");
  } else {
    console.log("avatar collision id disabled")
  }
}

MyAvatar.collisionsEnabledChanged.connect(collisionChanged);

通常、各シグナルは引数で渡されます。APIドキュメントを参照して、衝突に渡された有効なプロパティなど、シグナルが提供するものを確認できます。

シグナルから切断することをお勧めしますが、関数に名前を付けた場合にのみ切断できます。

MyAvatar.collsionEnabledChanged.disconnect(collsionChanged);

関連項目