Adsense

2008年12月26日金曜日

[LSL] 複数の文字列を一気に置き換えたい

スクリプト カテゴリに登録しているわりに最近スクリプトの話題が少ないので、、、(回転と位置のお話の続きはそのうち、、、でも、他の方の素晴らしい記事が最近あがっているので、、、ちょっとお休みかも)

笑い話に近いのですが、、、

よくエディタとかで「置換」または「すべて置換」というメニューで、ある文字列を違う文字列に置き換えることありますよね。それを LSL でやりたい、と思いました。それも複数の文字列をそれぞれ違うものに一気に置き換えたかったのです。

検索したら、lslwiki のライブラリに Sample スクリプトがあり、また、ちょっと考えると、置き換えたいストリングの長さを取得 (llStringLength) して、置き換えたい文字列のパターンでその文字がある位置を特定 (llSubStringIndex) して、置き換えたい文字列を削除 (llDeleteSubString) (もしくはその部分をさけて)して、そこに置き換えるべき文字列をいれ、原文に戻し、また、同じ処理を繰り返し、置き換えたい文字列がなくなることを意味する llSubStringIndex の戻り値が -1 になるまで行う、、というようなスクリプトになると考えました。

そこで lslwiki のサンプルを元に書いたのが、、、こんな感じです。(普通はユーザー関数にするのでこんなことしませんが、タッチすると確認できるようにしてみました。) A を 1 に、B を 2 に、C を 3 に、、、というように E まで置き換えます。

string text = "このようなD長いA文字列をBある文字がEきたらC分解してAリストにCいれます";
list rs_checkList = ["A", "B", "C", "D", "E"];
list rs_replaceList = ["1", "2", "3", "4", "5"];

default{
    touch_start(integer total_number){
        llResetTime();
        string source = text;
        integer i = 0;
        integer max = llGetListLength(rs_checkList);
        string p = "";
        string r = "";
        integer len = 0;
        integer pos = -1;
        for (; i<max; ++i){
            p = llList2String(rs_checkList, i);
            r = llList2String(rs_replaceList, i);
            len = llStringLength(p);
            while (llSubStringIndex(source,p) > -1) {
                 pos = llSubStringIndex(source, p);
                 if (llStringLength(source) == len) {
                       source = r;
                 } else if (pos == 0) {
                       source = r+llGetSubString(source, pos+len, -1);
                 } else if (pos == llStringLength(source) - len) {
                       source = llGetSubString(source, 0, pos-1) + r;
                 } else {
                       source = llGetSubString(source, 0, pos-1) + r + llGetSubString(source, pos+len, -1);
                 }
             }
         }
         llSay(0,text);
         llSay(0,source);
         llSay(0,(string)llGetTime());
     }
}

でも、これらの処理が変数の宣言を除くと、たった2行程度で終わる、、、のを知って愕然としました。(笑

llParseString2List / llParseStringKeepNulls で文字列分解

ポイントは llParseString2List や llParseStringKeepNulls を使って、指定文字列で List に分解して、llDumpList2String のセパレータに置き換えたい文字をいれて、分解された List をつなげることを繰り返す、という方法です。
string text = "このようなD長いA文字列をBある文字がEきたらC分解してDリストにCいれます";
list rs_checkList = ["A", "B", "C", "D", "E"];
list rs_replaceList = ["1", "2", "3", "4", "5"];
default{
    touch_start(integer total_number)    {
        llResetTime();
        string source = text;
        list sourceList = [];
        integer num = llGetListLength(rs_checkList);
        integer i = 0;
        for(;i<num;++i){
            sourceList = llParseStringKeepNulls(source, llList2List(rs_checkList, i, i), []);
            source = llDumpList2String(sourceList, llList2String(rs_replaceList, i));
        }
        llSay(0,text);
        llSay(0,source);
        llSay(0,(string)llGetTime());
    }
}
み、、、短い、、、(@@
気を取り直して、llParseStiring2List や llParseStringKeepNulls と文字列、置き換え、string, replace などで検索すると、文字列の置き換えで皆さんあたりまえのようにやられていることを発見、、、。
処理時間もあきらかに短くなります。半分以下ですね。
気がついてよかった、、、と思わされた一件でした。

2008年12月24日水曜日

あ、、、入賞してしまったり・・・

入賞しちゃった・・・・

入賞作品発表★BlackChiristmasSSコンテスト by Stone Age Entertainment

まさかコメントがそのまま載るとは思いませんでした。(笑
500L$ ゲットです!ダンス アニメーション購入資金ですね。
T さんのパーティクル(ぜんぜん伏字の意味ないし、、)、R ちゃんの豊富な情報のおかげです。

この R ちゃん情報はshige さんが自分のお店を紹介されたときに教えてくれたそうです。

2008年12月22日月曜日

[MLDU] 保存できるアニメーションの数

今日 22 日は予定通りなら Studio4D さんの新作ダンス アニメーションが発売される日
このところ精力的にリリースされている Studio4D さんには感謝です。
先日は Sine Wave も新作アニメーションのリリースがありました。種類、数ともに豊富な Sine Wave ですが、個人的に最近リリースされるダンス アニメーションは Sine Wave らしさ、、、というか、あの動きの大きな、華麗な感じのものが少なくなってきているような気がします。とはいえ、、、、買っちゃうんですよね ^^;

Sine Wave New Dances

よく MLDU (Massive Link Dance Unit) をご購入されたお客様から「MLDU にはダンス アニメーションいくつ入るのですかぁ?」と聞かれます。 これ、、、ほんとうに入れられない状態まで試したことがないのですが、少なくとも 200 以上のダンス アニメーションをいれることができます。過去の顛末はこちらから。。。

ASUKA SIM のクラブ雷神で LINZOO さんに聞いてみたら実績としての最大値になるでしょう。いま、、、いくつなんだろ?(笑

私が個人的に使っているのも今日時点で 186 のアニメーションが入っていますから、LINZOO さんところだともしかすると 300 くらいになっているかもしれません。

よって、、、ほぼ、困らない数は入れられますよ~、というのがいつもの回答になります。(笑
あ、あと MLDU はクラブ エルフィンさんのところAccess SIM さんのところ、そのほかいくつかのクラブでお使いいただいております。感謝 m(_ _)m

もともと MLDU はメガダンスフロア、ダンスクラブ向けに作ったので、MLDU にいれた数百のダンスから「お気に入り」をセレクトしてノートカードに書き込み、再生順番、再生秒数(オプション)を指定します。このノートカードを複数持つことで、ダイアログのボタンでダンスセットの切り替えをします。このダンスの指定のほうがスクリプト的にはリストを使うのでシビアですが、これも 40 や 50 くらいなら問題ありません。スクリプトが使える残りメモリーも表示されますが、たぶん 200 とかは余裕でしょう。

当初、個人向けを別に作っていたのですが、仕組み一緒だし、どうせなら同じもので、、、というのが MLDU4 になります。ですので、 HUD モードはどちらかといえば個人、少人数向けでの使用を想定していますし、ダンスボールモードはダンスフロアでの利用を想定していました。
そうそう、個人向け、、、ということでノートカードを作らなくても、MLDU にある全ダンスを順番に踊ることができます。[全ダンス] を選べば、MLDU 内にある全ダンスを楽しむことができます。個人利用はこっちのほうが多いのかな。(ただ、お友達の使い方を見ると、ショップ別とかにダンスをわけて、ノートカードによるダンスセットをつくってますね)

海外製に多いダンス HUD タイプのものは地面に Rez してダンスをいれますよね。MLDU4 ももちろんそうなのですが、上述のように個人用とダンスフロア用を一緒にしたので、地面に Rez するとダンスボールになり、HUD として装着すると HUD のサイズとテクスチャを使うので、Rez して見失うことはありません。

ということで、保存できるダンスアニメーション数など気にせず STUDIO4D の新しいダンスをゲットして、MLDU4 にいれてください^^
MLDU4 は STUDIO4D さんのアニメーションショップで購入できます。まずは 1L$ のお試し版を使ってくださいね~。

2008年12月17日水曜日

X'mas カードにいかが?-ElfYourself-

elfyourself8
GION Project プロデューサーの Summy さんの YouTube のビデオをみて、そういえばこのサービス話題になったかも、、、と思い出して作ってみました(笑
Send your own ElfYourself eCards


おもしろい^^
これはすべて Web 上で作ることができます。また、写真も顔を切り抜く、、、なんて作業せずに、とにかく顔がある写真を使えばすぐに作れます。作って、こうやって貼り付けるだけなら無料(!!)なので試してみてはいかがでしょう?
作り方は以下になります。

1. まずは顔が映っているフォトを用意しておきます。
2. http://elfyourself.jibjab.com/ にいきます。
3. [Upload Photo] をクリックします。
elfyourself1
4. アップロードする画像を選ぶウィンドウがでるので、使用する画像を選びます。
5. [Sacale] を使ってサイズをあわせます。傾きを変えたい場合は [Rotate] のスライダーを動かします。
elfyourself2
6. 顔の周りにあるポイントを動かして、顔の輪郭にあわせます。中の画像をドラッグすると動きますので、顔が中心にくるようにして調整することができますよ。調整しおわったら [Done] を押します。
elfyourself3
7. 他の人の顔もアップできます。で、次にダンスを選びます。今回はディスコを選んでみます^^
elfyourself4
8. 作成された動画を見ることができます。ここで [Download] を選ぶと有料(4.99$) を支払う必要がありますが、[Emial/Embed] だと無料で再利用することができます。
elfyourself5
9. 名前とパスワード、生年月日をいれます。すると、以下の画面になるので [Embed] を選びます。
elfyourself6
10. Embed コードがあるのでそれをコピーします。
elfyourself7
これで準備オッケーです。この Embed コードを貼り付けたのが以下(Sさん、Rさん、無断で使っちゃった、、、許して^^)
Send your own ElfYourself eCards

無料の場合は期限があり、そこで消えることになるので、残したい人は 4.99 ドルでダウンロードする、ということになりますね。
他のダンスなんかも一度画像をアップすると楽しめます!
Send your own ElfYourself eCards

面白いですね~。

2008年12月15日月曜日

スナップショットをブログ感覚で - flickr -

前回の投稿でものすごく綺麗なフォトが flickr にあがってます、、、という紹介をしましたが、そういう使い方じゃなく、ブログ感覚で気軽にスナップショットをあげて、その場所や SLURL なんかを一緒に付記するなんて使い方を最近してます。

PC の PrintScreen キーで SS (Screen Shot : スクリーンショット) 撮って、フォトショとかで切り取って png や jpeg で保存して、そこからアップロードって、、めんどくさいと思っている人にはいい方法かもしれません。flickr にさえあげておけば、slmame みたいなブログでもその画像を再利用できますから。

こんな感じで。(ただいま INSOLENCE で恒例の X'mas プレゼント中~です)
3106745883_fab0a74fe2

ですが、、、あいかわらず、flickr は何がどこにあるのかわかりづらく・・・(笑

まず、flickr のアカウント、、、無料なのでとってみましょう。アカウントの作り方はこのあたり、、を参考に
アカウントをもっていらっしゃるのであれば、自分の Home ページのメニュータブの [You] をクリックして展開し、[Your Account] をクリックします。

flickr1

すると、あなたのアカウント情報が表示されます。
アカウント情報の [Email] をクリックします。
flickr2
すると、flickr に登録している email アドレスと一緒に [Your Flickr upload email] というセクションがあり、そこに email アドレスが表示されています。このアドレスに画像を送ることで flickr に登録される仕組みになっています。
flickr3
このアドレスを書きとめておいて、次は Second Life からの操作となります。
Second Life Viewer でのスナップショットの撮り方ですが、通常は [ファイル] - [Take Snapshot(日本語だとスナップショットを撮る?)] ですが、そこに書かれているショートカットの [Ctrl+Shift+S] を覚えると楽です。これを押すと [SnapShot Previe] ウィンドウが開きます。
flickr4
ポイントは [Send via email] (ごめんなさい、英語で、、)が選ばれていることと、[Size] を好みのものに調整していくことでしょう。あと、取り直しは何度でもききますから、良いショットを撮って [Send] ボタンを押します。
すると、スナップショット送信用のウィンドウが開くので、場所の情報や SLURL などをコピーして、本文のところに貼り付けます。残念なのは日本語は通らないようなので注意してください。これは flickr の問題ではなく Linden の問題です、、、。
あと、送信先の email アドレスは、さきほど flickr で書き留めておいた email アドレスになりますね。
flickr5s
これで [Send] で flickr に送信されます。意外にこの登録処理は早くて、flickr サイトの自分の photostream にいくと、すでに登録されていることが確認できます。この時、画像つき email には Linden のロゴも張り付いているのでこれを削除します。
flickr6
これで画像登録終了です。
これ、ブログよりお気軽な感じで記録を残せるのでお勧めです。
あとは、Linden がメールとかエンコードとか、、、ちゃんと対応する気になってくれると日本語が、、、(お友達の話だと、結構前からリクエストがあがっているようなのですが、、、)

2008年12月13日土曜日

Beautiful Photos! - flickr -

セカンドライフでの写真といえばお友達の bark Aabye さんを思い出すのですが(って、bark さん、NHK で紹介されていたのね、、、知らなかった)、以前にも紹介したように flickr にはいろいろなグループ、個人がスナップショットから芸術性の高いものまで投稿されています。

画像ありました~」(Second Life Art グループを紹介)
SL 写真共有 flickr(1)」~「SL 写真共有 flickr(4)」 (flickr への登録方法を紹介)

最近、SL-Babes というサイトの存在を知って、そこの Photo を見ることが多いのですが、このサイト、要は flickr に投稿された画像から(たぶん、、、サイト所有者の個人的な好み?(笑))センスのよい photo を紹介している、、、ということみたいですね。 ただ、flickr に SL-Babes.com というグループがあるので、参加者それぞれが自分の画像をこのグループに投稿して、そこから選んでいるような気がします。(*1) flickr には本当にたくさんの人たちが画像投稿しているので、このようなサイト、グループは素敵な画像を探すのに重宝するかもしれません。

flickr の bark さんの flickr photostream も大好きなのですが、この方の photostream はタメ息が、、、、

Dee Dee Deepdene's photostream


bark さんは画像加工しないというポリシーのもとで素敵な photo をアップしてくれますが、この方は2007年の12月くらいの初期の作品から順を追ってみると、だんだん画像加工やアングル、ポーズ、オリジナル撮影時の陰影の使い方などがどんどん上達(な、、なんてことを言える立場じゃないですが)していくのがわかります。最近のもので驚いたのはこれ。画像をクリックすると flickr でオリジナルを見ることができます。

by Dee Dee Deepdene from flickr photostream

すごすぎ、、、

(*1) flickr の SL-Baes.com グループに参加したら、ベストショットを sl-babes.com で公開するのがルール、、、とありました。
(*2) 追記:DeeDee さんの Back To Nature という set もかなりすごいです。flickr スライドショーはこちら。

2008年12月11日木曜日

高画質モードで貼り付け!- YouTube -

[追記 2009年1月] 通常の埋め込みでも動画再生して HQ モードが有効だと埋め込みプレーヤーの右下に [HQ] ボタンが表示されるようになりましたね!
以前、"High Quality な動画を楽しむ" というタイトルで動画の画質が悪かった YouTube に高画質モードができて面白くなってきました~、という投稿をしました。そこでいくつかの動画サービスの埋込みを試して高画質モードの動画の貼り付けをしましたが、YouTube の高画質モードは埋込みには対応してなくて残念だった記憶がありましたが、、、

世の中に探し出す人はいるものです・・・

ソースは My Digital Life というブログの "How to Embed High Quality and Higher Resolution YouTube videos on Blog or Website" という記事です。

で、早速すでに YouTube に投稿してある Yaz さんの曲の Instant Sorrow で PV 風味に(笑 作った動画を試したのが以下。ただ、やっぱりダウンロードする動画のサイズが大きくなるため、再生している動画がカクカクする方は、ピンクのダウンロードバーが最後にいくまで一時停止して待ってから、再生したほうがいいかもしれません。

Instant Sorrow のタイトル、蛍パーティクル、夜空の星・・・たしかに高画質モード!
あと、、、再生したらモノラルになってしまっていた曲が・・・ステレオになってるかも。
この高画質モードでのブログの埋めこみはちょっとしたおまじないを唱えるだけです。設定の仕方は以下になります。

高画質モード埋込みコードのおまじまい

1. YouTube で貼り付けたい動画の [ 埋込み ] をコピーする。歯車アイコンをクリックすると埋めこみプレーヤーの色やサイズも変更できます。

2. コピーしたコードをブログの投稿編集に貼り付ける。ここの slmame だと [デザインモード] にしないで貼り付けですね。

3. 貼り付けたコードは以下のようになっているはずです。最初の <param name.... ></param> の vallue= と、<embed src=...></embed> の中の src= を確認。(青にしているところです)

<object width="500" height="405">
<param name="movie" value="http://www.youtube.com/v/3hIdFNdK64Q&hl=ja&fs=1
&color1=0x3a3a3a&color2=0x999999&border=1"
>
</param>
<param name="allowFullScreen" value="true"></param>
<param name="allowscriptaccess" value="always"></param>
<embed src="http://www.youtube.com/v/3hIdFNdK64Q&hl=ja&fs=1
&color1=0x3a3a3a&color2=0x999999&border=1"

type="application/x-shockwave-flash"
allowscriptaccess="always"
allowfullscreen="true"
width="500"
height="405">
</embed>
</object>

4. 上記の 2つの文字列の最後におまじないである &ap=%2526fmt%3D18 を入れます。以下のようになります。ダブルクォーテーションの内側にいれてください。

<object width="500" height="405">
<param name="movie" value="http://www.youtube.com/v/3hIdFNdK64Q&hl=ja&fs=1
&color1=0x3a3a3a&color2=0x999999&border=1
&ap=%2526fmt%3D18">
</param>
<param name="allowFullScreen" value="true"></param>
<param name="allowscriptaccess" value="always"></param>
<embed src="http://www.youtube.com/v/3hIdFNdK64Q&hl=ja&fs=1
&color1=0x3a3a3a&color2=0x999999&border=1
&ap=%2526fmt%3D18" 
type="application/x-shockwave-flash"
allowscriptaccess="always"
allowfullscreen="true" width="500"
height="405">
</embed>
</object>

5. これで完了です。実際に貼り付けたのが以下です。これも Yaz さんの曲の PARADOX を使った PV 風味なビデオ(笑

このビデオ、YouTube のほうでは 「高画質でみる」 がありません。もともとビットレートを落としたのか、もとの画質そのものがそれほど綺麗ではないから、、、だと思いますが、PARADOX のタイトルなどを比較すると高画質モードの動画が再生されているようです。
この方法を紹介しているブログにはさらに 720P の HD モードの再生方法も紹介しています。
How to Embed and Play 720p HD (High Definition) YouTube Videos
このおまじないをつかっても、720p に対応したものでないと YouTube から叱られますが、もし対応していると、、、、こんな動画になります。

YouTube がどんどんすごくなってきているかも・・・
[追記] あれれ、、、映画「オーストラリア」のトレーラー、、、日本から見られなくなったみたいです。
では、こちらを、、、

[追記] あれれ、、、またまた見られなくなってるし。では、、こちらで ^_^

2008年11月30日日曜日

祇園終宴花霞

1週間前に GION で行われた GION FINAL LIVE 「祇園終宴花霞」 のビデオをつくりました~。
サミーさんのブログにはすでに数名の方のビデオが紹介されていますね。
最初、「洛陽」を使おうと思ったのですが他の方が結構使われていたので GIONISM で作ってみました。



霞、夢 といったイメージで、なんか、夢だったかなぁ、、と思うようなビデオにしてみようといろいろやってみました。
Live ステージのグロウの使い方が素敵だったので、それを活かせれば、、、とちょっとチャレンジもしてみました。
いままで Windows Movie Maker でしたが、はじめて Ulead Video Studio を使ったので、、、まだよく使い方を把握してません(笑
ただ、さすが有料ソフト、エフェクトとかはたくさんあって迷うくらいです。

お楽しみください~。

2008年11月29日土曜日

雷神のド派手ナイト & アンリアル -レンダリング コスト-

club 雷神の「ド派手ダンスナイト」、、、私には無理・・・でした(笑
カメラワークできません^^
で、ちょっとアバターのレンダリング コストをみてみたら。。。

0

一番軽かったのは kenji さんで 500... うーん、kenji さん 200 人分w
こんなことやってたら落ちました・・・

だって、フロアまともにみられない^^

前はもっとサクサク動いていたような気がするんですけど。。。
CPU メーターが振り切っているので、、、これ以上は改善見込めない模様です。
速いパソコン欲しい~。

レンダリング コストについてはこちらを参照してください~。

Linden Official Blog のレンダリング コストの紹介(英語)
wiki.secondlife.com でのレンダリング コストの説明(英語)

レンダリング コストを表示するには、Advanced メニューから [Rendering] - [Info Displays] で [Avatar Rendering Cost] をクリックで、アバターの頭の上にレンダリング コストが表示されます。

簡単にいうと「重い」部類に入ると赤い数字で表示されます。

という私も 2091 で赤数字でしたがw

ま、、ド派手ナイトなのでw

2008年11月28日金曜日

GO! の練習~

この前の GION FINAL の Yaz さんのライブ(サミーさんとこにリンク)でも「皆さ~ん、Go! の練習しましたか~」なんて、Yaz さんが言ってましたが、Yaz さんの supernovasupersonic (通称スパスパ:スーパーノバ スーパーソニック)のナンバーで、みんなで一斉に「GOOOOOO!!!!!!」っていう部分があるんです。はいw

私が前につくった Steam Glider のビデオでもスパスパを使わせていただきましたが、、、なんといってもビデオ編集ソフトは Windows 付属のムービーメーカー(^ ^;, ですし、使っているパソコンはノート PC だし、あ、あと、、、まだまだこの動画編集・構成・撮影のやり方なんて自己流で勉強中なので、、、(センスが無理かも、、、ね、、、と落ち込む日々も多々、、、でも、SL がくれた楽しい趣味です) うまく、GOOOOO!!!!! の部分の効果が出せなかったんですよね。。。

いあ、LINちゃん、ほんとすごいわ。



あんなにアバターが画面の中にいて、パーティクルがたくさんでたら、、、私の PC 確実に 3FPS で止まります。(笑
LIN ちゃんから 3D マウスを教えてもらって使っていますが、やっぱりこういう撮影には必須ですね~。
軽量化された新しい 3D マウス、、、でてたんですね!)
と、、、いっても、私の場合は人数が多かったりすると「カ、、カックン!」になるので、、、(だからソロのダンスのシーンが多いという話も、、、あるんです、、、ナル度が高いせいではありませ・・ん?)

今日の雷神のテーマは「ド派手ダンスナイト」ということらしいので、、、、って、派手なのあまりない、、、この前の Yaz さんの Live のときも、とあるお友達に「ずいぶん、地味な色の着物ドレスにしたね・・・・」と言われ。うーん(^^;

Yaz さんのスパスパの GO!!!! の練習はこの LIN ちゃんのビデオでどうぞ~(笑

ちなみに、雷神のダンスマシーンは私作成の MLDU です~。(宣伝になっちゃって、すみません・・・)注:ダンスアニメは別ですよ^^;
お試し版とかも OEDO City の Studio4D さんにおいてます。日本語版、英語版両方用意してみました。

で、このビデオ、、、自分の PC / ビューワーで見るより、ちゃんと大人数でシンクロしてる。。。(泣 ><

2008年11月25日火曜日

位置と回転を理解したい その3

「その2」からのつづきで、、、これが「ネジ」です(笑

0

このネジに座ることで Sit の Animation をストップし、ネジ自身を透明にして、ダンスを踊る位置決めをしたかったのです。
前回プリムの正面のお話しを書きましたが、このネジの先端が「正面」になります。
正面の向きは常に西をみているわけではありません。クラブやステージなどによっては当然違います。

このネジを整列させながら Rez して、、、というのもスクリプトでやるのですが、Rez された複数のネジをたとえば 45度時計まわりに回転させたいとか、180度逆向きにさせたい、というのをプリムの編集からまわすのではなく、ダイアログのボタンで簡単にどんどん行いたい、と思ったわけです。

いつものごとく、「そんなの知ってるよ~」の人はスルーしてください(笑

クォータニオンは右からなのか左からなのかそれがポイント

rotation (ローテーション)型のクォータニオンについては「そんなもの~でとりあえず理解しましょう」と前回ご紹介しましたが、クォータニオンがすごい!と思ったのは、このシリーズ(?)で何度もでてくる「グローバル座標軸」(東西、南北、天地)と「ローカル座標軸」(前後、左右、上下)の双方を簡単に扱えることでした。

回転(というより「向き・方向」ですね)を指定する方法も、位置を指定するとき同様にグローバル座標をもとに向きを設定するのか、ローカル座標をもとに向きを設定するのかを考慮しなくてはなりません、、、といっても私も最初はピンとこなかった。。。(笑

まずは「軸を中心とした回転」を考えてみます。
これはプリムの [編集] の [回転] の数字をいじるのと同じことです。
このとき回転する方向はセカンドライフは右手座標系なので「右手の法則」(右ねじの法則)を使います。詳しいことは多くの方が記事にされているのでそちらを参考にしてもらって、、、、これも、見る方向で「時計まわり」なのか「反時計まわり」なのか変わるので注意が必要です。回転させる軸のグローバル座標軸の矢印と同じ方向をみて「時計まわり」になります。
これ、、、混乱するんですよね~

天地の軸である Z 軸を例にとると、おおよそプリムを Rez すると図のような状態で回転を試すことになります。
Z 軸を使って45度 [編集] - [回転] で回してみると、、、反時計まわりにまわっているようにみえますよね。
1
この図をよくみてみると天地の軸である Z 軸は上の方に向かって矢印があります。上記で赤で「回転させる軸のグローバル座標軸の矢印と同じ方向を見る、、、」としたのは、、、つまり、この図の場合は地中からプリムを見上げて時計まわり、ということになるからです。

これは慣れていくしかありませんね。

Z 軸で 45度回したいをベクトルで書こうとすると <0.0, 0.0, 45.0> と書きたくなりますし、[編集] - [回転] でも 45.0 という数値を使いますが、スクリプトではこの角度をラジアンというものにしないと使えません。このあたりの Degree(度) と Radian(ラジアン) の説明もいろいろなところに詳しくあるのでそちらを参照してもらうことにして、LSL で 度からラジアンに変更する方法があるのでそれだけを覚えてしまいます。

<0.0, 0.0, 45.0> * DEG_TO_RAD

これで Z軸45度がラジアンの形にかわります。ラジアンから度に変更するには RAD_TO_DEG という定数をかけてあげればいいのです。

ただ、これだけでは済まないのが回転の難しいところです。
現在の回転(向き)を表す rotation 型の値は llGetRot() でとることができました。
この現在の向きに Z軸を中心とし45度まわった後の「向き」の値を、今度は向きを設定する関数の llSetRot に渡せばよい、、、ということになりますね。
そのため llEuler2Rot という関数を使って <0.0, 0.0, 45.0> のベクトル型の値をラジアンにしてから <x, y, x, s> のローテーション型に変換してあげます。

rotation q = llEuler2Rot(<0.0, 0.0, 45.0>*DEG_TO_RAD);

これで返された q というローテーション型の値を現在の位置に、、、、積算します。加算するのではなくてかけるのです。

rotation newRot = llGetRot()*q;

この newRot は現在の向きからグローバル座標軸の z を中心に 45度 まわしたあとの向きになります。よって、

llSetRot(newRot);

で、向きを変更できました。

クォータニオンがすごいのは、、、上記の例はグローバル座標軸もローカル座標軸も重なっている場合ですが、たとえば図のように傾いていた場合で、プリムの上下軸(つまり傾いているローカル座標軸)を中心に同じく45度まわしたい場合は、

rotation newRot = q * llGetRot();

と、今度は q を左からかけてあげるだけでローカル座標軸を中心とした回転後の向きを算出できるからです。
2
余談ですが、このローカル座標の前後、左右、上下の軸をピッチ (picth)、ロール (roll) 、ヨー (yaw) と呼ぶそうです。(注1)
クォータニオンすごすぎ・・・(笑

ちなみに、、回転する量を <30.0, 45,0, 20,0> と指定した場合、X, Y, Z の順番ではなく、Z軸で20度、Y軸で45度、X軸で30度という順番で回転した結果を表すことに注意です。位置の指定と違って回転の場合はこの順番で結果の向きが変わります。
これで「ネジ」の場合はおおよそやりたいことができるようになったのですが、、、今度は「向きを指定する」といっても角度がわからないときもあるわけ、、、ですよね。
たとえば、近くのアバターの方向を向くとか、太陽の方向を向くとか、、そういう指定もありえます。

だんだん、ネジから離れていくのですが(笑 木漏れ日、太陽光、月光を表現しているプリムも何度も見たことがあるのでちょっと調べようと思ったのですが、、、これがまた(笑
つづく・・・

追記(注1)
誤解がありそうな表現なので、、、ピッチ(前後)の角度、つまり飛行機に乗った状態を想像して、上方に向かったり、下方に向かったりするのは「ピッチ角」を変える、というようですが、軸中心で考えると、ローカル座標軸のY軸をまわしています。同じようにロール(左右)は X 軸を回転させて角度を変えることで右に傾いたり、左に傾いたりします。ピッチの軸が前後のX軸ではないんですよね。

2008年11月22日土曜日

明るすぎるアバターが傍にいたら・・・

本日、GION FINAL イベントとして Yaz Rockett ライブが行われます。
祇園プロデューサーのさみーさんのブログにも書かれていますが、3つのお願いがあります。

・光源(フェースライトなど)使用禁止
・ド派手なパーティク使用禁止
・HUD(スクリプト類)使用禁止

特に、、、時々ものすごく明るいフェースライトをつけているアバターがいますよね。。。(それも、、、1つじゃなくて、3つも4つもつけている、、、つけているアバターは気がついてないかもしれませんが、、、)
WindLight 以前、Windlight 直後はフェースライトがものすごく重要だった(調整が難しい、、、)のですが、最近は SIM にある光源だけでも良い感じになってきましたし、逆に光源がいっぱいある状況だと白浮きすることのほうが多くなりましたね。

今回のようなイベントだと、フロアの光源もきちんと計算されるでしょうし、暗すぎることはないと思うので、フェースライトはぜひ外して参加したいですね。フェースライトをつけたアバターがあつまると光源がいっぱいある状況になってしまいますし。

でも、、、知っているアバターならともかく、知らないアバターに「フェースライトを外してください」って注意するのは勇気がいります。無用なトラブルも起こしたくない、、、というのが本音。会場にもたぶん注意事項としてあるわけだから、もともとあまりそういうことを気にしない、気にしたくないアバターだと、、、めんどうですし。(もちろん、気がつかなかった、、もあるでしょうが)

そういう時は、以前 Torley のビデオで紹介されていた方法で楽しみましょう。
フェースライトだけじゃなくて、アバターから出ているパーティクルに対しても同じように対処できます。


装着しているプリムのライトを消す方法(フェースライトを消す方法)
この方法は自分も含めてアバターに装着されているプリムの光源(ライト)を消します。
以下はフェースライトをつけた状態で、必要になるメニューを出したスクリーンショットです。
0
1. CTRL+ALT+D(Win)で Advanced メニューバーを表示する (Mac は Opt + Ctrl +D)
2. Advanced メニューの [Rendering] をクリックする
3. Rendering メニューの [X Attached Lights] をクリックする。
すると、X が消えた状態になります。それが以下です。
1
フェースライトが消えましたね。(ただし、、、自分のフェースライトは、自分が外さない限り、他の人にとっては光源となっているので、自分のフェースライトを消したい場合は、フェースライトをオフにする、はずすなどをしてくださいね。)
ピアスのパーティクルが上の SS では光っていますが、これも [X Attached Particles] をチェックすることで消すことができます。
これは覚えておきたいうれしい機能ですね。

2008年11月21日金曜日

GION FINAL・・・

ご存知の方も多いでしょうが、Linden の HP でも紹介されている GION(祇園) SIM が予定されていたプロジェクト終了ということで今月にてクローズされるようです。

サミーさんとこのブログ

GION のファイナル ライブは、、、Yaz Rockett です!

Yaz Mania グループには Yaz さんから POP も配られ、、、先週末につくった白虎(Byakko)の高台公園クリスマス仕様にも看板をおいてみました。

GION で行われた前の Yaz さんのライブは 3 回くらい落ちながら、、、なんとか Fraps で動画をとってまとめたのがこれ。


GION のオーナーのサミーさんにも褒められて(w)、動画作成の楽しさを感じさせてくれた貴重な体験でもありました。
また新しいプロジェクト、、、期待したいものですね。

2008年11月19日水曜日

位置と回転を理解したい その2

前回からの続きです。

llSetPosllGetPos を使った 西へ1m, 南へ2m, 上に1m の指定方法は理解できました。
次に、「前に1m, 左に2m, 上に1m」という設定をするには、オブジェクトが向いている方向、つまり「回転」を理解しなくてはなりませんでした。「回転」っていうとクルクルまわっているイメージを持ってしまいますが、どっちを向いているかの「方向」だと置き換えて考える必要がありました。

実は、、プリムの正面っていうのは決まっています。立方体にすると第2面が「顔」になります。(笑
西(W) を向いている方向です。 Rez したときの、東西の矢印の方向です。

0

地図上の東西が X 軸、南北が Y 軸、上下が Z 軸で、それをグローバル座標軸とよびます。グローバル座標軸はどこにいても、どちらを向いていても変わることはありません。一方、前後、左右、上下(ええ、上下も自分が傾いていたら上下軸も傾きますね)はそのときの状態でかわります。この前後、左右、上下を表す軸をローカル座標軸と呼びます。(便宜上、それぞれの軸をグローバル座標軸と同じように、ローカル座標軸の X, Y, Z と呼ばれます。また、この X, Y, Z は右手座標系と呼ばれるものに基づいていて、左手座標系の場合は X, Z, Y となります。他の回転・旋回の記事を参照するときは注意が必要です。。。)

プリムを作成したときはグローバル座標軸とローカル座標軸は一致していますが、プリムが回転してしまったら、グローバル座標軸とローカル座標軸は違うものになりますね。

1

前後に移動する、というのは東西、南北のグローバル座標軸を使うより、ローカル座標軸の X 軸に沿って移動する、左右に移動するというのはローカル座標軸の Y 軸に沿って移動する、と考えれば簡単そうですよね。

llGetRot を使って向いている方向を取得する

向いている方向、つまり、回転を扱うときに私がつまずいたのがローテーション型 (rotation) というものです。現在の回転の値を取得する llGetRot によって返される値は rotation 型と呼ばれる型の値で、ベクトル(ベクター)型とは違います。クォータニオン (quaternion) とも呼ばれるこの型の説明をネット上で探すと、、、<x, y, z, s> の4つの要素からなる4元数で、ジンバルロックが、三角関数が、虚数が(!)、、、と情報は豊富なのですが、数学をちゃんとやっていないと馴染みの薄い難しい単語が続きます。これをひとつひとつ理解しようとすると、かなり大変です。(それはそれで面白いのですけどね。。。)
ですので、x, y, z, s の4つの数字が意味することにあまり深く入らなくてもいいと思います。
実際、rotation 型に入る 4つの数値を直接いじることは私のやりたい範囲では皆無でした。
とりえあず、、、llGetRot で現在の向いている方向が rotation 型で表現できる、と理解して先に進みます。
(あとで、、、角度とローテーションの関係でもう一度でてくることになります)
(なお、wiki.secondlife.com の回転(ローテーション)についての日本語の記事がこちらになります。)

本題に戻って、llGetRot で今向いている方向がとれたら、次は「前」ですよね。LSL では「前」に進むための移動距離をとる関数が用意されていて、それが llRot2Fwd になります。
これが、、、「位置」と「回転」が違うことを意識していないとごちゃごちゃになる壁かもしれません。
いま、llGetRot() で「どの位置か」は関係なく、向いている方向を表す rotation 型の数値を取得できました。向いている方向がわかったらローカル座標軸にそった前方 1m の位置の情報をとりたい、ということですよね。最終的に llSetPos を使って位置を設定したいなら <x, y, z> のグローバル座標軸の位置情報がほしくなります。
そこで llRot2Fwd を使います。llRot2Fwd に現在の向きの情報を llGetRot() で取得して渡すと、Unit Vector (単位ベクトル)という値を返します。

vector fwdVec = llRot2Fwd(llGetRot());

<x, y, z> のベクトル型のデータを fwdVec にもらっていますが、これは「位置」をあらわす <x, y, z> ではありません。
Unit Vector (単位ベクトル) と呼ばれているのは現在の位置からローカル座標軸に沿って 1m 前に進むための「グローバル座標軸上の」移動方向を表しているのです。今のところから「前に 1m 進む」には東へ Xm、北へ Ym、上に Zm いきなさい、ということです。
最初この llRot2Fwd を知らなくて、三角関数の llSin, llCos を使って 1m 先に進むためのグローバル座標軸の値を算出しようとしていたんです、、、。
ええ、直角三角形の1辺が 1m になるような X 軸と Y 軸の値を、、、もう、十何年ぶりにピタゴラスの定理です(笑
2
これ、常に地面に垂直にいればいいですが、傾いた時点でかなり面倒なことになりそうなのは理解していました。こんなめんどうなことやらないかも、と思い検索してたら llRot2Fwd を運よく見つけたのでした。
繰り返しになりますが、ローカル座標軸の 前後、左右、上下方向に 1m 進むために、グローバル座標軸上の 東西、南北、天地 での進まなくてはならない移動距離を出してくれるのが、llRot2Fwd, llRot2Left, llRot2Up という便利な関数になるわけです。
そうすると、

1) 現在の向きをllGetRot でとって
2) llRot2Fwd(llGetRot()) と渡して、向いている方向に 1m 進むための東西・南北・天地の値を算出し、
3) 現在の位置を llGetPos でとり、そこに 2) で算出した値を足し、
4) 今の位置から前方 1m のグローバル座標軸上の位置を llSetPos に渡すことができる、

ということですね。 2m 進みたかったら llRot2Fwd を2倍すればよいですし、後方ならば -1 をかければよい、ということです。
これで思い通りの場所にオブジェクトを移動させたり、Rez したりできるようになりそうでした。
が、、、、
今度は Rez したオブジェクトを「右へ90度向かせる」、「反対方向(180度)に向かせる」などの調整をしたくなりました。
ここではじめて「とりあえずこんなもの」と理解していたローテーション型(クォータニオン)の「すごさ」を実感することになりました。
つづく・・・

2008年11月17日月曜日

位置と回転を理解したい その1

Computer Graphics やゲームの制作に携わってこられた方にとっては当たり前のことだと思うのですが、なかなかそのエリアとの関連が薄かった人(私含め、、)にとっては、LSL でオブジェクトの位置と回転を理解するのに相当の時間がかかるのではないかと思います。

ネット上に情報はたくさんあるのですが、とにかく専門用語がいっぱいで、記事を読めばまた知らない単語が出て、その繰り返しでなかなか学習が進まないんですよね。

反面、ネットの情報では平面上に3次元に見える絵を書いて苦労しながら説明しているのを見ると、Second Life ってこういうことを理解するには安上がりでお手軽な手段じゃないかな、と思います。高価なソフトを購入しなくてもよいですし、前提の知識が他の環境に比べて比較的に少ないのも敷居を低くしてくれているように思います。(それでも苦労したのですが、、、)

ダンス スクリプトしか興味のない私がなぜ位置と回転なのか、、、実は通称「ネジ」と呼んでいる、Sit することでダンサーのポジション(位置)を決めるためのオブジェクトを作ったときに思いっきりはまっちゃったわけです。

そこでちょっとその時に学習したことを備忘録的にまとめてみよう、と急に思い立ちました。(笑

llSetPos を使った位置の指定

位置を指定する関数としては llSetPos があります。また、LSL を使わなくても、プリムの [編集] で位置の X, Y, Z の値を変えたりしてると思います。
0
llSetPos はこの X, Y, Z の数値をスクリプトから変更する関数になります。そのため X, Y, Z の3つの数値を扱うために LSL ではベクター型 (vector, ベクトル) という 3 つの数値をひとまとめにした入れ物が用意されています。

vector nowPos;

nowPos というベクター型の入れものを宣言すると上記のようになります。
X, Y, Z にはその SIM の絶対位置が使われます。<0.0, 0.0, 0.0> という位置は SIM の地図上の左下の高度 0 mになります。
1
現在の位置を取得する関数は llGetPos です。タッチしたら現在の位置から 1m 上に上がるといった動きをするスクリプトは以下のようになります。

default{
      state_entry(){
          llSay(0,"Hello Avatar!");
      }
      touch(integer num_detected){
          vector nowPos = llGetPos();
          llSetPos(nowPos+<0.0,0.0,1.0>); // X, Y は変えず Z だけ現在の位置から 1m 上に設定
      }
}

touch イベントの中で現在の位置を取得して、1m 上の位置を指定していますから、タッチするたびに 1m ずつ上にあがっていきます。
現在の位置を state_entry や on_rez の中でとってしまうと、一回目のタッチでは 1m 上にあがりますが、動いた後の位置をとらないので次からはオブジェクトが動かないスクリプトになってしまいます。
ここで X, Y, Z という方向が「絶対位置」として、この3軸が必ず「直交」していることに注意します。
地図上では X 軸は東西、Y軸は南北、Z軸は上下(天地)です。
「今の位置から西に1m, 南に2m, 上に1m移動します」
こういう指示ならば llSetPos(llGetPos()+<-1.0, -2.0, 1.0>) という位置指定でいいのですが、おおよそ移動したい位置を指定するときは
「前に1m, 左に2m, 上方に1m」
こういうことを考えますよね。
そうすると「前ってどっち?」となります。もしかしたら、今向いているのは東北北東の方向で X, Y, Z といった軸に重なっていないかもしれません。
そこで出てくるのが「回転」の考え方になります。
つづく・・・

2008年11月9日日曜日

[MLDU] HUD としての装着場所

お試し版が Mod 不可だったので、、、MLDU お試し版に入れたフリーもののアニメーションが消せない、、、というご迷惑をおかけいたしました。。。
取引履歴から Mod 可に修正したものを送らせていただきましたが、その際に以下のご質問をいただきました。

「HUD として画面のどこにでも装着できますか?」

はい。お好きなところに装着できます。

単純に「装着 (Wear)」を選ぶと右上、または下の真ん中に MLDU が装着されますが、これはベンダーにいれる前のテストの状態を記憶しているからです。ですから、ご自身で HUD として装着した場所には次回から「装着(Wear)」でだいじょうぶです。

Rez したときは「ダンス玉」、HUD として装着したときは HUD 玉(笑 でサイズや形状、テクスチャを変更しているのが MLDU のコンテンツフォルダにある「AppearanceChanger」という名前のスクリプトです。このスクリプトは編集可能にしてますので、スクリプト ソースを見ることができます。

このスクリプトが Rez したときは 50cm, 50cm, 50cm のダンス玉にして、装着したときは 5cm, 5cm, 5cm の立方体に変更して Face 4 にテクスチャをつけて、Face 4 がちゃんと正面にきて見えるように回転をさせてます。
また、その際に HUD の装着位置を確認して、画面から HUD が出ないような調整をしています。

もし、HUD が消えてしまったら、こちらの投稿を参考にして調整してください。
HUD 位置調整方法

[MLDU] アニメーションが削除できない

お試し版(0L$, 1L$) で以下の不具合がありました。
ただし、製品版 (3人用、6人用、15人用、30人用) は問題ありませんのでご安心してください。

[現象]
・MLDUにアニメーションを移動もしくはコピー
・その後有料のコピー不可のものは再度インベントリ(持ちもの)に戻すことができる
・ところがコピー可のフリーものは消しても、消しても MLDU のコンテンツ フォルダに残り続ける
・なので、不要なダンス アニメーションを消すことができない

[原因]
・MLDU4 お試し版のパーミッションが適切に設定されていませんでした(Mod 可にする必要あり)

[解決方法]
・編集可能にした MLDU4 お試し版を再度入手してください
・取引記録にある方には個別に MLDU4 お試し版の修正したものをお送りしています

[確認方法]
・MLDU4 のパイメニューから [編集] を選んで、テクスチャの編集が可能なものは問題ありません
・OEDO City の Stuido4D さんに設置してあるお試し版ベンダのものが該当します
・すでに OEDO City Studio4D のお試し版は修正したものに差し替えています

お手数をおかけしますが、よろしくお願いします。


そもそも Mod(編集) 可にしていなかったのが大きな原因です。本当にすみませんでした。。。
これだと外観さえ編集できませんもの。
ただ、外観だけではなくて、コンテンツフォルダに「追加(コピー)」できても「削除」できなくなるんですね。
コピー不可の有料のアニメーションは持ち物(インベントリ)に再度 移動できるので大事には至らなかったといえますが、本当に何度も確認してからベンダーとして公開しないとだめですね。
深く反省。

2008年11月7日金曜日

[MLDU] 初期ダンス設定方法

MLDU は llStartAnimation/llStopAnimation を指定間隔で行うわけですが、llStartAnimation の指示あとでダンスに参加した Avatar は現在他の人が踊っている Animation に途中から参加することができません。

元々シンクロ(同期)ダンスを踊るための MLDU だったので、おくれて入ってきても、、、同じダンスをおどっても意味がない、という考えのもとでした。

そこで、MLDU3 まではコンテンツ フォルダの中の一番上にあるアニメーションをデフォルト ダンス アニメーションとして取り込んで、danceSlot スクリプトが同期スクリプトの SynchManager から「同期の指示がくるまで」そのダンスを踊らせる仕様でした。

llStartAnimation はプリム内のコンテンツ フォルダにあるダンス アニメーションの「名前」を使ってダンスを踊らせますから、llGetInventoryName を使って、アニメーション タイプのオブジェクトの名前をフォルダから取得していたわけです。

string initAnimName = llGetInventoryName(INVENTORY_ANIMATION,0);

こんな感じでした。

しかし、、、この待ちのダンス、「待っているような」ダンスを躍らせたい、というリクエストがあったわけです。

Sine Wave の dance 14 とか、そんなダンスも存在しているわけで、たしかにそうしたいのもわかるというもの。

そこで MLDU4 では 00:XXXXXXXXXX というノートカードを使っています。


ノートカードを使っているといっても、00:XXXXXXXXXX のノートカードの中身は空です。
つまり、ノートカードの名前の XXXXXXXXXX の部分を使っているわけです。
SynchManager と Animations というスクリプトからノートカードを読み込む方法をとっているにもかかわらず、この「名前」をとる方法にしたのは、、、単純にシンプルにしたかったためです。(というか、、、楽したかった?)
ノートカードの読み込みは dataserver イベントを使っているので軽い処理ではありません。そのため、ノートカードの読み込みが重なってしまうとエラーになることもあったわけです。
この初期ダンスの設定は MLDU4 リセット時に 50 ダンススロットバージョンだと 50 のスクリプトのリセットが走るわけですから、、、なるべくシンプルにしたかったのです。
ということで、、、ノートカード 00:XXXXXXXXXX は初期ダンスを指定するためのノートカードになります。
ブランクが入ってもかまいませんが、正確に名前を入れる必要があります。
もし、XXXXXXXXXXX で指定したダンス アニメーションが無かった場合は、MLDU3 までと同じようにコンテンツ フォルダにある一番上のアニメーションを使用します。
スクリプトとしては以下のようなものを使っています。
string initAnimName = "";
integer numberOfNotecards = llGetInventoryNumber(INVENTORY_NOTECARD); //ノートの数を取得
integer i;
for(i=0;i<numberOfNotecards;++i){ //ノートの数ぶん for をまわします
     string tName = llGetInventoryName(INVENTORY_NOTECARD, i);
     if(llGetSubString(tName, 0, 2)=="00:"){ //もしノートカードの名前の最初の3つの文字が 00: だったら
          string tName2 = llGetSubString(tName, 3, -1); //00: 以降のストリングを取り込み
          if(llGetInventoryType(tName2)!=-1){ //その名前のダンスがコンテンツ フォルダに存在していれば
               initAnimName = tName2; //初期ダンスとして登録します
          } else { //存在してなければ
               initAnimName = llGetInventoryName(INVENTORY_ANIMATION,0); //最初のアニメを登録
          }
          i = numberOfNotecards; // for を終わらせるため max 値をいれます
     }
}
//このあとで 00:XXXXXX ノートカードそのものが存在していない場合の処理を。。。
llStringTrim を使って 00: の後のダンス アニメーション名の前後のスペースの削除とかしてませんから、00: に続けてアニメーション名を「名前の変更」でいれてください。

2008年11月3日月曜日

[MLDU] 持ち物へのコピーと形状変更

MLDU4 のベンダーを公開しましたが、今までフォルダーのコピーだった販売方法を Pay 方式を使ってオブジェクトをお渡しする形にしました。4つのバージョン(3人用、6人用、15人用、30人用)の販売を1つのベンダーで可能になるのがメリットでした。

ちょっと販売方法が変更になったので、その手順をご紹介します。
また、MLDU4 は Rez したときのダンスボール状態と、装着したときの HUD 状態で形状、サイズ、テクスチャを切り替えるようにしています。その説明も最後のほうでしています。

1) オブジェクト(MLDU4 パッケージ)を地面上に REZ する
ベンダーから MLDU4 を購入すると、持ち物(インベントリ)の Objects フォルダに MLDU4(X) というオブジェクトが渡されます。
X にはお買いいただいた人数の数が入っています。まず、それを REZ できるエリアで地面に REZ します。
REZ したオブジェクト上でパイメニューを表示して「開く」を選択します。

0


2) 持ち物(インベントリ)にコピーする
オブジェクト・コンテンツのウィンドウが開くので、[持ち物にコピー] ボタンをクリックします。
1
MLDU4 は no copy なので、以下の警告がでますが、[OK] をクリックします。
2
3) 持ち物(インベントリ)にフォルダが作成され、オブジェクトが移ったことを確認する
MLDU4(X) (Xには人数が入ります) というフォルダが作成され、フォルダの中に MLDU4 その他のオブジェクトが入っていることを確認します。 NOTECARD もご一読ください。
3
4) REZ してスクリプト リセットを行い初期化する
実際にダンスボールとして使う場所で MLDU4 を REZ します。
初めて Rez したら必ずスクリプトのリセットを行います。MLDU4 をタッチしてダイアログ メニューを表示させ、[詳細設定] ボタンをクリックします。
4
次に表示されたダイアログで [リセット] をクリックすると、スクリプトのリセットがはじまります。
5
リセットが完了すると以下のようなメッセージが表示されます。
6
5) HUD として使う
HUD として使う場合は装着してください。もちろん、はじめて使う場合は HUD にした状態で 4) の手順でスクリプト リセットを行ってください。
7
MLDU4 は Rez した場合と HUD として装着した場合でプリムの形状、大きさとテクスチャを自動的に変更する仕組みになっています。
また、HUD として装着する場所はどこでもかまいません。 HUDの位置についてはこちらも参照してください
HUD として装着した小さな赤い玉をタッチすると、REZ した場合のダンスボールと同じダイアログ メニューが表示されます。
HUD の場合は他の人がタッチすることはできませんから、[招待] ボタンでダンスを招待します。
8
6) ダンスボールの形状変更 ApprearanceChanger スクリプトについて
REZ したダンス玉のテクスチャや大きさはオーナーにより修正可能ですが、以下のことに気をつけてください。
a) Take しない限り、変更は有効です。ダイアログからのスクリプト リセットをかけても、形状がもとにもどることはありません。
b) ダンス玉の形状を変更し、その後 Take して、再度 Rez した場合は初期の形状・サイズに戻ります。ただし、テクスチャの変更は有効のままです。
これらの動きを変更したい場合は MLDU4 のコンテンツ フォルダにある ApprearanceChanger というスクリプトを修正することになります。このスクリプトはフル パーミッションで修正可能です。
---------------------------------------------------------------------------------------------
ぜひ、お楽しみください~。

LSLCON アイテムデモ 無事終了~

スクリーンショットを取る余裕はなく(w
本日 11月2日 午後8時30分~午後9時15分の予定で LSL コンベンション 2008 Japan のアイテムデモ "MLDU4 ~ダンスアニメーションを本当に楽しませるのはスクリプターのお仕事~" 無事終了しました。担当の Miya さん、事前の準備で付きあわされた(笑)お友達、今日参加してくださった皆様、本当にありがとうございました。 あ、あと、この機会を作ってくれた Nullpo さんにも感謝。

ダンススクリプトって、正直地味な制御系の範疇なので、、、ダンススクリプトがあっても「ダンス アニメーション」が無ければただの箱(もとい、、玉w)ですし、ビジュアル系(動きが派手なものとか)のスクリプトと違って、、、手間がかかる割にはあまり見た目がわかりづらいですよね。

そこで、アイデムデモは前半はスクリプトの説明とかちょっとしたテクニックをパネルでご紹介して、後半は実際に踊ってもらう方式にしてみました。踊ってもらったほうがわかりやすいw

実はデモで使った My MLDU には 145 のダンス アニメーションが入っているのですが、もちろん Studio4D スペシャルでやってみました。

といっても、、、シンクロダンス(同期ダンス)とか、ご紹介してきた時間差ダンスを踊ってもらうだけじゃ、、、参加型じゃないので面白くありません。 そこで一応シンクロ、時間差をやったあとで参加型にしたのが通称「はないちもんめ」。

15人の方にダンスを踊ってもらっていたので、5人1組の同じダンスを踊るグループを作ると全部で3組できるわけです。で、「同じダンスを踊っている人を見つけて、そばに寄ってみましょう~」という、、、ある種、合コンのゲームのような(笑

仕組みは時間差とシャッフルを組み合わせたものです。
1) 15人の参加者を3組にわけるには、サイクルを 3 に設定します。すると、ダンススロットは以下のような「グループ番号」を持ちます。

   ダンススロット番号: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
   グループ番号: 0 1 2 0 1 2 0 1 2 0 1   2   0   1   2

グループ番号 0 の人は同じタイミングで、同じダンスを踊ります。つまり、ダンスの開始は グループ番号 0, 1, 2, 0, 1, 2, 0 .... と繰り返します。

2) シャッフルモードをオンにして、各グループ番号のダンスをばらばらにする
シャッフルモードをオンにすると、本来同じダンスを時間差で開始するものが、時間差のたびに違うダンスを選ぶようになります。llFrand を使ってるので必ず違うもの、、、とは限りませんが、ダンス アニメーションがそこそこ入っている状況であれば、かなりの確率で違うものになります。(もちろん、llFrand の指定はセットのダンス アニメーション数の上限をきちんと指定しています)
そうすると、グループ0、グループ1、グループ2 の人たちが踊るダンスを違うものにすることができるわけです。

3) で、あとは「同じダンスを踊っている人を探しましょう~」と皆さんに呼びかける。
結構楽しんでいただいたようです。意外に、、、同じダンスってみつけづらかったりするんですよ。

MLDU4 は踊りながらサイクルをどんどん変更することができます。なので、サイクル 3 を今度はサイクル 5 にすると、3人一組のチームが15人いたら5つできるわけですよね。
これを応用して、3人のときにサイクル2にすると、2人が同じダンス、1人が違うダンスを踊ることになります。

同じダンスを踊っている人たちが両サイドにくると、まるでアイドルのバックダンサーのような踊りを踊ることができます。
MLDU4 RC は 11月3日の夕方くらいには「正式版」となって SnuLib で販売開始になる、、、予定です。

3人/2ダンスセットは 1L$ のお試し版で、正式版は 6人/8ダンスセットが 600L$, 15人/8ダンスセットが 1,500L$, 30人/8ダンスセットが 3,000L$ でご提供させていただく予定です。 50人/8ダンスセットや、カスタムは IM (もしくは、ここのメールを送る)でお問い合わせください。

[追記]
正式発売しました。ベンダーを SUZAKU に設置しました。
今回は、、、ベンダーも自分で作ってみました。正式版はどれも 8 ダンスセットの登録が可能で、今回は 3 人分のフルバージョンも用意してみました。
vendor_explain
Pay 方式にして、3人用(300L$)、6人用(600L$)、15人用(1,500L$)、30人用(3,000L$)から選ぶことができます。
vendor_explain1
もちろん、1L$ の3人用(2ダンススロット)のお試し版のベンダーもそのまま設置しています。

2008年10月30日木曜日

[MLDU] ノートカードの編集

(ありがとうございます。LSLCON ではすでに 60名以上の方に MLDU4RC お試し版をお持ちいただけました。11月2日まで LSLCON 会場で MLDU4RC お試し版を 0L$ プライスレスで配布中です。)

MLDU4 と MLDU3 でのコンセプトの違いは NOTECARD 編集にそれほど時間をかけなくてもダンスを楽しめることかもしれません。
もともとクラブ雷神の LINZOO さんの依頼で作成し始めたとき、MLDU の特徴のひとつである「スムーズなダンスのつなぎ」を実現するために、NOTECARD によるそれぞれのダンス アニメーション再生時間は必須、、、と考えていました。

ですが、、、この NOTECARD 編集、結構手間なんです。(笑

MLDU3 でも NOTECARD に時間指定がないときはデフォルト24秒の再生時間を割り当てていましたが、MLDU4 では以下の機能でさらに時間指定がなくても楽しめるようにしました。

1) [次のダンス]、[前のダンス] ボタンでダンスを切り替えることができる
2) [間隔設定] からダンス アニメーション再生時間を随時変更できる(NOTECARD に再生時間の指定のないものだけが対象)

これにより、NOTECARD 編集の負担が減ったのではないかと思っています。

NOTECARD で指定されたダンス アニメーションはスクリプト リセット時にコンテンツ フォルダ内の存在チェックをします。
もし、NOTECARD に記述しているダンス アニメーションがフォルダ(MLDU)内になければエラー表示をして処理が止まる仕様になっています。

0

[10:28]  MLDU4(Snu): ノートカード 4.DANCES に記載されているアニメーションがありません。 タイプミス、大文字・小文字、半角空白などを確認してください。: weloveyou- boy
[10:28]  MLDU4(Snu): ノードカードに記述されているダンスアニメーションが存在しないので 4.DANCES は処理を中断しました。

というメッセージが表示され、処理が中断しています。
メッセージにあるように、大文字、小文字(Upper/Lower Case) や単純なタイプミスに注意してほしいのですが、なかなかどこが違うのか、何が悪いのかわからない典型的な例がいくつかあります。

1) 半角ブランクが2つあった、、、(SineWave)
SineWave の "4 and 2 the floor" というダンスがあります。そのままノートカードに打ち込むとなぜかエラー、、、
半角ブランクを □ に置き換えると、このダンス、なぜか 4□□and□2□the□floor という、4 と and の間に2つのスペースが入っていました。

2) 読み込めない、読み込めない、、、(SineWave)
これも SineWave なのですが、ダンス名にカンマ(,)が入っていると、、、今の MLDU ではノートカード読みこみの際にダンス名が途中で切られてしまうため、処理を続けることができません。ダンス名と再生秒をカンマで区切る方法をとっているためです。
おおよそ有料のダンス アニメーションは Mod 不可なので、名前を変更することができません。幸い、上記のケースは稀なので、とくに 2) は「ごめんなさい」なのですが、1) の場合などを回避するためになるべくキーボードで名前を打たないで、コピー&ペーストすることをお勧めします。
ダンス アニメーション上で右クリック(Win)でメニューを出して [プロパティ] を選択し、名前をマークして Ctrl+C(Win) でコピーして、ノートカードに貼り付ける方法をとれば、1) のようなトラップにかかりません。またタイプミスの心配もありません。
ノートカードの編集はプロパティから名前の Copy & Paste をしてくださいね。

2008年10月19日日曜日

LSLCON に出展・展示中~

実行委員関係のお友達からお願いされ、まったく気軽に展示してしまいました、、、MLDU4 RC。 (笑
多人数同期ダンスをしたくて作った MLDU3 をこの半年(!!!) くらいかけて、少しずつ改良、機能を追加していったものです。
なので、、、もともとあまり商売っ気がないダンサー/スクリプタですが、、、まだ売ってません(笑

LSLCON JAPAN 2008 の空中会場のテレポート近くのブースで展示中です。

LSLCON01

この数ヶ月、いろいろな方の助けをもらいながら試していたのが時間差ダンスやシャッフルダンス。以前の投稿にも書きましたが、時間差ダンスのアイディアはすぐに出たのですが、やっぱり、この手のものは半分は「エラー処理」になってしまいますね。基本的なところから例外的なところまでいろいろエラー処理をいれてきました。 Mono 化でメモリーに余裕がでたおかげです。

使い方や、MLDU4 の仕組みみたいなことはブースのパネルでも説明しています。(ええ、トリセツがなくて本当に迷惑をかけていた MLDU3 でした、、、)発売するときはこのパネルもいれようかと思っています。

で、、、展示2日目でエラー発見、、、、@@

ダンススロット管理は MLDU のもっとも重要なところです。たとえば、踊りながら落ちちゃった、他の SIM にいってしまった、、、などという場合は使用しているダンススロット(スクリプト)を解放して、次の人が使えるようにしないといけません。
相当このあたりは MLDU3 からテストしてきたつもりだったのですが、今日ブースにいくとだれも踊っていないのに1つのスロットが使用されている状態になっていました。
そこからいろいろと可能性を考えたのですが、どうやればこの状態になるかしばらくわかりませんでした。

llStartAnimation を Avatar に対して行って、もし Avatar がいなければそれによりスロットの解放をするので、llStartAnimation は動いていないと想定。とすると、、、以下の場合があてはまるのではないかと予想しました。
llRequestPermissions により「アバターに動きをつける?」ダイアログが表示されているときに落ちる。

試してみると、、、見事に(?)スロット利用状態のままでした。。。(追記 注2)
たしかに、、、llDialog は使っていませんが、llRequestPermissions によりダイアログは表示されているわけです。通常 listen イベントで受け取るダイアログとは違って、llRequestPermissionsrun_time_permissions イベントでうけとる特殊なダイアログですが、ダイアログはダイアログですよね。

ダンススロットが埋まって解放されないのは致命的なので、、、以下のようなエラー処理をいれました。

llRequestPermissions(id, PERMISSION_TRIGGER_ANIMATION);
llSetTimerEvent(60.0); // 60 秒タイマーをかける
run_time_permissions(integer perm) {
llSetTimerEvent(0.0); //なんらかの返信があったのでタイマーを止める
if (perm&PERMISSION_TRIGGER_ANIMATION) {
llStartAnimation("animation file name");
llInstantMessage(id, "ダンスを止めたい場合は、、、、");
} else reset(); // [ いいえ ] が押されたのでダンススロット解放
}
timer() {
llSetTimerEvent(0.0);
if (llKey2Name(id)!="") {
llInstantMessage(id, "タイムアウトです~");
}
reset(); //ダンススロットの解放サブルーチン
}

ダンスを踊るかどうか聞く前にスロットを一時的に予約して先にタッチした人を優先させるMLDU の管理・アニメ処理方法が、上記のエラー処理を必要としているかもしれません。その部分のロジックを変更するのはつらいので上記の方法をとりましたが、もう1年近くも使ってきて、llRequestPermissions のあとで llSetTimerEvent って、、、ぜんぜん気が付きませんでした。

llRequestPermissions をタイムアウトさせてしまう副作用は、、、、あるんです。
llRequestPermissions によるダイアログへの返答、はい、でも、いいえでも、タイムアウトした後で押すと、、、run_time_permissions イベントに記述されている関数が、、、動きます。@@

これを無効にする方法が、、、、、ないんです。

そんな、、、と思われるでしょうが、この状態でスクリプトをリセットしても、、、、表示されているタイムアウトにしたダイアログに返答すると run_time_permissions のスクリプトが動くのです。。。@@

つまり、、、あくまで想像ですがこの状態になったときの返答への処理は、スクリプトをよんで処理するのではなく、そのブロックがメモリというかスタック上にあって、それを使うような気がします。(注1)

ですが、、、この例外対応、この状態になったら「落ちている」のがほとんどのはず。故意に60秒間放置して、、、という状態の対応は優先順位が低いと考えました。たしかに「はい」を押すと、run_time_permissions イベントのブロックに書かれている初期のダンスアニメーションは始まりますが、それ以上はなにも起こらないので、タイムアウトの際のメッセージに「いいえ、を押して再度ダンスボールを押してください」という運用の対応にしてみました。
スクリプトって楽しいけど、難しいですねぇ、、、

[追記] 注1
基本的に LSL もそのときそのときにスクリプトファイルからスクリプトを読むようなことはしていないはず。なので、該当のスクリプトをリセットしても、そのスクリプトから出された llRequestPermissions に対する処理である run_time_permissons の部分がスタック上クリアされていない、、、というのが正しいのかもしれません。(すみません、本当に想像です。。。) run_time_permissions イベントにある llSay や llStartAnimation は効きますが、上記の例だと reset() というユーザー関数は呼ばれません。さすがにそこはスクリプトのリセットによりクリアされているのでしょうね。

[追記] 注2
注、、、というほどのものではないのですが。(笑
通常のご利用だと、今回示した llSetTimerEvent を llRequetPermissions のあとに入れなくても、スロットが解放されないことはありません。というのも、他のだれかがダンスを開始して管理スクリプトから実行ダンススロットのスクリプトにアニメーション開始命令が出された時点でアバターがいないチェックが入るので、このスロットは解放されます。他の人が使える状態になります。
考えすぎかもしれませんが、、、展示品の状態で「アニメーション許可のダイアログに答えずに落ちる」をスロットの数ぶん10回繰り返されると、スロットが埋まってしまい、このときオーナー(私 ^^)以外はスクリプトのリセットをかけられないので、展示品のダンスだまでは誰も踊れなくなる、、、というのを回避したかったのです、、、。

[追記] 上記のように思っていたのですが、llRequestPermissions に対する返答をしていない状態なので llStartAnimation がダンススロット側で開始されていません。管理スクリプトからダンス開始命令をだしても、ダンススクリプトは保留中のまま、、、でした。なので、やはりこの処理はもしものために必要だと考えたほうがよさそうです、、、

2008年10月4日土曜日

Torley のビデオ チュートリアル

ひさしぶりに Torley のビデオ チュートリアルを見たら知らないことがたくさん!

いろいろな方が翻訳とか紹介とかしていると思うので既知のものもあると思いますが、近々の面白かったものをピックアップしてみました。

Lip Sync
恥ずかしながら知りませんでした。7月23日追加なので情報としては古いですが、いつのまにか Voice Chat とアバターの「口バク」を同期させる機能がついていました、、、


この仕組みからする新たに口バクのアニメーションが追加されているか、既存のものを転用しているのか、ちょっと気になりました。あとで wiki で調べてみようと思います。
[追記] よくよくみたら、、ビデオの中で紹介してますね、、スピーチジェスチャ(笑
[追記] でも、クチパクは別みたいですね (^^;

他のAvatarのFaceLightやパーティクルをオフにする
他の Avatar がアタッチ(装着)しているライトやパーティクルをオフにする方法があるんですね。
時々、横の Avatar の FaceLight がきつくて白浮きする時があるんですが、これでやると回避できますね。(あれ、、、自分の Facelight も、、、消えるのかな?これは後でチェックしてみないと、、)

Windlight プリセットパック
前に見たことがあるような気がしますが、Torley が作った Windlight のプリセットのダウンロードと設定の仕方を説明しています。 Windlight は細かい設定ができる反面、個々の調整のバランスが難しいと感じるときもあるので、このようなプリセット集はうれしいですね。

お月様を変える
ある意味、、、期待していたものと違った(笑 のですが、夜に出てくる月を変える方法を紹介しています。

やはり定期的にチェック必須ですね。

2008年9月17日水曜日

Sunrise - 時間差ダンス

この前の週末に ASUKA DJ RELAY というイベントがあって、DJ さんがリレー形式でクラブ雷神で曲をかけるというイベントがありました。で、そのときの模様を動画でとって Yaz さんの Sunrise で編集してみました。

今、新しいダンス玉のテスト中で、今回のダンス玉の特徴は「時間差ダンス」です。

同期(シンクロ)ダンスはよくありますが、0.5秒とかわざとずらしてダンスを開始させるものを試しています。
今回の動画でもその「時間差ダンス」をみることができます。

時間差ダンスの仕組みはとても簡単ですが、Mono のおかげでちょっと気がラクになったかも・・・です。人数分の llStartAnimation の命令をちょっとずつ時間をずらして行うわけですから、軽い処理とはいえません。

しばらくクラブ雷神で様子をみながらテストを繰り返すことになると思います。

もちろん、時間差から同期の切り替えはボタンでオッケーです。


あ~、エンディングの日付・・・おもいっきり「未来」になってるし、、、開催されたのは9月13日でした。。。

2008年8月31日日曜日

新しい関数 llGetAgentLanguage

Second Life で外人の方とのコミュニケーションは珍しくありませんよね。
ダンスクラブに来られた外人の方にダンスの開始方法を教えるのも、、、まぁ、英語ならなんとかチャットで教えてあげていました。

サーバー 1.24 でいくつかの新しい関数が追加されていますが、llGetAgentLanguage という関数は、その Avatar の Agent が使っているビューワーの言語のバージョンを取得する関数です。これを使うと、スクリプトのメモリが許せば、日本語、英語、がんばれば他の外国語のメッセージをスクリプト内に保存しておいて、Agent が利用しているビューワーの言語情報によって切り替えることが可能ですね。

MLDU(ダンス玉) でいうと DDManager みたいなダイアログの操作でストリング(文字列)とリストを多用していると、メモリの問題から1つのスクリプト内で処理するのはつらいのですが、個々のアバターのパーミッションを管理して、ダンスの開始、停止を行うスクリプトなどは、複数の言語メッセージを保管しておいて、llGetAgentLanguage の情報からメッセージを切り替えることが可能になりますね。

こんな感じです。

string msg1 = "こんにちは!";
string msg1e = "Hello!!";
    if (llGetAgentLanguage(id)=="ja"){
            llInstantMessage(id, msg1);
    } else llInstantMessage(id, msg1e);
日本語以外だったら英語、という単純なものですが、ダンスの停止方法などをビューワーの言語設定にあわせて切り替えて表示させるには重宝しますね。
あたりまえですが、引数にはアバターの Key が必要です。ですから、Detected 系の関数をつかってあらかじめ対象となるアバターの Key を取得して llGetAgentLanguage に渡すことになりますね。戻り値は ja や en-us といった文字列になります。
list を使って利用する方法もありますね。
list msgList01 = ["ja","こんにちは!!","en-us","Hello!!","fr","Salut!!!"];
default
{
    state_entry()
    {
        llSay(0, "Hello, Avatar!");
    }
    touch_start(integer total_number)
    {
        integer i = 0;
        for(; i<total_number; ++i) {
            string lang = llGetAgentLanguage(llDetectedKey(i));
            integer x = llListFindList(msgList01,[lang]);
            if(x==-1) x=2; //言語対応してない場合のデフォルトを指定します。
            llInstantMessage(llDetectedKey(i), llList2String(msgList01,x+1));
        }
    }
}
ちょっとしたメッセージだと、この方が list に言語と対応するメッセージを追加するだけでよく、 if 文を変更せずに済むので楽なのかもしれませんね。
ちょっとした小ネタでした~。

2008年8月23日土曜日

Mono がやってきます

Linden の Official Blog に「Mono Launch」という記事がついに投稿されましたね。

Linden Official Blog - Mono Launch

20日から 1.24 サーバーの展開が始まって、その 1.24 サーバーには Mono が含まれている、ということらしいです。
サーバーが 1.24 になっただけでは Mono は使えず、スクリプト作成者はクライアントビューワーの 1.21 RC が必要になるということです。1.21 RC のビューワーではスクリプトエディタの下に [Mono] というチェックボックスが追加されるので、それをチェックして保存、コンパイルで Mono 対応に移行完了、ということらしいです。逆に [Mono] にチェックをいれなければ、従来のまま動くようです。
ちなみに サーバー 1.24 のリリースノートによれば、ビューワーの 1.21 RC は 8月25日の週にリリースする予定ですね。

Mono はスクリプトを動かすための新しいエンジンで、従来のものと並存して提供されるとのことです。すべてのスクリプトを変換する必要はなく、また、LSL の書き方が変わるわけではありません。ちょっと安心ですね。

この Mono ですが、この新しい実行環境はスクリプトの「実行スピード」と「メモリー管理」が現行のスクリプト エンジンよりも強化されている点が特徴です。

この 1ヶ月ほど、ダンス玉 (次の MLDU) に機能をどんどん追加していったらメモリーがかなり厳しくなって、スクリプトを分けないと 10人以上踊れない、、、という状況になっていてのこの記事だったので、早速ベータ グリッドにいって試してみました。メモリーに関していえば、これまで 1つのスクリプトは 16KB しかメモリーを使えませんでしたが、Mono では 64 KB まで拡張されていることは知っていました。

今の環境だと、一番メモリーがくるしい DDManager (Dance Slot と Dialog 管理スクリプト) は残りのメモリーが 1.1K しかありません。これ、リストの操作で空のリストを使う方法じゃないと、エラーでスクリプトが止まる状態だったりします、、、

mono003s


ベータ グリッドにアクセスするには Preview Grid Viewers でダウンロードできる 1.21 ベータをインストールして、1.24 サーバーになっている Sandbox のリージョンにいくと Mono のテストが可能です。
早速、スクリプトエディタを開いてみると、ありました、[Mono] のチェックボックスが。
mono002s
MLDU ダンス玉のスクリプトの [Mono] をすべてチェックして、メモリーの状況を確認してみました。
mono001s
1.1 KB しか余裕がなかった DDManager は 29.5KB(!!!) までフリーメモリーが増えました。(^^)v

リストやデータを保持するための単位必要メモリーの容量が大幅に変わっていなければ、これでかなり余裕 (というか、16KB より大きいしw) ができたことになりますね。
あと、やはり実行速度も速くなっています。メモリーの状況を表す上の画面の Text の表示や、MLDU 初期化時のアニメーションチェックなど、今のものよりも速くなっていますね。
ということで、スクリプト分割大改造せずに Mono を待つことにしました。(笑

2008年8月17日日曜日

YazMania Videos Clip

NMR10~、遅ればせながら参加できました。

nmr10d

ファンの人からの「この曲が好き、なぜなら、、、」みたいなやり方って、ほんと楽しかったし。
それぞれが、それぞれの思いあるから、「へぇ~、そうなんだー」みたいなのがあって、新鮮でした。
Yaz Yaz で素人なりにビデオつくってきて良かったなぁ~、と思いました。それぞれの思いがある曲もみんな違うし、それぞれの考え方や印象もみんな違う。それって、いろいろな思いをいだかせることができる才能のある人がなせる業w

すごいなぁ、、、Yaz さんって、いろいろな人にいろいろな感情・体験を持たせているんだぁ、、、と改めて実感しました。
で。。。。

こんなん、作ってみました~。
High Quality な、、、ですでに動画を見てる人は問題なさげ~、ですがw
[追記] サービス終了にて削除しました。
これからも多くのファンを楽しませてください~w

2008年8月12日火曜日

llDialog 再び

造形のセンスまったくなしなので、クールな HUD を作ってスクリプトを埋めこむ、、、なんてことができないので、どうしても llDialog を使うことになってしまいます。

llDialog で表示するダイアログには12個のボタンしか表示できない、ボタン内に表示できる文字数に制限がある、同じ場所から出てくるので「複数ダイアログ表示」できないことはないのですが、あまり使い勝手が良くないなど、制約が多いのですが、、、これを使うしかないわけで(笑

そこそこ多くのダイアログを作ってみて、気がついた点などを再度まとめてみようと思いました。

1) 複数の人がダイアログを押して、それを処理するような状況になるべくしないほうがいいかも

用途にもよりますが、複数の人がダイアログを押すような状況を仮定してスクリプトを組まないほうが懸命のようです。できないことはないのですが、if 文を駆使して、そのロジックをいろいろと悩むよりも、「前の人の処理が終わるまで待ってもらう」としたほうが当然のことながらスクリプトがシンプルになります。

[追記] ダンス玉(つまりアニメーション操作)など Permission を必要とするものなどは、touch されたら、アバターの Key を他のスクリプトに渡し、そちらで処理する方法があります。この場合は、複数の人が1つのプリムをタッチしても、個別に処理するスクリプトの数の最大に達するまで処理をさせることが可能になります。1つの Prim には複数のスクリプトを入れることが可能なので、touch を管理するスクリプトを親として、詳細の処理を子スクリプトに渡す、、、ということができます。

2) state を使ったほうがラクかも

これも人によりけりでしょうが、私の場合は、タッチされたら(もしくは、なんらかのイベントが発生してダイアログを呼ぶようなことになったら)、そのアバターの key を拾って state を変える方法を使うことが多くなりました。メリットは llListenRemove を使わなくても state が変わることによって listeners を溜めなくてすむこと(64 だったかな?、Remove せずにそのくらい溜まるとエラーになります)、他の人が touch したときの処理をシンプルにできること、だと思っています。また、state_entry, state_exit を使った初期化処理/終了処理が可能でスクリプトが見やすくなることもあげられます。デメリットは必ず llSetTimerEvent を使ってタイムアウトを検知させること。これをやらないでダイアログの [無視] ボタンを押されたら元の state に戻って来れません。
(以下は可読性を高めるためにグローバル変数をあまり使ってません)

key toucher = NULL_KEY;
list buttons = ["button1", "button2", "button3"];

default {
    state_entry() {
       toucher = NULL_KEY;
    }
    touch_start(integer detected_num) {
       toucher = llDetectedKey(0); //一番最初にタッチいた Avatar の Key を取得
       state dialog; //ダイアログ・ステートに移動
    }
}

state dialog {
    state_entry() {
       integer hDialog = llListen(-5555, "", toucher, ""); //-5555チャンネルで、タッチした Avatar の声だけ聞く設定
       llListenControl(hDialog, TRUE); //リスナーを追加(要は聞き始める、ということ)
       llDialog(toucher, "好きなボタンを押してください。", buttons, -5555); //ダイアログを表示。返信は -5555 チャンネル
       llSetTimerEvent(30.0); //30秒でタイムアウトにさせるため
    }
    touch_start(integer detected_num) { //ダイアログ処理中にタッチした Avatar への処理
       integer i = 0;
       for(; i<detected_num; i++) { //タッチした人分の処理をする for ループ
           llInstantMessage(llDetectedKey(i), "ダイアログ使用中です。しばらくまってください。");
       }
    }
    timer() {
        llInstantMessage(toucher, "タイムアウトになりました。");
        llSetTimerEvent(0.0);
        state default;
    }
   listen(integer channel, string name, key id, string message) {
        if (llListFindList(buttons, [message]) != -1) { //一応のチェック処理。この程度なら必要ないですが・・・
            llSetTimerEvent(0.0);
            if (message == "button1") {
                xxxxxxxx;
            } else if (message == "button2") {
                yyyyyyyy;
            } else if (message == "button3") {
                zzzzzzzz;
            }
        state default;
        }
   }
   state_exit() {
        toucher = NULL_KEY;
        llSetTimerEvent(0.0); //しつこいですが、、、過去に timer が戻らなかったことがあったので・・・
   }
}

3) ダイナミックにボタンを変えてみましょう

「前ページ」「次ページ」ボタンで複数ダイアログを使いこなすのもおもしろいですが、操作する側にとっては望まない複数ダイアログは結構迷惑、、、だったりします。
たとえば、ダンスを踊る、止める、みたいな場合、最初のころ [踊る] [止める] のボタンを用意していましたが、よくよく考えると踊っている時は [踊る] ボタンを押すわけもなく、だったら [踊る] のボタンを [止める] にすればいいわけです。このため、状態を保持するフラグを使用しなくてはなりませんが、ボタン使用の節約には効果大です。
この場合は、フラグを元にボタンのリストに対して llListFindList を使い、該当する List 要素の順番をとり、llListReplaceList で置き換える、ということをやります。
意外に、、、この手の「対称な意味を持つ」ボタンって、、、多かったりします。
以下の複数ページダイアログの例の「ノートカードが変更されたら Close ボタンを RESET ボタンに変更する」などもこの考えでボタンを変更しています。

4) 複数ページダイアログの例

以前にご紹介している ネトラジ・チェンジャーは複数ページダイアログでネトラジ局をボタンにしています。その方法をご紹介します。
以下のスクリプトの前段階処理で、ノートカードからネトラジ局の情報を読み込んで contentList という List に入れています。
ダイアログの一番下の段は [< Prev] [Close] [Next>] という3つのボタンがくるので、1つのダイアログには9つのラジオ局のボタンが表示できます。その9つの部分を変えていくわけですね。
現在のページ数を currentPage として、0ページ目(そう、この世界ってはじめはゼロのほうが都合がいいです)の場合は 0 番から8番まで、1ページ目の場合は 9番から17番、、、、としていきます。
最後のページは List の項目数を 9 で割った商になります。たとえば0ページから「前ページ」を押されたら、最大ページに移る、、、みたいなこともあらかじめ最後のページ数をとっておいて、もし、「前ページ」がマイナスになるのであれば、最大ページをいれる、次ページが最大ページを超えるようであれば、0ページを入れる、とすれば、複数ページのラウンドロビンが可能ですよね。
以下は NRC のソースの default ステートを除いたそのものです。オレンジにした部分がページとボタン操作になります。
state wait {
    state_entry()
    {
        llMessageLinked(LINK_THIS,myNumber,"wait",gToucher);
        currentPage = 0;
        buttonList = [];
        gToucher = "";
        integer handle = llListen(gChan,"","","");
        llListenControl(handle,TRUE);
    }
    link_message(integer sender_number, integer number, string message, key id)
    {
        if (message == "start") {
            if (number == myNumber) {
                gToucher = id;
                currentPage = 0;
                state active;
            }
        }
       
        if (message == "contentChanged")
        { // ノートカードが変更されたら Close ボタンを RESET ボタンに変更する
            fixedList = llListReplaceList(fixedList,["RESET"],llListFindList(fixedList,["Close"]),llListFindList(fixedList,["Close"]));
        }
    }
    listen(integer channel, string name, key id, string message)
    {
        if (llStringTrim(llToUpper(message),STRING_TRIM)=="HIDE TEXT") {
            llMessageLinked(LINK_THIS,myNumber,"HIDE TEXT","");
        } else if (llStringTrim(llToUpper(message),STRING_TRIM)=="SHOW TEXT") {
            llMessageLinked(LINK_THIS,myNumber,"SHOW TEXT","");
        }
    }      
}
state active {
    state_entry()
    {
        integer handle = llListen(gChan,"",gToucher,"");
        llListenControl(handle,TRUE);
        buttonList = fixedList + llList2List(contentList,currentPage*9,(currentPage+1)*9-1);
        gDialogMsg2 = "登録数 "+(string)gCount+", "+"ダイアログチャンネル: "+(string)gChan;
        gDialogMsg3 = "オブジェクト上の文字を消したい場合は"+"\n"+"/"+(string)gChan+" hide text をダイアログを閉じてから行ってください。";
        dMsg = gDialogMsg+"("+(string)(currentPage+1)+"/"+(string)(maxPage+1)+")"+"\n"+gDialogMsg2+"\n"+gDialogMsg3;
        llDialog(gToucher,dMsg,buttonList,gChan);
        llSetTimerEvent(0.0);
        llSetTimerEvent(gInterval);
    }
    state_exit()
    {
        llSetTimerEvent(0.);
    }
    timer()
    {
        if (llKey2Name(gToucher) != "") {
            llInstantMessage(gToucher,gMsgTimeout);
        }
        state wait;
    }
    listen(integer channel, string name, key id, string message)
    {
        if (llListFindList(fixedList,[message])!=-1) {
            buttonList = [];
            if (message == "Next >"){
                if (currentPage+1 > maxPage) currentPage=0;
                else currentPage = currentPage+1;
            } else if (message == "< Prev") {
                    if (currentPage-1 < 0) currentPage=maxPage;
                else currentPage = currentPage-1;
            } else if (message == "Close") {
                state wait;
            } else if (message = "RESET") {
                llResetOtherScript("dialogMgr");
                state wait;
            }
           
            buttonList = fixedList + llList2List(contentList,currentPage*9,(currentPage+1)*9-1);
            gDialogMsg2 = "登録曲数 "+(string)gCount+", "+"ダイアログチャンネル: "+(string)gChan;
            dMsg = gDialogMsg+"("+(string)(currentPage+1)+"/"+(string)(maxPage+1)+")"+"\n"+gDialogMsg2+"\n"+gDialogMsg3;
            llDialog(gToucher,dMsg,buttonList,gChan);
            llSetTimerEvent(0.0);
            llSetTimerEvent(gInterval);
        } else if (llListFindList(contentList,[message])!=-1) {
            llSetParcelMusicURL(llList2String(urlList,llListFindList(contentList,[message])));
            llSetText(message,<1,1,1>,0.8);
            state wait;
        }
    }
単純といえば単純ですが、、、なんらかのご参考になれば幸いです。

[追記]
最初にものすごく悩んで、今は普通にやっていることを書き忘れました。
llDialog が使用するチャンネルについてです。

5) llDialog が利用するチャンネルは決めうちにしないほうが良い場合が多い

ダンスボールや、音楽玉、ビデオ玉を作り始めのころに、ダイアログの混線の問題がありました。
たとえば、自分の作ったダンスボールを複数 Rez したとき、llDialog が利用するチャンネルを決めうちにしている場合は、それら Rez したダンス玉を交互に操作するとダイアログ・チャンネルの混線が発生します。
llDialog って、結局は llSay でいうことを代わりにやってくれているようなものなので、それぞれのダイアログの返答がどのダイアログからきているかを判定するもの(値)がないんです。
よって、それぞれのダイアログを判定する方法は、llDialog で使用するチャンネルを変える事になります。
私は llFrand を使って、ランダムにダイアログのためのチャンネルを Rez や初期化時に生成して利用するようになりました。
絶対同じものにならない、、、というわけではありませんが、同じオブジェクトを複数 Rez しても、それぞれのダイアログが利用するチャンネルが違う確率が高いので、この方法をいつも無意識に使うようになりました。
以下のようなユーザー関数を使って、ランダムに生成されたチャンネルを使います。
これは 1000 から 9999 までのランダムな数字を作る例です。

integer randChan() {
    return 1000 + (integer)llFrand(8999);
}

llFrand(8999) によって、0 から 8999 までの間の数字がつくられます。 0 が作られたら、それに 1000 を足したもの、つまり 1000 が返され、8999 だったらそれ1000を足した 9999 が返されます。
もちろん、これをマイナスの値にしてあげれば、さらに良くなりますね。