ソラマメブログ

2007年04月13日

看板を作ろう(初級スクリプト第九回)

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

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

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

看板を作ろう(初級スクリプト第九回)

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


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


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

  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(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とすると、
spinrate1回転に要する秒数
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(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ツールです。

SL anim creator

使い方:
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(string text)

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

  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(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


同じカテゴリー(初級スクリプト)の記事画像
衝突判定(スクリプト初級第二十三回)
カメラ制御(スクリプト初級第二十二回)
センサーを使おう(スクリプト初級第二十回)
HUDを作ろう(スクリプト初級第十六回)
prim間通信(スクリプト初級第十五回)
アニメさせよう(スクリプト初級第十三回)
同じカテゴリー(初級スクリプト)の記事
 衝突判定(スクリプト初級第二十三回) (2007-05-08 12:15)
 カメラ制御(スクリプト初級第二十二回) (2007-05-07 14:36)
 デモ商品を作ろう(スクリプト初級第二十一回) (2007-05-02 12:15)
 センサーを使おう(スクリプト初級第二十回) (2007-05-01 12:15)
 ステートのこと(スクリプト初級第十九回) (2007-04-27 12:15)
 rez!(スクリプト初級第十八回) (2007-04-26 12:15)
この記事へのトラックバック
今度はテクスチャーで1プリムのカーテンを作りました。 前回のスライドする窓やカーテンと異なり、今回は小窓につけるだけなので、プリム節約もかねテクスチャーの変更でカーテンが開...
1プリムカーテン(テクスチャー)【Konp KobaのSecond Life 雑記帳】at 2007年05月10日 02:21
 
Kichijoji SIM ハモニカ横丁「は21」に決まった rinsui SL+Making Shopの開店に向け、まづはカンバンと
Shop前道路設置用の照明付回転カンバンを作り申してMaking【Rinsui SL+ Making Blog】at 2007年07月29日 00:23
金曜日はRLのアクシデントでInできず、土曜日はその余波でInできず、日曜日はさらにその余波で風邪ひいたっぽくて頭痛がするのでInせず。で、3日……ん?4日ぶりか~。
そのせいだか何...
TPチラシとか金網とか【SL SCRATCH】at 2007年12月17日 19:34
この記事へのコメント
いつもいつもすばらしい情報ありがとうございます!
初心者の私にとっては大変、有益です。

こうやって表示させてたんですねぇ・・・
いつもどうやってるんだろう?と疑問でした。
Posted by 5号 at 2007年04月13日 14:26
すぐに役に立つスクリプト満載に感謝です。
アニメーション看板がそんなに簡単にできるとは意外でした。
Posted by Tak Nishi at 2007年04月13日 16:21
スクリプト講座、第一回から全部拝見させていただきました。
いままでぼやーっとしか見えなかったLSLが、ぼんやりと見えてくるくらいになりました。
大変な労力だと思いますが、本当にありがとうございます。
感謝の言葉を述べたくてコメント欄を汚してしまいました。
今後とも楽しみにしております。
Posted by 米王 at 2007年04月13日 16:35
>5号さん

疑問を解消する手がかりになって良かったです。
今後もなるべく役に立つような記事を心がけますね。

>Tak Nishiさん

llTargetOmega()もそうですが、llSetTextureAnim()はクライアント側で処理させることで、低負荷かつ動きのあるものが作れる良い関数だと思います(^^

>米王さん

コメント汚しなどとはとんでもない。
感謝の言葉は一番の励みになります(^^
少しでもlsl理解の手助けになれば嬉しく思います。
Posted by Miz at 2007年04月13日 17:13
こんばんは(^-^)この看板スクリの英語表記を漢字に変換することはできますでしょうか?
Posted by すみ at 2007年05月18日 19:13
>すみさん

できることはできるのですが・・・少々小細工が必要になります。
当blogの「lslで日本語を使う」の記事(http://miz.slmame.com/e1486.html)にやり方をまとめてありますので、参考にしてみてください。
Posted by Miz at 2007年05月19日 23:20
はじめまして。

いつもこちらのブログで勉強させていただいています。ありがとうございます。
地図看板のスクリプトをコピーペーストして使おうと思って試した所、syntaxエラーが出ます。

いろいろい試行錯誤して、最後に気づいたのが } が最後に1個足りないようです。私も初心者でずいぶん悩んだんですが、きっとこのページを今後参考にされる方もいると思うので、コメント残しておきます。

もしかしたら最後のランドマーク看板のスクリプトもそうかもしれません。

初心者ゆえ間違ってたらすいません。
Posted by kinnme at 2007年05月25日 22:48
>kinnmeさん

ご指摘の通り、最後の部分、defaultステートの閉じカッコ}が抜けておりました。
さっそく本文のほう修正しましたが、大変失礼しました・・・。

ご指摘ありがとうございます。
Posted by Miz at 2007年05月26日 20:28
ピンとこないのは、どんな数値を指定すると、どんな回転になるのかですね
Posted by Nike jordan 15 shoes at 2011年04月20日 18:57
 
<ご注意>
書き込まれた内容は公開され、ブログの持ち主だけが削除できます。