BlackSheep-LSL@Wiki 看板を作ろう
※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。


はじめに


第六回~第八回は初級スクリプトの最初の山場でした。
へヴィな内容が続きましたので、今回はちょっと息抜き的に、しかしながら実用的なスクリプトを作ってみたいと思います。

SLで店をやるという人は多いでしょう。
そして商品の販売用や、宣伝のために、看板を作りたいという人もいるかと思います。
綺麗なテクスチャさえ用意すれば、それなりの看板を作ることができますが、この記事は一応スクリプトの勉強ですのでw、スクリプトを使った動きのある看板に挑戦してみましょう。

照明スクリプトをクリアした人にとっては、何ら難しいところは無いスクリプトばかりです。
ちょっとしたスクリプトだけで、いろいろな看板が作れます。
小粒なスクリプトをいくつか書いてみようと思います。

フローティングテキスト



オブジェクトの上に文字を表示するスクリプトです。
あんまり大量にこれがあるとウットオシィのですが、超基本的なスクリプトですので紹介しておきます。

default {
  state_entry(){
    llSetText("Welcome!", <0.0, 1.0, 0.0>, 1.0);
  }
}

このスクリプトはオブジェクトの上に「Welcome!」という文字を緑色で表示します。
ハロー・アバター並に簡単ですので、あんまり説明するところもないですが・・・一応。

llSetText関数


 llSetText(string text, vector color, float alpha)

color色のtextを透明度alphaでオブジェクトの上に表示する関数です。
透明度の値alphaは、0.0-1.0です。
0.0が完全に透明、1.0は完全に不透明です。

表示した文字を消すときは、

 llSetText("", ZERO_VECTOR, 0.0);

これで消えます。

回転看板


しばしば店の屋上に設置されたりしている、ぐるぐる回転する看板です。

vector axis = <0.0, 0.0, 1.0>;
float spinrate = 0.2;
float gain = 1.0; 

default {
  state_entry(){
    llTargetOmega(axis, spinrate, gain);
  }
}

以上でZを軸としてぐるぐる回転するオブジェクトが作れます。
ポイントはllTargetOmega?()関数だけです(^^;

llTargetOmega関数


 llTargetOmega(vector axis, float spinrate, float gain)

この関数はオブジェクトを、axisで示される軸の周りを、毎秒spinrateラジアンの速さで回転させます。
gainはとりあえず1.0の固定値で考えてかまいません。
物理的なオブジェクトを扱うようになるとgainの値が意味を持ってくるのですが、看板など、通常のオブジェクトの場合は1.0を使うのだという理解でOKです。

関数の使い方は特に問題ないでしょう。
ピンとこないのは、どんな数値を指定すると、どんな回転になるのかですね。

まずaxisですが、ここには基本的に「単位ベクトル」を指定します。
高校の数学あたりで出てくる、長さが1のベクトルのことですね。
なんのことやらサッパリという方は、お近くの博識な方にお尋ね下さい(^^;

軸が縦向きなら、横に回転します。
軸を横にしたら、縦回転になりますね。
axisはこの軸の向きを設定する値です。

上記のスクリプトでは、<0.0, 0.0, 1.0>を指定しています。
Z軸は縦方向、1.0ですので上向きです。
この軸の周囲を回転させると、左から右へ、上から見ると逆時計周りの回転になります。
axisを<0.0, 0.0, -1.0>にすると、相変わらず軸は縦方向ですが、下向きです。
このときの回転は、右から左、上から見ると時計回りになります。
<1.0, 0.0, 0.0>や<0.0, 1.0, 0.0>などは、縦回転になります。

spinrateはラジアン/毎秒の回転速度です。
一回転(360度)=2πラジアンですので、π=約3.1415とすると、

spinrate 1回転に要する秒数
6.283 約1秒
3.142 約2秒
2.094 約3秒
1.570 約4秒
1.257 約5秒
0.628 約10秒
0.314 約20秒
0.209 約30秒
0.105 約60秒

設定の際の参考値です。

なお、llTargetOmega?()はSLのサーバーに対する負荷が最も小さい回転処理です。
サーバーはクライアントに対して回転の軸と速度のパラメータを送りつけるだけで、あとの回転は全てクライアント側で計算されるためです。
常に放置する看板のようなオブジェクトを回転させるには最適の手法だと言えるでしょう。

逆説的ですが、回転の処理をクライアント側で行うということは、人によって回転の状態が異なるということです。
同じ場所、同じ時間にAさんとBさんが居て、二人が一緒に回転する看板を見ていたとしても、その回転の角度が同じである保証はありません。
Aさんには40度回転して見えているタイミングに、Bさんには90度回転しているように見えるかもしれません。
ですので、厳密に回転角度をコントロールしたい場合にはllTargetOmega?()は向きません。

また、サーバーの負荷にはなりませんが、時として一番最初の「回せー」という指示がクライアントに届かず、一切回転して見えないというバグもあります。

余談です。
llTargetOmega?()はルートプリムで使ったときとチャイルドプリムで使ったときの動きが異なります。
ルートプリム(オブジェクトの親プリム)で使うと、オブジェクト全体が回ります。
チャイルドプリムで使うと、そのプリムだけが回転して見えます。
これを組み合わせて使うと面白い効果を得ることができますが、親子の軸を考慮して動かす必要があり、なかなかに複雑ですので、いずれ機会があるときにまた詳細に解説します。

アニメーション看板


看板のテクスチャをパラパラ漫画のようにアニメーションさせることができます。
アニメーション用のテクスチャ(アニメの各コマを並べてつなげた一枚のテクスチャ)を用意する必要があります。

テクスチャをアップロードし、アニメーションさせたいオブジェクトに貼り付けたら、以下のようなスクリプトで動き出します。

default {
  state_entry(){
    llSetTextureAnim(ANIM_ON | LOOP, ALL_SIDES,4,4,0,0,4.0);
  }
}

用意したテクスチャに応じて、パラメータは変える必要があります。

llSetTextureAnim関数


 llSetTextureAnim(integer mode, integer side,
   integer x_frames, integer y_frames, float start, float length, float rate);

引数がいっぱいありますが、まあ、難しくはありません。

  • integer mode

まず最初の引数modeですが、パラパラ漫画のようにアニメーションさせるには、ANIM_ONという値を設定します。
それだけだと一度だけしか再生されないので、LOOPという値も指定します。
ANIM_ONとLOOPを、|でつなぐことで、ANIM_ONでLOOPなモードになります。
「ANIM_ON, LOOP」ではありませんので注意しましょう。

ここには他に、
 REVERSE・・・アニメを逆再生させる
 PING_PONG・・・最後まで再生したら逆再生し、先頭まで戻る
などが指定できます。

例えば、パラパラアニメを逆回しで繰り返し再生するには、
ANIM_ON | LOOP | REVERSE
のように指定します。

再生、逆再生、再生、逆再生・・・と繰り返したいときは、
ANIM_ON | LOOP | PING_PONG
このようになります。

  • integer side

primのどの面のテクスチャをアニメーションさせるかを指定します。
全面をアニメーションさせるときは「ALL_SIDES」という値を指定すればよいのですが、特定の面だけにしたい場合は以下のような値をセットします。

以下はあまり妙な形の看板は作らないに違いない(きっとそうだ、そうかもしれない)という独断に基づき、立方体の場合のみです。
なお立方体でも、穴を開けたりパスカットした場合は数値が違ってきますので注意して下さい!

数値
上面 0
-Y方向の面 1
+X方向の面 2
+Y方向の面 3
-X方向の面 4
下面 5

  • integer x_frames, integer y_frames

アニメーションのコマの分割数です。
x_framesはテクスチャの横方向に何コマ並んでるか、y_framesは縦方向に何コマあるかです。
例で示したスクリプトでは、「4,4」にしてますので、横4コマ、縦4コマの合計16コマのアニメーションということですね。
実習する際には自分のテクスチャに合わせて数字を変えてください。

  • float start

スタートのコマが何番目のコマなのかを指定します。
先頭は0コマ目です。
通常0ですよね・・・多分。

  • float length

何コマ目まで再生するかです。
0を指定すると全コマ再生になります。

  • float rate

再生スピードです。
一秒間に何コマアニメーションさせるかを指定します。
例えば4.0であれば、一秒間に4コマの速度で再生されます。

このllSetTextureAnim?()関数も、llTargetOmega?()関数と同様に、クライアント側で実行される処理です。
従ってサーバーの負荷は低めです。
また、見る人によって何コマ目が再生されているかは異なる可能性があります。

スクリプト自体は非常に簡単ですので、手軽でかつ低負荷に、目を引く看板を作ることができますが、おそらく一番手間なのはアニメーション用のテクスチャの準備でしょう。
Second Life Wiki JPのフォーラムにて、便利そうなツールが紹介されていましたので載せておきます。
GIFアニメをSLのパラパラアニメ用テクスチャに変換してくれるWebツールです。


使い方:
1.お好みのGIFアニメを用意し、ソースファイルとして選択します。
2.秒間何コマ再生するのか数字を入力します(デフォルト8コマになっているようです)
3.「Prosess」ボタンを押します。

するとtgaイメージが作成され、ダウンロードできますので、それをSLにアップロードしhて使用します。
スクリプトのソースコードも自動的に作ってくれるという親切設計ですw

またしても余談です。
llSetTextureAnim?()関数は、パラパラアニメ以外にもテクスチャを使ったアニメーションが可能です。
  • ROTATE・・・テクスチャを回転させるモード
  • SCALE・・・テクスチャを拡大・縮小させるモード
  • SMOOTH・・・テクスチャをスクロールさせるモード
これらのモードを使う際には、startやlengthの引数の意味が異なってきます。

地図看板


タッチすると、お店の場所をMAP上に表示してくれるような看板です。

string simname="adder";
vector pos=<104.0, 210.0, 0.0>;

default {
  state_entry(){
    llSetText("Touch to open map.", <0.0, 1.0, 0.0>, 1.0);
    llSetTouchText("map");
  }

  touch_start(integer detected){
    llMapDestination(simname, pos, ZERO_VECTOR);
  }
}

このスクリプトは私の店をMAP上に表示しますw
難しいところは特にないはずです。
初めての関数だけ説明しておきましょう。

llSetTouchText関数


 llSetTouchText(string text)

オブジェクトを右クリックしたときに表示される「touch」の項目を、指定した文字列に変更する関数です。
ここでは、「touch」の変わりに「map」が表示されるようにしています。

llMapDestination関数


 llMapDestination(string sim_name, vector position, vector lookat)

指定したSIMの特定座標をMAP上で示す関数です。
引数が三つありますが、簡単です。

  • string sim_name

表示するSIM名です。

  • vector position

表示する座標です。

  • vector lookat

この引数は現在のバージョンでは使われていません。
将来的には実装される予定らしいですが・・・。
名前からするとテレポートしたときの視線の方向(アバターの向き)でしょうか。

なおllMapDestination()関数を見て、
「おや?」
と思った人は鋭いですね。

何が「おや?」なのかと言うと、この関数には「誰に対してマップを提示するか」の引数が存在しない点です。
マップを表示する相手のUUIDを指定する引数あたりがあっても良さそうなものですよね。
それが無いので、
「これは一体誰に対してMAPを表示するのだろう・・・?」
と疑問を持った人もいることでしょう。

結論を言うと、この関数はアタッチメント・オブジェクトの中か、タッチイベントでしか使えません。
アタッチメントの場合は、MAPはアタッチしている人に対して表示されます。
タッチイベントの場合は、タッチした人に対して表示されます。

なぜこのような制限があるかというと、おそらくスパム対策でしょう。
UUIDでMAPを表示する相手を指定できるとすると、近くに来た人に片っ端からMAPを出すようなスクリプトが組めてしまいます。
そんなものがあったらウットオシイ以外の何者でもありませんね(^^;

ランドマーク看板


地図看板と似ていますが、こちらはランドマークを配布する看板です。
MAPの表示は一箇所しかできませんので、複数お店を持っている人などはランドマークを渡すことで全ての店の位置を相手に伝えることができます。

あまりスマートなスクリプトではありませんが、こんな感じのコードで実現可能です。

list lmlist=[
  "shop1",
  "shop2",
  "shop3"
]; 

default {
  state_entry(){
    llSetText("Touch for getting a landmarks.", <0.0, 1.0, 0.0>, 1.0);
    llSetTouchText("landmarks");
  } 

  touch_start(integer detected){
    llSetText("Please wait ...", <1.0, 0.0, 0.0>, 1.0);
    llGiveInventoryList(llDetectedKey(0), "My shop list", lmlist);
    llSetText("Touch for getting a landmarks.", <0.0, 1.0, 0.0>, 1.0);
  }
}

list型の変数lmlistには、渡したいランドマークの名前を羅列します。
ここに書いたランドマークはオブジェクトのコンテンツ(オブジェクト・インベントリ)の中に入っていなければなりません。
コンテンツにないものを書くとエラーになりますので注意して下さい。

ランドマークが増えた際には、コンテンツにランドマークを放り込むのと同時に、このlmlistに名前を追加する必要があります(このへんがスマートでないw)。

タッチイベントで処理されるllGiveInventoryList()関数は、コンテンツの中から複数のアイテムをアバターに渡す命令です。

llGiveInventoryList関数


 llGiveInventoryList(key destination, string category, list inventory)

  • key destination

渡す相手のUUIDです。
例示したスクリプトではllDetectedKey(0)を渡しています。
これはたびたび登場してますが「タッチした人のUUID」でしたね。

  • string category

アイテムを渡したとき、ここに設定した名前のフォルダが相手のインベントリに作成されます。
例では「My shop list」という名前のフォルダが作られます。
Myって誰だよ・・・という突っ込みは大歓迎ですw
実際に使う際にはわかりやすい名前をつけましょう。

  • list inventory

渡すアイテムのリストです。
さきほども書きましたが、コンテンツに存在しないものがあるとエラーになります。

llGiveInventoryList()の前後でllSetText?()を使っているのは、処理に少々時間がかかるためです。
通常、llGiveInventoryList()は3秒かかります。
ですので、まずフローティングテキストを"Please wait ..."(ちょっち待ってね)と変更し、ランドマークを渡し終わったら、もとのテキストに戻しています。

まとめ


以上、5つのスクリプトを紹介しました。
これらは組み合わせて使うことももちろん可能です。

看板用ということで書きましたが、llSetText?()やllSetTouchText?()などは様々な用途に使える基本的な関数です。
また、llGiveInventoryList()はベンダーを作る際にも役に立ちます。
llTargetOmega?()やllSetTextureAnim?()は、アタッチメントに組み込んでも面白い効果が出せます。

工夫次第で使いどころがあると思いますので、ぜひ応用してみて下さい。

さて。
看板が出来たので、今度はアイテムを販売する仕組みについても見たいところです。
土日はお休みしますので次回は来週月曜日、ベンダーのスクリプトを作ってみることにしましょう。

ではまた来週~w

名前:
コメント: