proto_sheep.wrl source
#VRML V2.0 utf8

PROTO Sheep [
eventIn MFFloat packet_in
eventOut MFFloat packet_out
]
{
DEF Move-Tf Transform {
children [
DEF Action-Tf Transform {
translation 0 1.1 0
children [
# 体
Shape {
appearance DEF Body-Ap Appearance {
material Material {
diffuseColor 1 1 0.8
}
}
geometry Sphere {
radius 1.0
}
}
# 頭
DEF Head-Tf Transform {
rotation 1 0 0 0.0
children [
Transform {
scale 0.7 0.9 0.7
rotation -1 0 0 0.5
translation 0 0.2 1
children [
Shape {
appearance DEF Haed-Ap Appearance {
material Material {
diffuseColor 0.3 0.2 0.2
}
}
geometry Sphere {
radius 0.7
}
}
# 左耳
DEF YearL Transform {
scale 2 0.7 1
translation 0.6 0.4 0.1
children [
DEF Year-Sp Shape {
appearance USE Haed-Ap
geometry Sphere {
radius 0.2
}
}
]
}
# 右耳
DEF YearR Transform {
scale 2 0.7 1
translation -0.6 0.4 0.1
children USE Year-Sp
}
# 左目
DEF EyeL Transform {
translation 0.35 0.25 0.5
children [
DEF Eye-Sp Shape {
appearance Appearance {
material Material {
diffuseColor 0 0 0.001
}
}
geometry Sphere {
radius 0.1
}
}
]
}
# 右目
DEF EyeR Transform {
translation -0.35 0.25 0.5
children USE Eye-Sp
}
]
}
]
}
# 左前足
DEF FootFL-Tf Transform {
rotation 1 0 -1 0.8
children [
Transform {
translation 0.75 0.0 0.75
children [
DEF Foot-Sp Shape {
appearance USE Haed-Ap
geometry Sphere {
radius 0.3
}
}
]
}
]
}
# 右前足
DEF FootFR-Tf Transform {
rotation 1 0 1 0.8
children [
Transform {
translation -0.75 0.0 0.75
children USE Foot-Sp
}
]
}
# 左後ろ足
DEF FootRL-Tf Transform {
rotation -1 0 -1 0.8
children [
Transform {
translation 0.75 0.0 -0.75
children USE Foot-Sp
}
]
}
# 右後ろ足
DEF FootRR-Tf Transform {
rotation -1 0 1 0.8
children [
Transform {
translation -0.75 0.0 -0.75
children USE Foot-Sp
}
]
}
# 尻尾
DEF Tail-Tf Transform {
rotation 1 0 0 0.3
children [
Transform {
translation 0 0 -1
children [
DEF Foot-Sp Shape {
appearance USE Body-Ap
geometry Sphere {
radius 0.2
}
}
]
}
]
}
]
}
DEF Shadow-Tf Transform {
translation -0.1 0 -0.1
scale 1 0.01 1
children [
Shape {
appearance DEF Shadow-Ap Appearance {
material Material {
diffuseColor 0 0 0.001
transparency 0.5
}
}
geometry Sphere {
radius 1.05
}
}
]
}
DEF Vp Viewpoint {
position 5 2.5 5
orientation 0 1 0 0.785
}
DEF ThS TouchSensor {}
]
}

# クリックするとその羊に視点を移動するスクリプト
DEF View-Sc Script {
eventIn SFTime touchTime
eventOut SFBool set_bind
url "javascript:
function touchTime () {

set_bind = TRUE;

}
"
}
ROUTE ThS.touchTime TO View-Sc.touchTime
ROUTE View-Sc.set_bind TO Vp.set_bind

# 小数値を4本の足の角度に適応するスクリプト
DEF Foot-Sc Script {
eventIn SFFloat set_value
field MFNode Foots [ USE FootFL-Tf USE FootFR-Tf USE FootRL-Tf USE FootRR-Tf ]
directOutput TRUE
url "javascript:
function set_value (f) {

for ( var i = 0; i < 4; i++ ) Foots[i].rotation[3] = f;

}
"
}

# ジャンプの高さに応じて影の大きさを変えるスクリプト
DEF Shadow-Sc Script {
eventIn SFVec3f set_translation
eventOut SFVec3f scale
url "javascript:
function set_translation (vec) {

var s = 1 / (vec.y - 0.1);
scale = new SFVec3f ( s, 0.01, s );

}
"
}
ROUTE Action-Tf.translation TO Shadow-Sc.set_translation
ROUTE Shadow-Sc.scale TO Shadow-Tf.scale

# ジャンプアニメーション
DEF Jump-TiS TimeSensor {
cycleInterval 3
}

DEF Jump-Body-PI PositionInterpolator {
key [ 0.0 0.1 0.5 0.9 1.0 ]
keyValue [
0.0 1.1 0.0
0.0 1.0 0.0
0.0 2.6 0.0
0.0 1.0 0.0
0.0 1.1 0.0
]
}

ROUTE Jump-TiS.fraction_changed TO Jump-Body-PI.set_fraction
ROUTE Jump-Body-PI.value_changed TO Action-Tf.translation

DEF Jump-Foot-SI ScalarInterpolator {
key [ 0.0 0.1 0.2 0.5 0.7 0.9 1.0 ]
keyValue [ 0.8 0.5 1.2 0.2 0.2 0.9 0.8 ]
}

ROUTE Jump-TiS.fraction_changed TO Jump-Foot-SI.set_fraction
ROUTE Jump-Foot-SI.value_changed TO Foot-Sc.set_value

DEF Jump-Head-OI OrientationInterpolator {
key [ 0.0 0.1 0.5 0.7 0.9 1.0 ]
keyValue [
1 0 0 0.0
1 0 0 0.2
1 0 0 -0.3
1 0 0 0.2
1 0 0 0.3
1 0 0 0
]
}

ROUTE Jump-TiS.fraction_changed TO Jump-Head-OI.set_fraction
ROUTE Jump-Head-OI.value_changed TO Head-Tf.rotation

DEF Jump-Scale-PI PositionInterpolator {
key [ 0.0 0.9 0.95 1.0 ]
keyValue [
1.0 1.0 1.0
1.0 1.0 1.0
1.1 0.8 1.0
1.0 1.0 1.0
]
}

ROUTE Jump-TiS.fraction_changed TO Jump-Scale-PI.set_fraction
ROUTE Jump-Scale-PI.value_changed TO Move-Tf.scale

DEF Jump-Position-PI PositionInterpolator {
key [ 0.0 1.0 ]
}

ROUTE Jump-TiS.fraction_changed TO Jump-Position-PI.set_fraction
ROUTE Jump-Position-PI.value_changed TO Move-Tf.translation

# 自転アニメーション
DEF Rot-TiS TimeSensor {
cycleInterval 2
}
DEF Rot-OI OrientationInterpolator {
key [ 0.0 1.0 ]
}

ROUTE Rot-TiS.fraction_changed TO Rot-OI.set_fraction
ROUTE Rot-OI.value_changed TO Move-Tf.rotation

# 餌を食べるアニメーション
DEF Eat-TiS TimeSensor {
cycleInterval 1.5
}

DEF Eat-Head-OI OrientationInterpolator {
key [ 0.0 0.2 0.5 0.7 1.0 ]
keyValue [
1 0 0 0.0
1 0 0 0.6
1 0 0 0.4
1 0 0 0.6
1 0 0 0.0
]
}

ROUTE Eat-TiS.fraction_changed TO Eat-Head-OI.set_fraction
ROUTE Eat-Head-OI.value_changed TO Head-Tf.rotation

DEF Eat-Body-PI PositionInterpolator {
key [ 0.0 0.2 0.5 0.7 1.0 ]
keyValue [
0.0 1.1 0.0
0.0 1.0 0.0
0.0 1.1 0.0
0.0 1.0 0.0
0.0 1.1 0.0
]
}

ROUTE Eat-TiS.fraction_changed TO Eat-Body-PI.set_fraction
ROUTE Eat-Body-PI.value_changed TO Action-Tf.translation

DEF EatPos-PI PositionInterpolator {
key [ 0.0 0.25 0.5 0.75 1.0 ]
}

ROUTE Eat-TiS.fraction_changed TO EatPos-PI.set_fraction
ROUTE EatPos-PI.value_changed TO Move-Tf.translation

DEF EatRot-OI OrientationInterpolator {
key [ 0.0 0.25 0.5 0.75 1.0 ]
}

ROUTE Eat-TiS.fraction_changed TO EatRot-OI.set_fraction
ROUTE EatRot-OI.value_changed TO Move-Tf.rotation

# 羊の動作用タイムセンサー
DEF Action-TiS TimeSensor {
loop TRUE
}

# 羊の動作及びデータ交信スクリプト
DEF Action-Sc Script {
eventIn MFFloat receivePacket IS packet_in
eventIn SFTime startAction
eventIn SFTime transmitPacket
eventOut MFVec3f keyValueJumpPosition
eventOut MFRotation keyValueRotation
eventOut MFVec3f keyValueEatPosition
eventOut MFRotation keyValueEatRotation
eventOut MFFloat packet_out IS packet_out
field SFInt32 thisId -1 # この羊のIDナンバー (追加された直後に、0以上の順番がメインから与えられる)
field SFNode thisSheep USE Move-Tf # この羊の位置と向きの取得及び設定に使う
field MFNode TimeSensors [ USE Jump-TiS, USE Rot-TiS, USE Eat-TiS ] # この羊の動作を仕切るタイムセンサー
field SFVec3f targetPos 0 -99 0 # この羊の目標位置(y成分が -99 ならば未設定)
field SFVec3f initDirection 0 0 1 # この羊の移動方向(前方)の初期値
field SFInt32 nearestId -1 # 最も近くにいる羊のIDナンバー ( -1 ならば未設定)
field SFVec3f nearestPos 0 0 0 # 最も近くにいる羊の位置
directOutput TRUE
url "javascript:

function initialize () {

// (1-1)
thisSheep.rotation.setAxis( new SFVec3f ( 0, 1, 0 ) );

}

function receivePacket (p) {

var receiveId = p[0];
var receivePos = new SFVec3f ( p[1], p[2], p[3] );

// (2-1)
if ( thisId < 0 ) {

thisId = receiveId;
thisSheep.translation = receivePos;
thisSheep.rotation[3] = Math.random() * 2 * Math.PI;
return;

}

// (2-2)
var thisPos = thisSheep.translation;

// (2-2-1)
if ( nearestId < 0 ) {

nearestId = receiveId;
nearestPos = receivePos;

}
// (2-2-2)
else if ( nearestId == receiveId ) {

nearestPos = receivePos;

}
else {

var receive2thisLength = thisPos.subtract( receivePos ).length();
var nearest2thisLength = thisPos.subtract( nearestPos ).length();

if ( receive2thisLength < nearest2thisLength ) {

nearestId = receiveId;
nearestPos = receivePos;

}
else return;
}

// (2-3)
targetPos = thisPos.subtract( nearestPos ).normalize().multiply( 7.0 ).add( nearestPos );

}

function startAction (t) {

// (3-1)
if ( thisId < 0 ) return;

// (3-2)
for ( var i=0; i<TimeSensors.length; i++) if ( TimeSensors[i].isActive ) return;

// (3-3)
var thisPos = thisSheep.translation;
var thisRot = thisSheep.rotation;
var vecThis2Target = targetPos.subtract( thisPos );
var thisDirection = thisRot.multVec( initDirection );

if ( targetPos.y == -99 || vecThis2Target.length() < ( Math.random() * 1.0 + 2.0 ) ) {

var p0 = new MFVec3f();
p0[0] = p0[1] = p0[2] = p0[3] = thisPos;
p0[4] = thisDirection.multiply( Math.random() * 0.2 + 0.1 ).add( thisPos );

var newAngle = thisRot.angle + Math.random() - 0.5;
var axis = thisRot.getAxis();
var newRot = new SFRotation ( axis, newAngle );

var r0 = new MFRotation();
r0[0] = r0[1] = r0[2] = thisRot;
r0[3] = r0[4] = newRot;

keyValueEatPosition = p0;
keyValueEatRotation = r0;

TimeSensors[2].startTime = t + Math.random() * 0.5;

return;
}

// (3-4)
var cosDirAndTarget = thisDirection.dot( vecThis2Target.normalize() );

if ( cosDirAndTarget < 0.9 ) {

var r0 = new MFRotation();
r0[0] = thisRot;
r0[1] = new SFRotation ( initDirection, vecThis2Target );
keyValueRotation = r0;

TimeSensors[1].startTime = t;

}
else {

var p0 = new MFVec3f();
p0[0] = thisPos;
p0[1] = thisDirection.multiply( 3.0 ).add( thisPos );
keyValueJumpPosition = p0;

TimeSensors[0].startTime = t;

}

}

function transmitPacket () {

if ( thisId < 0 ) return;

var packet = new MFFloat();
packet[0] = thisId;
packet[1] = thisSheep.translation[0];
packet[2] = thisSheep.translation[1];
packet[3] = thisSheep.translation[2];
packet_out = packet;

}

"

# initialize() 初期設定
# (1-1) この羊の向きを示す回転軸をy軸中心に設定する。

# receivePacket () データ受信
# (2-1) 一番最初に受信するデータは他の羊からではなくメインのプログラムからであり、それはこの羊のIDナンバーと初期位置である。
# これを受診したとき、羊の向きがランダムに設定される。
# (2-2) データを送ってきた羊が、他の羊の中から一番近い場所にあるかどうか調べる。
# (2-2-1) nearestId が未設定ならば、送信元の羊が一番近い場所にいるとする。
# (2-2-2) nearestId が設定済ならば、受診したIDが nearestId と一致するか調べる。
# 一致するならば nearestPos を受診した位置データに更新する。
# (2-2-3) 受診したIDが nearestId でないならば、この羊からの距離が nearestPos と 受診した位置とどちらが近いか比べる。
# もし受診した位置の方が近いならば、その送信元の羊を一番近い場所にいるとする。
# (2-3) 最も近い場所にいる羊から始まってこの羊への半直線上にあり、7.0 離れた場所を目標位置(targetPos)とする。

# startAction () この羊に何らかのアクションを行わせる関数
# (3-1) まだこの羊のIDが設定されていないならば何も行わない。
# (3-2) いずれかのアニメーションのタイムセンサーが動作中ならば、何も行わない。
# (3-3) 目標位置(targetPos)が未設定もしくは、この羊と最も近い場所にいる羊との距離が2.0〜3.0(ランダム)未満ならば、餌を食べるアニメを開始する。
# (3-4) 上記の条件に一致しないならば、この羊の進行方向のベクトルとこの羊から目標位置(targetPos)に至るベクトルのなす角を調べる。
# なす角のコサイン値が0.9未満ならば、羊の向きを目標に向ける回転アニメを開始する。
# そうでないならば、この羊を前方へジャンプするアニメを開始する。

# transmitPacket () データ送信
# この羊のIDナンバーが設定済ならば、この羊のIDナンバーと位置を送信する。

}

# 一定時間ごとに羊に何らかのアクションを行わせる
ROUTE Action-TiS.cycleTime TO Action-Sc.startAction

# ジャンプもしくは餌を食べた後にデータ送信
ROUTE Jump-TiS.cycleTime TO Action-Sc.transmitPacket
ROUTE Eat-TiS.cycleTime TO Action-Sc.transmitPacket

# ジャンプと回転のアニメ設定
ROUTE Action-Sc.keyValueJumpPosition TO Jump-Position-PI.keyValue
ROUTE Action-Sc.keyValueRotation TO Rot-OI.keyValue
ROUTE Action-Sc.keyValueEatPosition TO EatPos-PI.keyValue
ROUTE Action-Sc.keyValueEatRotation TO EatRot-OI.keyValue

}

##### 羊のインスタンス #####
Sheep {}