02/25/2007

とりあえず動くポーズボールの作り方

ポーズボールというのは、アバターを座らせたり躍らせたりするためのスイッチのようなものです。椅子の上に丸いボールが置かれているのをよく見かけると思います。

ここではチュートリアルにあるスクリプトを利用して、実際のポーズボールの作成方法を紹介します。
 
用意するものは3つ。

1.アニメーションファイル
2.オブジェクト
3.スクリプト

このうちアニメーションファイルはSLの外で作成します。汎用ツールでもSL用に作られたツールでも作成可能です。今回は簡単のためにQAvimatorというソフトを使います。各OS版がでてますが、他はわからないのでWindows前提で話を進めます。
アニメーションの作成法はSLwiki(JP)でも紹介されています。
アニメーション作成(SL wiki JP)


1.QAvimatorセットアップ
公式サイトhttp://qavimator.org/からWindows版QAvimator(2007/02現在では「qavimator-install-2006-09-25.zip」)をダウンロードします。
そのまま解凍してセットアップファイルを実行、インストールします。

2.QAvimator起動・作成
QAvimatorを起動します。

Qavimator


今回は2こまのアニメーションなので、右下のフレーム数を「2」に設定します。
2フレーム目にアバターにとらせたいポーズを作成しますが、起動した状態で最後のフレームになっているのでそのままで大丈夫です。各パーツを選択した状態で右の「Rotation」や「Position」を変更してポーズを作っていきます。
このとき腰パーツの位置がアバターの座標となります。腰位置が高すぎるとポーズをとらせたときに体が浮いてしまったりします。

3.アニメーションファイル保存
ポーズが完成したらファイルに保存します。拡張子は「BVH」です。
拡張子は手打ちしないとダメそうだったので、例えばファイル名を「pose.bvh」などとします。

4.アニメーションファイルアップロード
セカンドライフビューワーを起動してログインします。
左上のfileメニューの3番目に「Upload Animation(L$10)というのがあるので、先ほど保存したアニメーションファイルを選択してアップロードします。
その際、LoopにチェックをいれPriorityを4にします。

5.アニメーションチェック
アップロードしたアニメーションは、下のメニューの一番右の「Inventory」→「Animation」に収納されています。
ファイル名右クリックで出るメニューから、「Play in World」(またはPlay Local)を選択すると、実際にアニメーションを試してみることができます。
ここでうまくいかない場合はアニメーションがうまく作れてないかもしれません。
また、アバターが浮いたり埋まってしまう場合はもう一度修正してからアップロードするか、場合のよってはスクリプトで補正できるかもしれません。

6.オブジェクト作成
今度はセカンドライフの中でオブジェクトを作成します。
下のメニューの中からBuild(または「立てる」)を選んで編集モードに入ります。create(または「生成」)を選んで適当に丸いオブジェクトを作成します。
オブジェクト作成の細かい操作方法ははじめてのオブジェクト作成(SL wiki JP)などで。

7.スクリプト作成
オブジェクト編集の「Content」で「New Script」を選択して新しいスクリプトをオブジェクト内に作ります。
「New Script」という名前のスクリプトができているので、中身をダブルクリックで開き、そこに書いてあるスクリプトは消してポーズボール用のスクリプトを書き込みます。
今回はLSL wikiのチュートリアルにあるスクリプトをそのまま使います。

現在元ページが工事中らしくて参照できないので、以下をそのままコピペしてください。

-------引用開始----------------

integer hidden = FALSE; // Stores whether the object is visible

default
{
state_entry()
{
llSitTarget(<0,0,1>,<0,0,0,1>); // Set the target one meter above the ground
llSetSitText("Pose!");
}

changed(integer change)
{
if(change & CHANGED_LINK) // If someone has sat on, or "linked," to this prim...
{
key agent = llAvatarOnSitTarget();
if(agent)
{
llStopAnimation("sit");
llStartAnimation("stand");
}
else
{
llStopAnimation("stand");
}
}
}

touch_start(integer total_number)
{
if(hidden)
{
hidden = FALSE;
llSetLinkAlpha(LINK_SET,1,ALL_SIDES);
}
else
{
hidden = TRUE;
llSetLinkAlpha(LINK_SET,0,ALL_SIDES);
}
}
}

-------引用終わり----------

さらに、このスクリプトで「dance1」となっているところを、自分のアニメーションの名前にします。(そのままだと「dance1」というもともとあるアニメーションが再生されます)
「Save」をクリックして保存し、エラーが出ていないことを確認します。

Script1


8.オブジェクトにアニメーションファイルを格納
先ほどのInventory内のアニメーションファイルを、ドラッグアンドドロップで「Content」のボックスに格納します。

Edit1

これで、ポーズボールの作成は完了です。


何かがおかしいとき
・アバターの向きや位置がおかしくなる
オブジェクトの向きを変えるか、スクリプトの最初のほうにある「llSitTarget(<0,0,1>,<0,0,0,1>); 」を調整してください。<0,0,1>が座標、<0,0,0,1>が向きになります。座標を調整することで、アニメーション作成で失敗してアバターが浮いてしまった、というのも直せる場合があります。
向きは欲しい向きを算出するのがめんどくさいので、編集モードでオブジェクトの向きを変えてしまうほうが楽だと思います。
参考:オブジェクトの回転に関する覚書

・ポーズボールの上に黄色い三角と「!」が表示される
エラーがでているので、その内容を確認します。
ビューワーのToolメニューから「Show Script Warning~」を選ぶとエラーの内容を確認することができます。でてこない場合はすでにその辺にでてるかもしれません。
考えられることは、コピペでミスをしている、アニメーションのファイル名が一致していない、などです。

・踊ってしまう
スクリプトで実行するアニメーションが「dance1」のままになっています。書き換えて見てください。


ちなみに私はエラー落ちしたり、立ち上がるときにまれに周りが真っ暗になったりしました。なのでどこか適正でないところがあるのかもしれません。

| | Comments (3)

02/07/2007

11.3. Definitions

"roll""pitch""yaw"といった言葉はよく、飛行機やボートにおける回転のモードを記述するのに使われます。それぞれx軸、y軸、z軸の回転に該当します。

z-axis .
yaw-axis /|\
| __. y-axis
._ ___| /| pitch-axis
_||\ \\ |\. /
\|| \_______\_|__\_/_______
| _ _ o o o o o o o |\_ ______\ x-axis
// ./_______,----,__________) / roll-axis
/_,/ // ./
/__,/

初歩的な物理学のコースでよく紹介される右手の法則は、これらの軸についての正回転を定義するのに使われます。右手の法則の使い方の例として、"roll(x軸)"の正回転について考えてみてください。
これらの回転がどのように飛行機を動かすかを可視化するために、右手の親指をx軸方向を指すようにして、飛行機のroll軸と平行になるように置いてください。そして、4本の指は手の平に折り曲げてください。そうすると、あなたの指は飛行機が回転する方向を指し示しています。


.-.--.--.--. __
/ / / / _ \ / \
(-(- (- (- ( | _________|______\ axis of
\.\._\._\._) | | / rotation
| \:__,---. \|/
| | + positive
\ .,_.___.' rotation
\_ ^ `.__,/
| /
| |

乗り物を制御する多くのパラメータはVEHICLE_BEHAVIOR_TIMESCALEで表されます。
乗り物の挙動の"timescale(時定数)"は一般的には、(何をさせたいかに関わらず)乗り物の挙動に対して押したり、カーブさせたり、もしくは別の影響を与え、その動作の大きさをe分の1にする時間です。
ここで"e"は自然対数の底(約2.718281828)です。

つまり、乗り物に希望通りの動作をさせているときに対する、指数的な減衰時間の目安であると言えます。

もし乗り物のレスポンスをとてもよくしたいのであれば、時定数を1秒やそれ以下という風に短く、そしてもしこの影響を無効にしたいのであれば300(5分)やそれ以上といった非常に大きな値にしてください。
ひとつ注意することは、安定性の問題から、通常は最小値に制限がありたいていは0.1秒のオーダーです。
時定数を0にすることは安全で最小値に設定することと同義です。時定数に特徴付けられたいかなる挙動も、効果が表れるまで丸一日かかるほど時定数を大きく設定してしまうことで効果的に無効にできます。


補足:超訳してしまいましたが例えばある初速度vを物体に与えたとすると、動き出した物体は最初はvで進んでいきますがだんだんと速度が落ちていき、時定数で設定した時間後にはv/eの速度になってしまいます。
現実で異動する物体が摩擦や空気抵抗でだんだん速度が落ちていくのを、このようにして模擬的に再現しているのです。
ここにあるように時間をものすごく短く(または0に)すればものすごく摩擦が働いているような状態になって一瞬でとまります。逆にものすごく長くすると、実際にはこの効果は働いているのですがその時間が長くなるため効果は出ていないように見えます。

| | Comments (2)

11/30/2006

Linden Script Language目次

<LSL wiki日本語訳>
チュートリアル - LSL101(プログラミング初心者向け)
  chapter1/chapter2/chapter3/chapter4/chapter5/chapter6


チュートリアル - Vehicles(乗り物作成)
11. Vehicles
11.1. Overview
11.2. Warnings
11.3. Definitions
11.4. Setting the Vehicle Type
11.5. Linear and Angular Deflection
11.6. Moving and Steering the Vehicle
11.7. The Linear Motor
11.8. The Angular Motor
11.9. Using the Camera to Steer
11.10. The Vertical Attractor
11.11. Banking
11.12. Friction Timescales
11.13. Buoyancy
11.14. Hover
11.15. Reference Frame
C. Constants
C.24. Vehicle Parameters
C.25. Vehicle Flags
C.26. Vehicle Types


<その他>
オブジェクトの回転に関する覚書
その1/その2

とりあえず動くポーズボールの作り方

| | Comments (0) | TrackBack (1)

07/14/2006

11.2. Warnings

乗り物についてはまだ開発中であり、SLの将来バージョンでは変更される可能性があります。安定性と安全性をより確実なものにする必要があるため、動作の細かい部分のいくつかは変更されるでしょう。特に、追記にある制限やデフォルトは変更される可能性が高く、長期的に見ると信頼できないものになっているでしょう。

オブジェクトに衝撃や力を与えるような他のスクリプトの呼び出し(特にllSetBuoyancy、llSetForcellSetTorquellSetHoverHeight)を、乗り物の動作と一緒に使うことはおすすめしません。

以下のメソッドは不安定性を起こさないと思いますが、乗り物と競合を起こして予期せぬ結果や矛盾を引き起こす可能性があるので、自己責任のもとで利用してください。 
llLookAt、llRotLookAt、llMoveToTargetllTargetOmega

乗り物に関するバグを発見したら、報告する方法のひとつとしては、乗り物とスクリプトのコピーをコメントかノートカードに問題を書いてAndrew Lindenに渡してください。
すべての依頼品には "Bugged Vehicle XX"と名前をつけてください。XXはあなたのセカンドライフイニシャルです。乗り物とスクリプトはできるだけ早く試験されるでしょう。

| | Comments (0)

11.1. Overview

スクリプトが組み込まれたそれぞれのオブジェクトはある乗り物としての動作を持っていて、その動作はライブラリから呼び出されるllSetVehicleTypellSetVehicleFloatParamllSetVehicleVectorParamllSetVehicleRotationParamllSetVehicleFlagsllRemoveVehicleFlagsによってコンフィグすることができます。

スクリプトが呼び出すこれらの関数の詳細は上のリンクにありますが、ここで注意すべき重要なことは乗り物の動作は、乗り物の処理の仕方を変更するたびに調整される、いくつかのパラメータをもっていることです。
選ばれる値によって、乗り物はボートのように水中で方向を変えたり、そりのようにレール上を走ったりします。

乗り物フラグ(vehcle frags)を設定すれば、いくつかのデフォルトの動作を期待できます。そのうちのいくつかは、ある動作が利用可能になったときのみ効果を持ちます。たとえば、VEHICLE_FLAG_HOVER_WATER_ONLYは乗り物が地形の高さを無視するようにしますが、ホバリングしているときのみ高低差を作ります。

| | Comments (0)

06/20/2006

オブジェクトの回転に関する覚書 その2

さて、オイラー表記できる回転は関数llEuler2Rotでrotation(四元数)に変換してくれるからいいとして、問題は軸の方向と回転角だけがわかっているとき実際に四元数でどう記述するのか、です。
例えばある方向に傾いたまま回る独楽を作りたいなんてときです。

残念ながらこの場合は、少しややこしい計算を行わなければなりません。

規格化された軸の方向を(a,b,c)とし回転角をθとすると、四元数(x,y,z,s)は

x = a ・sin(θ/2)
y = b ・sin(θ/2)
x = c ・sin(θ/2)
s = cos(θ/2)

となります。なぜ角度がθ/2なのかは直観的には、実際の計算は似たような形のものを2回掛けているからです。

 
詳しくはここなど。

物理のかぎしっぽの四元数
http://www12.plala.or.jp/ksp/mathInPhys/quaternion/
 
 

この若干面倒な計算のためのサンプルスクリプトがLSL wikiにあって、次のようになります。


rotation make_quaternion( vector axis, float angle )
{
vector unit_axis = llVecNorm( axis );
float sine_half_angle = llSin( angle/2 );
float cosine_half_angle = llCos( angle/2 );

rotation quat;
quat.x = sine_half_angle * unit_axis.x;
quat.y = sine_half_angle * unit_axis.y;
quat.z = sine_half_angle * unit_axis.z;
quat.s = cosine_half_angle;

return quat;
}

 

axisに回転軸の方向(規格化されてなくてもよい)・angleに回転角を与えればrotation quatが計算されます。

| | Comments (0)

06/16/2006

オブジェクトの回転に関する覚書

プリミティブ(オブジェクト)を回転させるとき、

vector eul = <0, 0, 45>; //z軸周りに45度回転するというオイラー表記
eul *= DEG_TO_RAD; //とりあえずラジアンに変換
rotation quat = llEuler2Rot( eul ); //オイラー表記を四元数に変換
llSetRot( quat ); //回転の実行

とします。
非常に数学的な操作を含んでいるので、一行ずつ解説を加えていくことにします。
 


■vector eul = <0, 0, 45>;

x軸を周りにα、y軸周りにβ、z軸周りに回転させるとき、<α,β,γ>と書き、これをEuler表記といいます。値が3つ並んでいるので、変数の型はvector(ベクトル)です。ちなみに、この表記をしたときは必ずx軸周り→y軸周り→z軸周りの順に回転が行われます。
(試してみるとわかりますが、回転の順序を変えると異なる結果になります。)
 


■eul *= DEG_TO_RAD;

角度はラジアンで表す必要があります。360[度] = 2π[ラジアン]なので、45度はπ/4[ラジアン]になります。DEG_TO_RADというのはLSLにはじめから用意されている定数(constant)で、"2π/360"と同じ意味です。
もちろん最初からラジアンで<0, 0, π/4>としておけば、この変換は必要ありません。

 

■rotation quat = llEuler2Rot( eul );

オイラー表記に対抗して(?)もうひとつ回転の表現方法があります。
それは回転軸の方向(x,y,z)と回転角度θを指定してやる方法で、3回必要だった計算が一回で済むようになります。そのため、LSLの内部ではこちらの方法が用いられています。

オイラー表記からの変換は、<α,0,0>などの場合には非常に簡単です。しかし<α,β,γ>などの変換はそう簡単にはいきません。

<α,0,0>   → 回転軸(1,0,0)・回転角度α
<0,β,0>   → 回転軸(0,1,0)・回転角度β
<0,0,γ>   → 回転軸(0,0,1)・回転角度γ
<α,β,γ> → 回転軸(?,?,?)・回転角度?

もちろん実際には変換する複雑な計算式があって、計算が得意な彼らはいとも簡単にやってのけます。

ところで突然ですが、この後者の表現方法をつかうために四元数というものを考えます。スクリプト中のquatというのはquaternion(四元数)のことです。回転はすべて四元数で表されます。細かい話はおいといて、数字が(x,y,z,s)と4つ並んだものが四元数です。

※ここでrotation(回転)という言葉は、変数の型の一種類という意味も持つようになります。
変数の型がvector(ベクトル)である、というときその変数は(x,y,z)の3つの値で表されるのと同様に、変数の型がrotation(回転)であるというときは、その変数は(x,y,z,s)の4つの値で表されます。

四元数は物理系の人ならば、特殊相対性理論で見かけたことがあると思います。最近は工学にも利用されているようです。四元数に関しては機会があれば詳しく説明するとして、兎に角llEuler2Rotという関数はこの変換を行っています。

 

■llSetRot( quat );

そして最後にllSetRotで回転を実行します。回転を実行するというよりは、文字通りプリミティブの"回転"というパラメータをセットするといったほうが正確かもしれません。


ちなみに、4行をまとめて

llSetRot(llEuler2Rot(<0, 0, 45*DEG_TO_RAD>));

という風に書いてもかまいません。
ところでこのままだと、オブジェクトの初期状態に関わらず結果は同じになります。先に述べたように、回転を実行するというよりはパラメータをセットするだけなので、当たり前といえば当たり前です。相対的に角度を変化させたい場合は、llGetRotを用いて現在の回転のパラメータを取り出す必要があります。


vector eul = <0, 0, 45>; //z軸周りに45度回転するというオイラー表記
eul *= DEG_TO_RAD; //とりあえずラジアンに変換
rotation quat = llEuler2Rot( eul ); //オイラー表記を四元数に変換
rotation quat0 = llGetRot();//実行前の回転の状態を取り出す
llSetRot( quat * quat0); //回転の実行

 
4行目でその操作を行っています。取り出される回転の状態も四元数であるため、変数の型はrotationです。
実行前の状態に、実行したい回転を左から掛けることで相対的な回転を行うことができます。なぜ掛け算かということは、たとえば回転行列などを思い出してみるとよいかもしれません。そして、勘のよい方は気がつくと思いますが、この掛け算の順序は逆にすることはできません。

ちなみにこれも一行にまとめることができます。

llSetRot(llEuler2Rot(<0, 0, γ>) * llGetRot());

| | Comments (0) | TrackBack (0)

05/11/2006

LSL101 Chapter6

chapter1/chapter2/chapter3/chapter4/chapter5/chapter6
 


Chapter6:簡単なポーズボールの作り方

ポーズボール?ポーズキューブ?
 
 
以上のことを考慮すれば、有用であろうスクリプト(ポーズボール)を実際に書くことが出来ます。


ポーズボールはセカンドライフにおいてアニメーションを作ろうとすれば必ず必要になります。簡単なものでは、以下の4つのパーツが必要になります。

1) 座る
2) ポーズボールを隠す/表示する
3) アニメーション本体
4) アバターをアニメーションさせる

この簡単なチュートリアルはデフォルトのアニメーションを使ったポーズボールの作成の助けとなるでしょう。

もう一度始めから
新しいスクリプトを作成してください。このスクリプトに戻りましょう:

default
{
    state_entry()
    {
        llSay(0, "Hello, Avatar!");
    }

touch_start(integer total_number)
{
llSay(0, "Touched.");
}
}


次に、ポーズボールが現れたり消えたりする必要があります。これは簡単にできます。llSetLinkAlphaを使えば、触れるだけでオブジェクト全体を消したり出現させたりできます。ここでブーリアンに挑戦してみましょう。

integer hidden = FALSE; // オブジェクトが現れている状態かどうかを記録します

default
{
    state_entry()
    {
        llSitTarget(<0,0,1>,<0,0,0,1>); // ターゲットをプリムの中央から1メートル上にセットします
        llSetSitText("Pose!");
    }

touch_start(integer total_number)
{
if(hidden)
{
hidden = FALSE;
llSetLinkAlpha(LINK_SET,1,ALL_SIDES);
}
else
{
hidden = TRUE;
llSetLinkAlpha(LINK_SET,0,ALL_SIDES);
}
}
}


 
 
素晴らしい!コンパイルして座って見てください。パーミッションが設定されてないという青い警告バーがでるはずです。

パーミッション?一体何のことでしょうか?アクションの中には、まずパーミッションによる承諾を得る必要があるものがあります。ここで例をいくつか見てください。

run_time_permissionsとllRequestPermissionsを使ってポーズボールを完成させましょう。

integer hidden = FALSE; // Stores whether the object is visible

default
{
    state_entry()
    {
        llSitTarget(<0,0,1>,<0,0,0,1>); // Set the target one meter above the ground
        llSetSitText("Pose!");
    }

changed(integer change)
{
if(change & CHANGED_LINK) // If someone has sat on, or "linked," to this prim...
{
key avataronsittarget = llAvatarOnSitTarget();
if( avataronsittarget != NULL_KEY ) //Someone is sitting on the object
{
// Comment out this code:
//llStopAnimation("sit");
//llStartAnimation("dance1");
// Before animating, first check if we have permission to do so:
if ((llGetPermissions() & PERMISSION_TRIGGER_ANIMATION) && llGetPermissionsKey() == avataronsittarget) {
// If we do, we can animate:
llStopAnimation("sit");
llStartAnimation("dance1");
} else {
// If we dont, ask for them:
llRequestPermissions(avataronsittarget, PERMISSION_TRIGGER_ANIMATION);
// We'll animate in the run_time_permissions event, which is triggered
// When the user accepts or declines the permissions request.
}
}
}
}

run_time_permissions(integer perm)
{
if(perm)
{
// Place the code here!
llStopAnimation("sit");
llStartAnimation("stand");
}
}

touch_start(integer total_number)
{
if(hidden)
{
hidden = FALSE;
llSetLinkAlpha(LINK_SET,1,ALL_SIDES);
}
else
{
hidden = TRUE;
llSetLinkAlpha(LINK_SET,0,ALL_SIDES);
}
}
}

 

おめでとう!初めてのスクリプトを完成させLSLスクリプトの世界への最初の一歩を踏み出しました。 
あなたが迷ったときや解決の方法を知りたくなったら、いつでも参考にしてかまいません。
 
 
chapter1/chapter2/chapter3/chapter4/chapter5/chapter6

| | Comments (0)

05/10/2006

LSL101 Chapter5

chapter1/chapter2/chapter3/chapter4/chapter5/chapter6

 
 
Chapter5:主要なパラメータ

Particles and SetText and Spam, Spam, Spam, Eggs, SetText and Spam, Spam Spam and...
 
 


スクリプトによってできる便利なことのひとつに、プリミティブのプロパティを変化させることが出来るということが挙げられます。パラメータのいくつかを簡単に紹介しましょう。

すべての変更されたプロパティは(スクリプトが削除されれても)永久的に保持されるので、使う前にはあなたの作業をコピーして保存するのを忘れないでください!
 
 

Floating Text(テキスト表示)
llSetTextは最も簡単なパラメータです。プリムにfloating textを付け加えることが出来ます。
 
 

Particles and Textures(パーティクルとテクスチャ)
llParticleSystemは、比較的すぐ出会う複雑なシステムのひとつです。幸運にも多くのレジデントがパーティクルシステムの毒沼地帯に突っ込む道から脱出しています。そんな例題はこちら。より効果的なのはこちらです。
llCollisionSpriteはオブジェクトが何かにぶつかったとき(またはぶつかられたとき)のスプライト表示を変更します。
llSetTextureAnimを使えばテクスチャアニメーションをセットできます。
 
 

Sounds(音声)
llLoopSoundはオブジェクト内でサウンドをループさせ続けることができます。
llPlaySoundはオブジェクトを音源としてサウンドを一度だけ再生させることができます。
llTriggerSoundはサウンド再生のトリガーですが、オブジェクトをは関係なしに再生されます。そのため、音声はオブジェクトに追従しません。
CollisionSoundはプリムが何かにぶつかったとき(またはぶつかられたとき)にサウンドを変更します。
 
 

Sit Targets and Camera Stuff(座る位置とカメラ)
llSitTargetでプリムに対して座る位置を変更することができます。
llSetSitTextllSetTouchTextはそれぞれのアクションをパイメーニューから選択したときに表示されるテキストを編集することができます。
さらにプリムに座ったときにカメラがどのように動くかを編集することも出来ます。
 
 

Script-Related Goodies(スクリプト間のやりとり)
llSetRemoteScriptAccessPinllRemoteLoadScriptPinと共に用いられ、オブジェクトにスクリプトを送ることが出来ます。
 
 

Other Primitive Parameters(その他)
llSetPrimitiveParamsにはその他すべての重要なプリミティブの項目が含まれいます。形状、サイズ、外見、位置、角度、台所のシンク、スケールなど・・・
詳しくはこちらです。

 
 
chapter1/chapter2/chapter3/chapter4/chapter5/chapter6

| | Comments (0)

05/09/2006

LSL101 Chapter4

chapter1/chapter2/chapter3/chapter4/chapter5/chapter6
 
 


Chapter 4: ロジック

"What do you mean invalid parameters?! 9,000 gigs of RAM and it can't answer a simple question!" - Earthworm Jim

LSLは頑丈な言語ですが、一度ものの作り方を覚えてしまえば思うように操ることが出来ます!
このセクションでは変数、構文、繰り返しその他便利な機能の使い方と内部での働きを教えることにしましょう。


Everyone that knows C or C++ is dismissed, as LSL resembles that to the letter.


変数の再考

ここで働きをよりよく理解するために、変数について少しおさらいをしましょう。

C++と同様、データを受け取るための変数は左側に書きます。残ったスパムは右へ置いておいてください。例えば:

integer this = 1; // "this"に"1"を格納します
integer two = 2; // Stores "2" into "two"

this = 1 + 2; //  "this"に"1+2"または"3"を格納します
this = two; //  "this"に"two"の値を格納します


典型的に、変数の演算(1+2など)はイベントか関数内部でのみ行われます。あなたがいとも簡単に変数を格納できても、コンパイラが失敗してひっくり返ることもあるでしょう。
このような理由から、state_entryはかなり便利かもしれません。

そのほかにも変数を変化させるために有用な特別なコマンドがいくつがあります。Linden関数に加えて横切ることになるであろう対になるコマンドがあります:


integer i = 0; // Just a quick variable

++i; // Increments (adds one to) the value of i
i++; // Same thing, only it does so after the line of code is executed

--i; // Decrements (removes one from) the value of i
i--; // Same thing, except it happens after.

i += 1; // Shorthand for "i equals i plus one." Very handy.
i -= 1; // "i equals i minus one."
i *= 1; // "i equals i times one."
i /= 1; // "i equals i divided by one."

i = TRUE; // "TRUE" is a constant for 1.
i = FALSE; // "FALSE" is a constant for 0.


イコールとダブル・イコール

あなたはコードのある部分には1つだけイコール(=)が使われているのに対し、他では2回繰り返されている(==)のに気がついたでしょうか。これは意図してやったことです。

単一のイコールは、上記のように値に対して変数を宣言するのに用いられています。ダブル・イコールはある値に対する変数を評価するのに用いられています。一般的には繰り返しやif-else構文の中で用いられます(後述)。

True/FalseとIf/Else構文の記述

IfとelseはLSLの肉とポテトです。

構文を記述する前に、ifをこんな風にはじめてみましょう:


if(TRUE)
{
}


括弧{}と"TRUE(真)"に注意してください。これがあるのには理由があります。If構文は処理される際に、TRUE(1)と評価されるという条件が必要です。もしこの条件が満たされなければ、{}内のコードは完全に無視されます。

LSLではif構文は0よりも大きければどのような値でも可能です。例えば"if(15)"でも内部のコードは動くでしょう。これは一部のコード作成者にとっては注意すべきことです。

if構文は必ずしも後ろの{}を必要としません。時には完全に省略されます。その場合は、コードの次の行が条件節とみなされます。 - つまり、条件が満たされたときのみ走ります。


どうやってその条件を満たせばいいのでしょうか?それにはいろいろな方法があります:


integer one = TRUE;
integer zero = FALSE;

if(!one)
{
// これは決して実行されません。LSLでは!または"not"コマンドは
// 条件を反転させます。"not True"は"False"に等しく、反対に"not False"は"True"に等しくなります。
}
if(!zero)
{
// つまり、ここのコードは走ります。
}

if(one == TRUE)
{
// もし"one"が真であれば、ここでの記述は実行されます。
// ダブル・イコールは、値が一致すれば"真"を返します。
// 一致しなければ"偽"を返します。
}
if(zero == FALSE)
{
// なのでこれも実行されます
}

if(zero < one)
{
// また違った条件分がでてきました。これは"真"です。
// なぜなら"zero"は"one"より小さいからです。
}

key stuff = "Yar";
if(stuff)
{
// 面白いことに、条件としてキーや
// 文字列を与えることもできます。やってみてください!
}


ひとつif構文を置けば、その後に直接else構文を置くことができます。


単純にelseだけの場合、そのelseの前にあるif構文の実行に失敗したときに実行されます。また"else if"として連鎖を作ることも可能です。


例えば:

if(FALSE)
{
}
else if(FALSE)
{
}
else
{
    // ここのコードだけが実行されます。
}


より詳細な情報は、ifElseの項目を参照してください。


AndとOr

同じコマンドに、まったく違う実行。
Same commands, vastly different execution.

単一のanmpersand(&)はバイナリのAND(理論和)です。つまり、現在の変数のビットを評価します。

単一のvertical line(|)はバイナリのORです。この手軽な変数は要求されたビットを反転させます。

2つ並んだ&や|はANDやORの比較です。これらはifや繰り返し構文の中で用いられます。


例:

if(change & CHANGED_LINK)
{
    // If change is greater than zero, and the bits of CHANGED_LINK are on, do stuff.
}

llSetStatus(STATUS_PHANTOM | STATUS_PHYSICS, TRUE);
// Using Phantom + Physics bits to define a status.

if(TRUE && FALSE)
{
// Will never run. Both parts must be TRUE.
}

if(TRUE || FALSE)
{
// Will run, since only one part needs to be TRUE.
}


全くわかりませんか?ここここに挑戦してみてください。

繰り返し

繰り返しにはいくつかの方法があります。これらはほとんどC++からそのまま持ってくることが出来ます。

"while"ループは条件が真である限り走り続けます。ifと同じように、偽であればコードは実行されません。ifと違っている点は、条件が変わらない限り永遠に実行され続けることです。


例えば:

while(TRUE)
{
    // 無限に実行されます。
}

integer i = TRUE;
while(i == TRUE)
{
// 一度だけ実行されます。
i = FALSE;
}


"do-while"ループは基本的に常に一回は実行されるwhileループです。


do{
// 何が何でも実行します
}
while(FALSE);


"for"ループは3つのパラメータを用いて、簡単なイベントの流れを作ります。こんな風に:

integer i;
for(i = 0; i < 10; ++i)
{
    // iは0からスタートします。iが10未満の間繰り返し、それぞれの繰り返しごとにiに1を加えます。
    // ここは10回実行されます。
}


わからなくなった?ここに挑戦してみてください。

値を返す関数

関数の中には値として扱われるものもあります。例えば、 "number = llSin(2);"というのを見ることもあるでしょう。他の関数は値を返しませんが、ある関数は値を返します。これらの関数はまるで値であるかのように扱われます。

ここでどの関数が値を返すのか見ることが出来ます。

グローバル関数

グローバル関数(またはユーザー関数)も作り出すことができます。これらの関数はstateの外のみに作成でき、このような感じです:

float i_am_a_function(integer item)
{
    // Here's what we just defined. This function returns a float value.
    // It also accepts one parameter, which is defined here as "item"
    // "item" will act as if it has been declared, since it can be in the start of a function like this.
    item = 2;

// To call this function in the code, you would write something like "i_am_a_function(1)"

// Because this function returns a value, you MUST include this line:
return 0.0; // Returns a float.
}

State

stateはとても便利です。既にすばらしいチュートリアルがあるので、そちらに行ってみるというのはいかがですか?

演算子の順序

算数やif構文では、あるコマンドは特別な順序で実行されることに注意してください。
















演算子(上にあるものほど先に実行されます) Description
() [] . Parentheses, Square Brackets, Dot Operator
! ~ ++ -- NOT, One's Compliment, Prefix Increment, Prefix Decrement
* / % Multiply, Divide, Modulus
+ - Addition, Subtraction
<< >> Left Shift, Right Shift
< <= > >= Less Than, Less Than Or Equal To, Greater Than, Greater Than or Equal To
== != Comparison Equal, Comparison Not Equal
& Bitwise AND
^ Bitwise XOR
| Bitwise OR
&& Comparison AND
|| Comparison OR
= += -= *= /= %= ++ -- Value functions, Suffix Increment, Suffix Decrement


一般的に、もし演算子の順序がわからないようならたくさんの括弧を使って閉じてしまうのがよいと思われます。


ふー、長かった。そうでもないですか?
 
 
chapter1/chapter2/chapter3/chapter4/chapter5/chapter6


| | Comments (0)

04/20/2006

Chapter 11. Vehicles

LSLにより好みどおりの乗り物を構築し、制御することができます。このチャプたーでは乗り物の動作原理の基本と乗り物を記述するのに使われる命令、そして利用可能なAPIの例題などを紹介していきます。

スクリプトが組み込まれたオブジェクトを動かすにはいくつかの方法があります。1つは"乗り物"に変換することです。この方法は物体をスライドさせたり、ホバリングさせたり、飛ばしたりするのに十分対応できます。利用可能な動作は例えば:

・任意の動作軸の速度と角速度の制御
deflection of linear and angular velocity to preferred axis of motion

・非対称な直線及び角運動の摩擦
asymmetric linear and angular friction

・地面/水上またはあらゆる高さのホバーリング
hovering over terrain/water or at a global height

・方向を変えるときのバンキング(傾き走行)
banking on turns

・加速や方向転換のための直線及び角度方向のモーター
linear and angular motor for push and turning

| | Comments (2) | TrackBack (0)

LSL101 Chapter1

chapter1/chapter2/chapter3/chapter4/chapter5/chapter6

Chapter1:ハロー アバター!

始めに、そこに居たのはPhilip Lindenただ一人だった。
Philipは空っぽのシムを見てみると、
そこには生命や人々がまったく存在せず、
悲しみを感じた。

そこで、Philipは思いついた。
この広大な世界に人々と共に住み、
彼らに世界を変化させる力を与えることにした。
その力はたったひとつの言葉だった。

その言葉は"LSL"、
そしてそれは素晴らしいものだった。

------------------------------------------

LSLはSecond Lifeの神々にとって格好の材料です、たとえあなたがLSLをマスターするのに神になる必要がなくても!
コードを書き始める前に、まずはスクリプトの生成の仕方を知らなければなりません。


仕様では(?)、3つの方法のうちのどれかの方法でスクリプトを生成できます。

1.地面を右クリックし、pie menu(パイのような形をしたメニュー)からcreateを選び、地面を左クリックします。これによってprimが生成されEdit windowが開くはずです。
"More>>"ボタンをクリックします(表示されている場合)。Edit windowの右下の隅にあるはずです。
"Content"タブをクリックし、"New Script..."ボタンをクリックします。
script editor windowが開きます。

2.(1ボタン以上のマウスを使っているPC/Macユーザーであれば)Inventoryのフォルダを右クリックし、"New Script"を選びます。
新しく生成されたスクリプトをWクリックします。
script editor windowが開きます。

3.外部のエディターでスクリプトを生成し、それを上記の方法を用いてSL内にコピー&ペーストします。


これはなんでしょうか?なにかコードがでてきました!

それはきっとこのような感じでしょう:

default
{
    state_entry()
    {
        llSay(0, "Hello, Avatar!");
    }

touch_start(integer total_number)
{
llSay(0, "Touched.");
}
}

落ち着いて!実はみかけよりずっと簡単です!


Default State:

あなたの新しいスクリプトで最初に出てくるのは"default"という言葉です。これは"state"(状態)と呼ばれるものです--"state of being"(現在の状態)なども呼ばれます。すべてのLSLスクリプトは、うまいことに"default"と名前のついたdefault stateと、"default"内に動作するためのコードを含んでいなければなりません。スクリプトにはいくつものstateを含めることが出来ますが、それについては後で述べます。

default stateは最初に走らせるコードを含んでいます。"default"はコンパイラ(あなたのコードをSL内で動作できるものに変換するプログラム)に"いいかみんな、ここからはじまるよ"と知らせます。defaultに続く次の行には、opne brace({)があるはずです。これはコンパイラにこれよりあとの情報はdefaultに含まれているものであると知らせます。defaultのあとの{からまっすぐ下にみていくと、スクリプトの最後の行にdefaultのclosing brace(})が見つかると思います。defaultの閉じ括弧はコンパイラに"defaultのコードはここで終わり"と知らせます。この1セットの{}の間にあるスペースをscopeと呼びます;defaultの開き括弧と閉じ括弧の間にある文章はすべてdefault stateのスコープ(scope)内にある、といいます。

スコープはお互いにネストすることができます(スコープ内部にスコープを含むことが出来ます)。このサンプルでは、defaultのスコープはstate_entryとtouch_startのスコープ両方を含みます。見てのとおり、それぞれのスコープは固有の開き括弧と閉じ括弧を持っています。開き括弧に開かれたすべてのスコープは閉じ括弧で閉じなければいけません。そうしないとスクリプトをセーブしようとしたときに、script edit windowは"Syntax error"と表示します。スコープはまた、コードブロックとも呼ばれます。

とりあえず、ここに3セットの括弧があるのがわかると思います。最初の括弧はdefault stateを開くためにあります。次のセットはstate_entryイベントのために開かれ、一行おいた後直ちに閉じられます。3つ目のセットはtouch_startイベントの後に開かれ、再びすぐに閉じられます。 最後の閉じ括弧はコンパイラに ここまで全部がdefault stateに含まれることを伝えます。

わかりましたか?それほど難しいことではありません!


Eventsとstate_entry:

// <snip>
    state_entry()
    {
        llSay(0, "Hello, Avatar!");
    }
// <snip>

何らかの動作を行う最初の部分は、このようにstate_entryのスコープ内にあります。


state_entryとtouch_startはイベントと呼ばれます。イベントスコープにコードを加えることによって、"イベントハンドラ(event handler)"を生成します(we respond to the event's occurance by adding code to handle it)。Second Life内で起こった出来事によってイベントは発動します(そしてそれらのスコープ内にあるコードが走ります) - 例えば、touch_startイベントは誰かがマウスでオブジェクトをクリックした際に発動します。state_entryイベントはデフォルト状態が入力されると発動します。デフォルト状態はスクリプトがコンパイル(またはリセット)されるとすぐに入力されるので、state_entryのスコープ内にあるコードは一番最初に実行されることになります。覚えておいてください!もしスクリプトが世界に生み出されたオブジェクトであるならば、このようなポップアップを目にするはずです。


Object: Hello, Avatar!


いいえ、このオブジェクトは暗号によって"hi"といっているだけではありません。これはstate_entryスコープ内にあるllSayのステートメント(statement)によって起こっているのです。ステートメントはスクリプトの中で何らかの動作を起こす複数行のテキストです。それぞれのステートメント時通常は1行内におさまり、セミコロン(;)で終わらなければいけません。ステートメントの最後のセミコロンは文章の最後のピリオドみたいなものだち思ってください(そしてコンパイラは、学者風のグラマーな3年生の先生だと思ってください)。


state_entryイベントの中には、llSayではじまるステートメントがあると思います。llSayは関数(function)と呼ばれるタイプのステートメントです。関数は必要な情報を与えるといろいろと面白い動作をします(あなたが与えた情報のことをパラメータ(parameter)と呼びます)。関数はいつもあなたが必要な情報を正確に与えてくれると期待しています。そしてあなたはその情報を関数の括弧内(parenthesis)に与えてやります。関数に情報を与えることを、"関数パラメータを受け渡す(passing the function parameters)"といいます。もし関数が2つ以上の関数をパラメータを必要としているときは、関数は情報の量の変化を待ち受けることが出来ます。。それぞれのパラメータはコンマで区切られます。llSayについてのはまたあとで詳しく説明します。


小文字のL2つで始まる関数はすべて、Linden関数です。これらのコードのそれぞれ部分は、スクリプト作成者に新しいアビリティを提供するためにLindenが作成したものです。実際これらは、あなたのすべてのスクリプトのバックビーンを支えることになるでしょう。


llSay
llSayを詳しくみていきましょう!

// <snip>
    state_entry()
    {
        llSay(0, "Hello, Avatar!");
    }
// <snip>


llSayは20メートルの範囲内にあるオブジェクトやアバターに聞こえるチャンネルに、チャットとしてテキストを表示する関数です。


llSayはあなたに、どのチャンネルにどんなテキストを表示するかという2つの情報を与えられるのを待ち受けています。これらの情報は開いたセミコロンの直前の括弧の中(llSayのあとの(と閉じ括弧))に記述されます。アバターはチャンネル0を使ってチャットを行うので、スクリプトがコンパイル(セーブ)されると "Hello, Avatar!"が画面とチャット履歴の中に表示されます。オブジェクトはチャンネル0以外でもチャットができますが、それらは画面には表示されません。これはオブジェクト間のプレイベートな会話に便利です。

発言するテキストはダブルクオーテーション(")で囲みます。これでコンパイラに"ダブルクオーテーションの中のテキストはすべて文字であると解釈し、ステートメントやイベントやマッシュポテトにしようとしないでください - ただありのまま関数に渡してください"と知らせます。これがダブルクオーテーションの中のテキストと0という番号がリテラル(literals)と呼ばれる所以です。リテラルはコンパイラに文字として解釈させるための情報です。リテラルでないもの(変数)については後で述べることにします。

ステートメントの最後はセミコロン(;)で終わることを覚えていてください!セミコロンを忘れるというミスはたいていのプログラミング言語にありがちなミスのひとつです。

touch_start:
次にくるイベントはtouch_startです。このコードは先に説明したコマンドに非常によく似ています。


touch_start(integer total_number)
{
llSay(0, "Touched.");
}


見覚えがあるはずです!関数のように、このイベントは変数:integer total_numberで始まっています。注意すべき違いは、この値はSecond Lifeそのものがスクリプトに与えるものです!変数がイベントの中で定義されたときは、シムがとったアクションによって与えられます。これは非常に便利です。特にmoney(イベント名)のようなイベントの中では。

この場合、total_numberの定義はそのときにオブジェクトに触れた人の人数になります。これは重要です!この番号は私たちに何人のユーザーが必要かを教えてくれます(?)。
This number lets us know how many users we need for detected functions.

しかし今は、私たちがやっていることはユーザーがオブジェクトをクリックするたびに "Touched"と言わせるということだけです。llSayが以前と同じように現れています:チャンネル0に"Touched"と言う言葉をテキストとして与えています。


おめでとう!あなたは初めてのスクリプトを解読することに成功しました!


chapter1/chapter2/chapter3/chapter4/chapter5/chapter6

| | Comments (4) | TrackBack (0)

04/17/2006

LSL101 Chapter3

chapter1/chapter2/chapter3/chapter4/chapter5/chapter6


Chapter3:変数


新しい開拓地、変数。そこには大航海が・・・ああ、くだらないことはやめよう。

このセクションでは変数について説明します。


変数って何?

変数は高度なプログラミングにおいて便利な、データをおいておくためのメモリスロットです。これらの便利なデバイスによって、データの高速な相互アクセスが可能になるため、博士号を持ってない人でもプログラミングができます。

1つのスクリプトは最大で16k(タイプされたものを含んで16000bit)までなので、あなたはそれを賢く利用しなければいけません。


変数の宣言

変数を使うためには、まずは宣言が必要です。そのためには変数のタイプと名前に注意する必要があります。


// もし変数を宣言しなかった場合、その減数はデフォルト値として使われます。

string name; // "string" は変数のタイプ、 "name"は名前です。 特に指定していないので、""が値になります。
integer num = 1; // 同時に値を宣言することが出来ます。LSLでは必ずしも必要ではありません。


変数には多くのタイプがあります。LSLで現在利用できるのは次のとおりです:

Integer(整数型)

整数型は-2147483648から2147483647までの値をとることが出来る32ビットの変数です。面白いことに、名前の通り整数値しか取ることが出来ません。

小数点以下は四捨五入でなく切り捨てられるので、整数型の演算には注意が必要です。例えば、整数型の計算は次のほうになります:

// 結果は3.5ではなく3になります。
integer test = 7 / 2;


Float(浮動小数点型)

浮動小数点型は32ビットの浮動小数点を持つ変数です。整数型とは違い、この型は精度を犠牲にして整数と同じように小数を格納することができます。

浮動小数点型の演算は小学校を出た人なら誰でも予想できるような振る舞いで実行されます。

Q:そうであれば何故整数型を使うのですか?全部浮動小数点型を使ってはいけないのですか?

A:それは実際の機能とイベントのための必要性と、あなたのスタイルに完全に依存します。

Q:倍精度型はありますか?

A::LSLにはありません。


Vector(ベクトル型)

ベクトル型はX、Y、Zと浮動小数点型の変数がこの順番に3つ並んだものです。

ベクトル型の演算はとても複雑です。助けになるようなものを置いておきます。

ベクトル型のそれぞれの値は、浮動少数型と同様に扱うことが出来ます。例えばこのようになります:


vector this = <0.0,1.0,2.0>;

this.x = 0.0; // The X component.
this.y = 1.0; // The Y component.
this.z = 2.0; // The Z component.

Rotation(回転型)

回転型はX、Y、Z、Sと言う順番に浮動小数点型の変数が4つ並んだものです。

回転は4元数で定義されます。多くのコード作成者にとっては、"お尻が痛い"のと同義です。

とりあえず、知っておくべきことは次のようになります:

- <0,0,0,1>は回転なしと同等です
- もし4元数が苦手であれば、Eulerを試してみてください
- llGetRotllSetRotはあなたの友達です

4元数について学びたいなら、ここによい解説があります。


String(文字列型)

文字列型は "The sky is blue."のような文字の並びです。余計な飾りはありません。

文字列型は容易に足し算や引き算ができます。stringの項目を見てください。


Key(鍵型)

鍵型変数は文字列型の特別なもので、Second Life内のオブジェクト固有の識別子を格納するのに使われます。UUIDとしても知られているように、鍵型変数はちょうど文字列型変数のように機能します。llStartAnimationllLoopSoundllSetTextureのように関数の中には文字列型や鍵型と可換なものもあります。

否定しようとも、すべての観点から鍵型変数は文字列型変数です。


List(リスト)

リストは1つのデータの中に複数の変数を持ちます。上述のすべての変数型を含むことができ、長さも自由です。

しかし他の変数と同様に、利用可能なメモリの量には制限されることを覚えておいてください。

リストはそれだけでもより詳細な議論が必要ですが、とりあえずは基本だけを示しておきます:

- リストに加えるには、単純に"+"や"+="などを使ってください:

list this = [];

this += 1; // 整数"1"をリストに加えます.
this += "2"; // 文字列"2"をリストに加えます

this = [1,"2","x","The sky is blue."]; // またこのような定義もできます
// それぞれの値はコンマで区切られます

- リストに対する操作や中身をみるために、いくつかの関数があります。リストの項目を見てください。


Q:配列はどうですか?

ALSLにスープはありません

Q:syntax errorがでます。何故ですか?

A:リストを正しく定義していること、それぞれの値がコンマで区切られていることを確かめてください。
またある値の個数(72とかそれぐらい)までしか打ち出せないことに注意してください。
リストは何度でもその個数を格納することができますが、ユーザーは手動で一回に入力できる程度しか入力できません(?)
A: Make sure you defined your list properly and used commas between each entry.
Also note that you can only type out lists to a certain number of entries (72 or so).
While lists can store many times this number on their own, a user can manually enter only so many at a time.

より詳細なことは、リストとアペンディックス2を見てください。


ある変数型から異なる変数型への変換

あなたはきっとこう思ってるに違いありません。"どうすれば変数の型をかえられるの?"

変換の方法には2通りあります:

- Implicit typecasting:値はあなたが入力したときに、コンパイラによって解釈されます。例えば、2.0は浮動小数点型と解釈されますが、2とすれば整数型になります。

- Explicit Typecasting:プログラムに直接そのオブジェクトがどの型であるかを指定します。以下のようにします:

// 数字を文字列にしようとしていると思ってください
integer number = 1; // まだまだ簡単!

string not_a_number = (string)number; // これで文字列になりました!

// 実際の値でもこのように出来ます
number = (integer)"12";

// これもすばらしい!
vector vect = (vector)"<1,1,1>";


変数の型を注意深く観察するのを覚えていてください!Second Lifeでは変数の型はとても厄介です。


グローバル変数とローカル変数

LSLの変数には2種類のクラスがあります - ローカルとグローバルです。グローバル変数はスクリプトの全体に渡って存在できます。
一方ローカル変数は、そのスコープ内でしか存在できません。

この2種類を理解するために、また別のスクリプトを見てみましょう:


integer global = 1; // グローバル変数です。スクリプト全域に存在できます。

default
{
state_entry()
{
integer local = 2; // ローカル変数です
}
// この時点でローカル変数はもうメモリ上に存在しません
// ローカル変数は、スコープ内で閉じ括弧があったときに消滅します

// わかりましたか?もう一度。
touch_start(integer total_number)
{
integer test = 3; // こんなかんじです

if(test == 3)
{
llOwnerSay((string)test);
}
// testはまだ存在していますか?
// もちろん!
}
// でもここにはもういない!
}
// グローバル変数はまだ存在しています。もちろんこの場所以降でも!
// 当然、変数の場所はあなたが一番よいと思うところにおくべきです。


時々ローカル変数とグローバル変数が同じ名前を持っているコードを見つけるかもしれません。これは文法上は可能ですが、悪いコードの例であり混乱を避けるためにこのようなコーディングはしないほうがよいでしょう。

スープがない(no soup)っていうのはスープ・ナチっていうTVのキャラクターからきたらしいですよ。スープがめちゃくちゃおいしいので連日満員のレストランで、客の行動がちょっとでも気に入らないと、スープ・ナチが客に向かって"no soup for you!"というそうです。コメディなんだろうか。


chapter1/chapter2/chapter3/chapter4/chapter5/chapter6

| | Comments (1) | TrackBack (0)

LSL101 Chapter2

chapter1/chapter2/chapter3/chapter4/chapter5/chapter6

Chapter2:構文再び


すべてのコード作成者はこの恐ろしい言葉を知りました:

Syntax Error


この言葉はすべての人類とねずみを恐怖に陥れます。数百万の心に恐怖心を抱かせるインターネットの災難です。 そして今、あなたはそれと向き合わなければなりません。


実際にはSecond Lifeでは、あなたが自分が何をやっているかわかていれば、構文エラーは簡単に回避したり修正したりできます。このセクションでは完璧なコードを書くために便利なTipsを提供します。


()と{}は常に閉じられていなければなりません。

家事をしていると思って考えて見ましょう。現実世界では、いったんドアを開ければ閉めることを覚えていなければなりません。夜に何者かが侵入してこないように。{}はある1行のコードが複数行のコードに言及できるようにあります。(本質的には、"このコードはそのコードに属している"といいます)
このコードを参考にしてみましょう:

if (grassIsGreen)
{
   llSay(0, "Woo-hoo!");
}

開き括弧は"ここから閉じ括弧までのコードは、このif-statementに属しています"と述べています。

括弧は通常は(必ずしも必要ではありませんが)それぞれ対になる括弧が、このように左から同じ空白を持つようにします:

{ // Opening brace A
   { // Opening brace B
      { // Opening brace C

      } // Closing brace C
   } // Closing brace B
} // Closing brace A


Second Life LSLエディターは、開き括弧を打った後に勝手に行をそろえてくれます:)
コードの中で()や{}を開けたら閉じることを常に忘れないでください。もし3つの開き括弧があれば、3つの閉じ括弧があるはずです。

より詳細な情報はcodeblockやbraceの項目を見てください。


セミコロンを忘れないで!

もしある1行のコードが{}を必要しないとしても、その行の終わりにはセミコロン(;)が必要であるという危険が潜んでいます。セミコロンを付けてください、戦士よ!


時々{}は省略されます

しかしこれはまれな例外です。もし他の人のコードの中で、括弧が必要なのにない場所を見つけたら、非常に注意深く見てください。なぜそのようになるかという手がかりが見えてくるようになるでしょう。


算数はとても簡単です

LSLでは演算はとても簡単です 基本的な説明
+ 加算
- 引き算/負号
/ 割り算
* 掛け算
% 合同 (外積)
> より大きい
>= 以上
< より小さい
<= 以下
llSin 正弦(サイン)
llCos 余弦(コサイン)
llTan 正接(タンジェント)
llAbs 絶対値
llRound 四捨五入

より詳しいことは、mathの項目を見てください。

他にも演算子はあることに注意してください。. "++" "/="などといった記号にもであうかもしれませんが、後で説明するので気にしないでください。


変数は常に宣言されなければなりません

変数の宣言についてはまだ述べてませんが、コードのどの部分においても変数を使うまえには宣言をしなければなりません。


2つ続きのスラッシュはコメントです

// This is a comment. We use these to leave notes in our code.
// Comments are extremely useful for figuring out what a coder is doing.
// Likewise, they're helpful in letting others know what *you're* doing!

// All you need to write a comment are two slashes before a line.
// You can also "comment out" code if it's not working properly in this manner!


すべてが括弧で囲われている必要はありません。

あとで学ぶように、グローバル変数などは定義するのに括弧はまったく必要ありません!


もし正しくないようなら、尋ねてみてください

他にも間違いがあるようなら、他のコード作成者に尋ねてみてください。Scripting Mentorはあなたを助けるために入手可能です。またフォーラムや私にコンタクトをとることでも助けを得られるでしょう。


chapter1/chapter2/chapter3/chapter4/chapter5/chapter6

| | Comments (0) | TrackBack (0)

04/06/2006

LSL101 Chapter1 続き

state_entryとtouch_startはイベントと呼ばれます。イベントスコープにコードを加えることによって、"イベントハンドラ(event handler)"を生成します(we respond to the event's occurance by adding code to handle it)。Second Life内で起こった出来事によってイベントは発動します(そしてそれらのスコープ内にあるコードが走ります) - 例えば、touch_startイベントは誰かがマウスでオブジェクトをクリックした際に発動します。state_entryイベントはデフォルト状態が入力されると発動します。デフォルト状態はスクリプトがコンパイル(またはリセット)されるとすぐに入力されるので、state_entryのスコープ内にあるコードは一番最初に実行されることになります。覚えておいてください!もしスクリプトが世界に生み出されたオブジェクトであるならば、このようなポップアップを目にするはずです。


Object: Hello, Avatar!


いいえ、このオブジェクトは暗号によって"hi"といっているだけではありません。これはstate_entryスコープ内にあるllSayのステートメント(statement)によって起こっているのです。ステートメントはスクリプトの中で何らかの動作を起こす複数行のテキストです。それぞれのステートメント時通常は1行内におさまり、セミコロン(;)で終わらなければいけません。ステートメントの最後のセミコロンは文章の最後のピリオドみたいなものだち思ってください(そしてコンパイラは、学者風のグラマーな3年生の先生だと思ってください)。


state_entryイベントの中には、llSayではじまるステートメントがあると思います。llSayは関数(function)と呼ばれるタイプのステートメントです。関数は必要な情報を与えるといろいろと面白い動作をします(あなたが与えた情報のことをパラメータ(parameter)と呼びます)。関数はいつもあなたが必要な情報を正確に与えてくれると期待しています。そしてあなたはその情報を関数の括弧内(parenthesis)に与えてやります。関数に情報を与えることを、"関数パラメータを受け渡す(passing the function parameters)"といいます。もし関数が2つ以上の関数をパラメータを必要としているときは、関数は情報の量の変化を待ち受けることが出来ます。。それぞれのパラメータはコンマで区切られます。llSayについてのはまたあとで詳しく説明します。


小文字のL2つで始まる関数はすべて、Linden関数です。これらのコードのそれぞれ部分は、スクリプト作成者に新しいアビリティを提供するためにLindenが作成したものです。実際これらは、あなたのすべてのスクリプトのバックビーンを支えることになるでしょう。


llSay
llSayを詳しくみていきましょう!

//<snip>
  state_entry()
  {
    llSay(0, "Hello, Avatar!");
  }
// <snip>


llSayは20メートルの範囲内にあるオブジェクトやアバターに聞こえるチャンネルに、チャットとしてテキストを表示する関数です。


llSayはあなたに、どのチャンネルにどんなテキストを表示するかという2つの情報を与えられるのを待ち受けています。これらの情報は開いたセミコロンの直前の括弧の中(llSayのあとの(と閉じ括弧))に記述されます。アバターはチャンネル0を使ってチャットを行うので、スクリプトがコンパイル(セーブ)されると "Hello, Avatar!"が画面とチャット履歴の中に表示されます。オブジェクトはチャンネル0以外でもチャットができますが、それらは画面には表示されません。これはオブジェクト間のプレイベートな会話に便利です。

発言するテキストはダブルクオーテーション(")で囲みます。これでコンパイラに"ダブルクオーテーションの中のテキストはすべて文字であると解釈し、ステートメントやイベントやマッシュポテトにしようとしないでください - ただありのまま関数に渡してください"と知らせます。これがダブルクオーテーションの中のテキストと0という番号がリテラル(literals)と呼ばれる所以です。リテラルはコンパイラに文字として解釈させるための情報です。リテラルでないもの(変数)については後で述べることにします。

ステートメントの最後はセミコロン(;)で終わることを覚えていてください!セミコロンを忘れるというミスはたいていのプログラミング言語にありがちなミスのひとつです。

touch_start:
次にくるイベントはtouch_startです。このコードは先に説明したコマンドに非常によく似ています。



touch_start(integer total_number)
{
   llSay(0, "Touched.");
}


見覚えがあるはずです!関数のように、このイベントは変数:integer total_numberで始まっています。注意すべき違いは、この値はSecond Lifeそのものがスクリプトに与えるものです!変数がイベントの中で定義されたときは、シムがとったアクションによって与えられます。これは非常に便利です。特にmoney(イベント名)のようなイベントの中では。

この場合、total_numberの定義はそのときにオブジェクトに触れた人の人数になります。これは重要です!この番号は私たちに何人のユーザーが必要かを教えてくれます(?)。
This number lets us know how many users we need for detected functions.

しかし今は、私たちがやっていることはユーザーがオブジェクトをクリックするたびに "Touched"と言わせるということだけです。llSayが以前と同じように現れています:チャンネル0に"Touched"と言う言葉をテキストとして与えています。


おめでとう!あなたは初めてのスクリプトを解読することに成功しました!

| | Comments (3) | TrackBack (0)

04/05/2006

勉強しようそうしよう

Second Lifeのための言語であるLSL(Linden Script Language)の勉強のため、突然LSL wiki(の一部を)全文翻訳プロジェクト始動。
とりあえずTutorialLSL101から。

誤訳・意訳は仕様です!


--------------------------------------------

Chapter1:ハロー アバター!

始めに、そこに居たのはPhilip Lindenただ一人だった。
Philipは空っぽのシムを見てみると、
そこには生命や人々がまったく存在せず、
悲しみを感じた。

そこで、Philipは思いついた。
この広大な世界に人々と共に住み、
彼らに世界を変化させる力を与えることにした。
その力はたったひとつの言葉だった。

その言葉は"LSL"、
そしてそれは素晴らしいものだった。

------------------------------------------

LSLはSecond Lifeの神々にとって格好の材料です、たとえあなたがLSLをマスターするのに神になる必要がなくても!
コードを書き始める前に、まずはスクリプトの生成の仕方を知らなければなりません。


仕様では(?)、3つの方法のうちのどれかの方法でスクリプトを生成できます。

1.地面を右クリックし、pie menu(パイのような形をしたメニュー)からcreateを選び、地面を左クリックします。これによってprimが生成されEdit windowが開くはずです。
"More>>"ボタンをクリックします(表示されている場合)。Edit windowの右下の隅にあるはずです。
"Content"タブをクリックし、"New Script..."ボタンをクリックします。
script editor windowが開きます。

2.(1ボタン以上のマウスを使っているPC/Macユーザーであれば)Inventoryのフォルダを右クリックし、"New Script"を選びます。
新しく生成されたスクリプトをWクリックします。
script editor windowが開きます。

3.外部のエディターでスクリプトを生成し、それを上記の方法を用いてSL内にコピー&ペーストします。


これはなんでしょうか?なにかコードがでてきました!

それはきっとこのような感じでしょう:

default
{
   state_entry()
   {
     llSay(0, "Hello, Avatar!");
   }

   touch_start(integer total_number)
   {
     llSay(0, "Touched.");
   }
}


落ち着いて!実はみかけよりずっと簡単です!


Default State:

あなたの新しいスクリプトで最初に出てくるのは"default"という言葉です。これは"state"(状態)と呼ばれるものです--"state of being"(現在の状態)なども呼ばれます。すべてのLSLスクリプトは、うまいことに"default"と名前のついたdefault stateと、"default"内に動作するためのコードを含んでいなければなりません。スクリプトにはいくつものstateを含めることが出来ますが、それについては後で述べます。

default stateは最初に走らせるコードを含んでいます。"default"はコンパイラ(あなたのコードをSL内で動作できるものに変換するプログラム)に"いいかみんな、ここからはじまるよ"と知らせます。defaultに続く次の行には、opne brace({)があるはずです。これはコンパイラにこれよりあとの情報はdefaultに含まれているものであると知らせます。defaultのあとの{からまっすぐ下にみていくと、スクリプトの最後の行にdefaultのclosing brace(})が見つかると思います。defaultのclosing braceはコンパイラに"defaultのコードはここで終わり"と知らせます。この1セットの{}の間にあるスペースをscopeと呼びます;defaultのopne braceとclosing braceの間にある文章はすべてdefault stateのscope内にある、といいます。

scopeはお互いにネストすることができます(scope内部にscopeを含むことが出来ます)。このサンプルでは、defaultのscopeはstate_entryとtouch_startのscope両方を含みます。見てのとおり、それぞれのscopeは固有のopening braceと closing braceを持っています。opening braceに開かれたすべてのscopeはclosing braceで閉じなければいけません。そうしないとスクリプトをsaveしようとしたときに、script edit windowは"Syntax error"と表示します。scopeはまた、コードブロックとも呼ばれます。

とりあえず、ここに3セットのbraceがあるのがわかると思います。最初のbraceはdefault stateを開くためにあります。次のセットはstate_entryイベントのために開かれ、一行おいた後直ちに閉じられます。3つ目のセットはtouch_startイベントの後に開かれ、再びすぐに閉じられます。 最後のclosing braceはコンパイラに ここまで全部がdefault stateに含まれることを伝えます。

わかりましたか?それほど難しいことではありません!


Eventsとstate_entry:

//<snip>
   state_entry()
   {
   llSay(0, "Hello, Avatar!");
   }
// <snip>

何らかの動作を行う最初の部分は、このようにstate_entryのscope内にあります。


-------------------------------------


今日はここまで!

| | Comments (2) | TrackBack (0)