<?xml version="1.0" encoding="UTF-8"?>
<X3D>
<Scene>
<WorldInfo title='Squash rackets'/>
<Viewpoint position='0 1.7 10' description='initial'/>
<Viewpoint position='0 7.8 9.7' orientation='-1 0 0 0.68' description='Bird'/>
<NavigationInfo headlight='FALSE'
type='
"EXAMINE"'
/>
<Background
skyAngle='1.57 1.571'
skyColor='
0 0.2 1
0.5 0.8 1
0.6 0.3 0'
/>
<PointLight location='1 2.5 6'/>
<PointLight location='-1 2.5 6'/>
<!-- floor -->
<Transform translation='0 -0.005 0'>
<Shape>
<Appearance>
<Material diffuseColor='1 0.7 0.3'/>
</Appearance>
<Box size='5 0.01 10'/>
</Shape>
</Transform>
<!-- ceiling -->
<Transform translation='0 3.05 0'>
<Shape>
<Appearance>
<Material diffuseColor='1 0.9 0.7' emissiveColor='0.3 0.3 0.27' transparency='0.7'/>
</Appearance>
<Box size='5 0.1 10'/>
</Shape>
</Transform>
<!-- back wall -->
<Transform translation='0 1.5 -5.05'>
<Shape>
<Appearance DEF='Court-Ap'>
<Material diffuseColor='0.2 0.9 0.7'/>
</Appearance>
<Box size='5.2 3.2 0.1'/>
</Shape>
</Transform>
<!-- left wall -->
<Transform translation='-2.55 1.55 0'>
<Shape DEF='SideWall-Sp'>
<Appearance USE='Court-Ap'/>
<Box size='0.1 3.1 10'/>
</Shape>
</Transform>
<!-- right wall -->
<Transform translation='2.55 1.55 0'>
<Shape USE='SideWall-Sp'/>
</Transform>
<!-- ball -->
<Transform DEF='Ball-Tf'>
<Shape>
<Appearance>
<Material diffuseColor='1 0 0'/>
</Appearance>
<Sphere DEF='Ball' radius='0.2'/>
</Shape>
<TouchSensor DEF='Ball-ThS'/>
</Transform>
<!-- ball's shadow -->
<Transform DEF='BallShadow-Tf' scale='1 0.01 1'>
<Shape>
<Appearance>
<Material diffuseColor='0 0 0'/>
</Appearance>
<Sphere USE='Ball'/>
</Shape>
</Transform>
<!-- racket -->
<Transform DEF='Racket-Tf' translation='0 1 5.2'>
<Shape>
<Appearance>
<Material diffuseColor='1 1 0' transparency='0.3'/>
</Appearance>
<Box size='1 1 0.1'/>
</Shape>
<PlaneSensor DEF='Racket-PlS' maxPosition='2 2.5' minPosition='-2 0.5' offset='0 1 5.2'/>
</Transform>
<!-- racket's shadow -->
<Transform DEF='RacketShadow-Tf' translation='0 0 5.2'>
<Shape>
<Appearance>
<Material diffuseColor='0 0 0'/>
</Appearance>
<Box size='1 0.001 0.1'/>
</Shape>
</Transform>
<TimeSensor DEF='TiS' loop='TRUE'/>
<Script DEF='Sc'>
<field accessType='inputOnly' type='SFTime' name='touchTime_Ball'/>
<field accessType='inputOnly' type='SFFloat' name='set_fraction'/>
<field accessType='inputOnly' type='SFVec3f' name='translation_Racket'/>
<field accessType='outputOnly' type='SFVec3f' name='posBall'/>
<field accessType='outputOnly' type='SFVec3f' name='posBallShadow'/>
<field accessType='outputOnly' type='SFVec3f' name='posRacketShadow'/>
<field accessType='initializeOnly' type='SFVec3f' name='moveVec' value='0 0 0'/>
<field accessType='initializeOnly' type='SFFloat' name='oldF' value='0'/>
<field accessType='initializeOnly' type='SFVec3f' name='posRacket' value='0 0 0'/>
<field accessType='initializeOnly' type='SFBool' name='active' value='FALSE'/>
<field accessType='initializeOnly' type='SFFloat' name='speed' value='5'/>
<field accessType='initializeOnly' type='SFBool' name='isCortona' value='FALSE'/>
<![CDATA[ecmascript:
function initialize () {
// ボールとその影の位置をセットする。
posBall.x = 2 * Math.random() - 1;
posBall.y = 2 * Math.random() + 0.5;
posBall.z = 5;
posBallShadow.x = posBall.x;
posBallShadow.y = 0;
posBallShadow.z = posBall.z;
// 実行中のブラウザーが Cortona か調べる。
isCortona = (Browser.getName() == 'Cortona VRML Client');
}
function touchTime_Ball () {
// 既に active が true (ボールが動いている)ならば、この関数を終える。
if (active) return;
// active を true にセットする。(ボールを動かす)
active = true;
// ボールの移動ベクトルをセットする。
moveVec.x = Math.random() * 2 - 1;
moveVec.y = Math.random() * 2 - 1;
moveVec.z = -1;
// ボールのスピードを 5.0 とする。
speed = 5.0;
moveVec = moveVec.normalize().multiply(speed);
}
function set_fraction (f) {
// fraction の変化量を得る。
var df = f - oldF;
if ( df < 0 ) df++;
oldF = f;
// ブラウザーがCortonaならば、df にフレームレートの逆数を入れる。
if (isCortona) {
var fps = Browser.getCurrentFrameRate();
if ( fps > 0.0 ) df = 1 / fps;
}
// active が false ならば、この関数を終えてボールを動かさないようにする。
if ( !active ) return;
// ボールを移動させる。
posBall = moveVec.multiply(df).add(posBall);
// ボールがコートからはみ出ているならば、
// ボールの進行方向を変えて、ボールをコートの内側に置く。
if ( posBall.x < -2.3 || posBall.x > 2.3 ) {
moveVec.x = -moveVec.x;
posBall.x = Math.max( -2.3, Math.min( 2.3 , posBall.x ));
}
if ( posBall.y < 0.2 || posBall.y > 2.8 ) {
moveVec.y = -moveVec.y;
posBall.y = Math.max( 0.2, Math.min( 2.8 , posBall.y ));
}
if ( posBall.z < -4.8 ) {
moveVec.z = -moveVec.z;
posBall.z = Math.max( -4.8 , posBall.z );
}
// ボールが手前に帰ってきたならば、ラケットにボールが当たっているか判断させる。
if ( posBall.z > 5.0 ) {
judgeCollisionWithRacket ();
posBall.z = 5.0;
}
// ボールの影の位置をセットする。
posBallShadow.x = posBall.x;
posBallShadow.y = 0;
posBallShadow.z = posBall.z;
}
function judgeCollisionWithRacket () {
// ボールとラケットの中心位置との距離をx成分とy成分について得る。
var dx = Math.abs ( posRacket.x - posBall.x );
var dy = Math.abs ( posRacket.y - posBall.y );
if ( dx < 0.7 && dy < 0.7 ) {
// ボールがラケットに当たっているならば、ボールの進行方向を変える。
moveVec.z = -moveVec.z;
// ボールがラケットに当たる度に、ボールのスピードを少しずつ上げる。
speed += 0.2;
moveVec = moveVec.normalize().multiply(speed);
}
// ボールがラケットから外れているならば、 active を false にしてボールを止める。
else active = false;
}
function translation_Racket (val) {
// ラケットの位置を得る。
posRacket = val;
// ラケットの影の位置をセットする。
posRacketShadow.x = val.x;
posRacketShadow.y = 0;
posRacketShadow.z = val.z;
}
]]>
</Script>
<ROUTE fromNode='Racket-PlS' fromField='translation_changed' toNode='Racket-Tf' toField='translation'/>
<ROUTE fromNode='Sc' fromField='posRacketShadow' toNode='RacketShadow-Tf' toField='translation'/>
<ROUTE fromNode='Ball-ThS' fromField='touchTime' toNode='Sc' toField='touchTime_Ball'/>
<ROUTE fromNode='TiS' fromField='fraction_changed' toNode='Sc' toField='set_fraction'/>
<ROUTE fromNode='Sc' fromField='posBall' toNode='Ball-Tf' toField='translation'/>
<ROUTE fromNode='Sc' fromField='posBallShadow' toNode='BallShadow-Tf' toField='translation'/>
<ROUTE fromNode='Racket-PlS' fromField='translation_changed' toNode='Sc' toField='translation_Racket'/>
</Scene>
</X3D>