VRML with JavaScript Tutorial

戻る はじめに

変数について

VRMLのJavaScriptの変数はWebブラウザーのJavaScriptの変数と概ね同じですが、若干仕様が異なります。

変数の有効範囲

先の作例から initialize 関数内の
var col = blue;

col = blue;
に変えてみました。
VRML - ソース / X3D - ソース
DEF Sc Script {
eventIn SFTime colorChange
eventOut SFColor ballColor
field SFColor col 0 1 0 # 緑
field SFColor blue 0 0 1 # 青
url "javascript:

function initialize () {
col = blue;
}

function colorChange () {
ballColor = col;
}

"
}
この作例ではCosmoCortonaContact ともに、赤い球をクリックすると青色にかわります。

先の例では initialize 関数の中の col の前に var を付けていました。  これは新規に col という名前のローカル変数を生成したことを意味します。  関数の中で var 宣言をして生成された変数はローカル変数となります。  ローカル変数はそれを生成した関数(この場合 initialize 関数)が終了すると破棄されます。  field で定義した col はグローバル変数扱いであり、ローカル変数が有効な範囲では影響を受けません。  その為、先の例では 0 1 0 (緑色)が colorChange 関数で ballColor に代入されたのです。

それに対して、この作例では initialize 関数の中で var 宣言をしていません。  これは field で定義したグローバル変数 col への代入となります。  colorChange 関数では initialize 関数で代入された blue の値が ballColor に代入される為、クリックすると青く変わるのです。
グローバル変数 と ローカル変数
プログラムの何処からでも読み書きできる変数をグローバル変数、ある範囲内でのみ有効な変数をローカル変数といいます。

ある関数内でグローバル変数と同じ名前のローカル変数が生成されたならば、その関数の中ではそのローカル変数のみにアクセスでき、グローバル変数は値が保持されます。  ローカル変数はその関数が終了すると破棄されます。

ローカル変数を使うと複数の関数で変数名の使い回しができます。  大きなプログラムを作る際に変数名が重複していないかどうかなど、チェックの負担が軽減します。

VRMLブラウザーごとの変数生成の違い

それでは、field で定義されておらず、また関数内で var 宣言せずに生成された変数はどの様な扱いになるのでしょうか。  先の作例から
field SFColor col 0 1 0 # 緑
を省いてみました。
VRML - ソース / X3D - ソース
DEF Sc Script {
eventIn SFTime colorChange
eventOut SFColor ballColor
field SFColor blue 0 0 1 # 青
url "javascript:

function initialize () {
col = blue;
}

function colorChange () {
ballColor = col;
}

"
}
CosmoCortona では赤い球をクリックすると、青色に変わります。  これらのVRMLブラウザーでは変数 col はグローバル変数になり、たとえ initialize 関数が終了しても破棄されないまま他の関数に値を引き継ぐことができます。

Contact では赤い球をクリックするとエラーが表示され、色は変わりません。  このVRMLブラウザーでは initialize 関数で生成された 変数 col はローカル変数になり、この関数が終了すると破棄されます。  colorChange 関数で未定義変数 colballColor に代入しようとした為、エラーとなるのです。

この通りVRMLブラウザーにより変数生成の扱いが異なる為、違う結果となってしまいます。


Cosmo Cortona Contact
field もしくは eventOut で定義された変数 グローバル変数 グローバル変数 グローバル変数
関数内で var 宣言しないで生成された変数 グローバル変数 グローバル変数 ローカル変数
関数内で var 宣言して生成された変数 ローカル変数 ローカル変数 ローカル変数

Cosmo Cortona Contact ともに同様の動作をさせるには、 グローバル変数は field で定義し、ローカル変数は関数内で var 宣言して生成するようにしてください。

変数の型

field を設定する際、同時にを定義する必要がありますが、 その定義された変数にが異なる値を代入するとどうなるか確かめてみましょう。
VRML - ソース / X3D - ソース
この作例では左に赤い球、右に黄色い箱が表示され、どちらもクリックを受け付けます。
DEF Sc Script {
eventIn SFTime colorChange
eventIn SFTime translationChange
eventOut SFColor ballColor
eventOut SFVec3f boxTranslation
field SFColor col 0 1 0 # 緑
field SFColor blue 0 0 1 # 青
field SFVec3f vect 0 0 1
url "javascript:

function colorChange () {
col = vect;
ballColor = col;
}

function translationChange () {
var col = vect;
boxTranslation = col;
}

"
}
左の赤い球をクリックすると colorChange 関数が実行され、 右の黄色い箱をクリックすると translationChange 関数が実行されます。

field で定義されている bluevect は値こそ同じ 0 0 1 ですが、それぞれ SFColorSFVec3f という異なったが設定されてます。

colorChange 関数では変数 col とはが異なる vect を代入しています。
Cosmo では赤い球をクリックすると、エラーが表示され、色は変わりません。
CortonaContact ではエラーこそ表示されませんが、青色 ( 0 0 1 ) ではなく緑色 ( 0 1 0 ) に変わります。
実行結果こそ異なりますが、何れのVRMLブラウザーでも colvect の値は代入されません。  field もしくは eventOut で定義した変数に代入する値は、が同じである必要があります。

もちろん JavaScript の特徴である型変換が自動で行われる場合もあります。  例えば、既に文字列が入った変数もしくは SFString で定義された変数に数値を代入すると、その数値は自動的に文字列に変わります。  SFInt32 型の変数に小数点以下が含まれた実数を代入すると、自動的に整数化されます。

translationChange 関数はローカル変数 col に代入しています。
Cosmo Cortona Contact ともに、黄色い箱をクリックすると、中央の手前の位置 ( 0 0 1 ) にその箱が移動します。  が定義されずに生成されたローカル変数に代入する場合は、同名のグローバル変数のに縛られることはありません。


イベント入力値や field で定義された値など が示されている値を JavaScript で扱う際は、以下のような型変換が行われます。 この作例でいえば、グローバル変数 colSFColor オブジェクト、vectSFVec3f オブジェクトが値として入っている、といえます。

変数の複写と参照

複写 ( Copy ) と 参照 ( Reference )
ある変数から別の変数へ値を代入する際の性質は、値の種類により異なります
数値 か bool値 か 文字列 ならば、変数への代入は「複写」が行われます。  それ以外のオブジェクトならば、「参照」で行われます。

「複写」によって代入された変数を操作しても元の変数に影響を与えませんし、元の変数を操作しても「複写」された変数は影響を受けません。

「参照」によって代入された変数と元の変数は、どちらか一方を操作しても互いに同じ値になります。
VRML の JavaScript でも基本的には上記枠内の通りなのですが、以下の項目で示される仕様がありますので注意してください。

VRML - ソース / X3D - ソース
左側の球をクリックする度に、赤 ( 1 0 0 ) → 緑 ( 0 1 0 ) → 青 ( 0 0 1 ) → 赤 ( 1 0 0 ) と色が変化します。  右側の箱をクリックする度に、黄 ( 1 1 0 ) → 水色 ( 0 1 1 ) → 紫 ( 1 0 1 ) → 黄 ( 1 1 0 ) と色が変化します。  これは CosmoCortonaContact ともに同じ動作をします。
DEF Sc Script {
eventIn SFTime touched_Ball
eventIn SFTime touched_Box
eventOut SFColor ballColor
eventOut SFColor boxColor
field SFColor black 0 0 0
field SFColor red 1 0 0
field SFColor col 0 1 1
url "javascript:
function initialize () {

ballColor = red;

}
function touched_Ball () {

// c0 is reference of ballColor.
var c0 = ballColor;

var b = c0.b;
c0.b = c0.g;
c0.g = c0.r;
c0.r = b;

// c0 is reference of black.
c0 = black;

}
function touched_Box () {

// c1 is reference of col.
var c1 = col;

// boxColor is copy of c1.
boxColor = c1;

var b = c1.b;
c1.b = c1.g;
c1.g = c1.r;
c1.r = b;

print( 'boxColor = ' + boxColor );
print( 'col = ' + col );

}
"
}
touched_Ball 関数において、最初の
c0 = ballColor;
で、c0 は ballColor の「参照」となります。  よって、それ以降 c0 を操作すると ballColor は c0 と同じ値になります。  但し、
c0 = black;
は、ここで c0 は black の「参照」となりますので、ballColor も黒くなるようなことはありません。

touched_Box 関数において、
c1 = col;
で、c1 は col の「参照」となります。  しかし、その次の
boxColor = c1;
で、その時点の c1 の値が boxColor に「複写」されます。  boxColor は c1 の「参照」ではありません。  以降 c1 を操作すると col も同じ値になりますが、boxColor は影響を受けません。  col の内容は次回の関数実行時に boxColor に値が引き継がれます。
このページのトップ | 前へ 初期化について | 次へ オブジェクト