2008年5月21日水曜日

セカンドライフのアニメーションを操る その7

これでシリーズ最終回 (笑) でしょう。

MLDU (Massive Link Dance Unit) のベンダー販売に最後まで躊躇したものは前の投稿でちょっとご紹介した「ラグのときのノートカードの読み込み」でした。

アニメーションを操る、、、という件名との関連性が薄い話題なのですが、ノートカードによるダンス記述は MLDU では欠かせないものだったということと、llHTTPRequest といった関数を使った外部サーバー、サービスからのデータ読み込み・書き込み方法 (Sine Wave AO 1.2 方式ですね) を除けば、ユーザーさんが唯一データの追加・変更をして、スクリプト・リセットしてもそのデータを再度使うことができる、、、というものなのでご紹介させてください。

ダンス・アニメーションの再生の順番やその再生時間を MLDU ではユーザーがノートカードに記述して保管しておきます。スクリプトはノートカードを読み込み、その情報を LIST に格納して、その順番で llStartAnimation を開始し、llSetTimerEvent には該当する秒数をセットしてタイマーをかけます。
timer() イベントが発生したら、LIST の次の項目のアニメーション名と秒数を使ってアニメーションを開始し、それまで動いていたアニメーションを止める、、、この繰り返しです。

ダンス記述ノートカードは1枚ではなく複数枚利用でき、MLDU 3.2 のデフォルトは 5 つのダンスセットを準備し、リセットすることなしに即時にダンスセットを切り替えることができます。ダンス記述ノートカード1枚につき、1つのスクリプトが割り当てられています。これはより多くのメモリーを利用したいためでした。

0

それぞれのダンス制御スクリプトはノートカードの読み込み時に指定されているダンス・アニメーションが本当にあるかどうかを llGetInventoryName を使ってチェックします。llStartAnimation / llStopAnimation の時に Avatar がいない場合エラーになることをご紹介しましたが、アニメーションが無い場合も当たり前ですがエラーになります。

意外にタイプミスが多かったり、半角スペースが2つ入っているのが本当の名前、、、などがあります。エラーの場合はどのダンスアニメーションがエラーになっているかを llOwnerSay を使って表示します。ダンスアニメーションを記述する際には、アニメーションのプロパティを開いて名前の部分をマウス・ドラッグでマーキングして、Ctrl+C でコピーし、ノートカードに Ctrl+V で貼り付けるのが一番確実ですね。

ダンス制御スクリプトをシーケンシャルにリセットしたい
このダンス制御スクリプトも含めたすべてのスクリプトを制御する親スクリプトがあります。
MLDU3.2 デフォルトだと、この親スクリプトが1本、ダンス制御スクリプトが6本、ダンススロットスクリプトが 15 本の計 22 本のスクリプトが llMessageLinked を使って連携するわけですが(ちなみに雷神の MLDU はその倍の数、、)、全スクリプトのリセットは親スクリプトからの llResetOtherScript により行っていました。

実は、この llResetOtherScript は、指定したスクリプトのリセットが終わるまで処理を待つことなく、次から次へとリセットをかけることが可能なんです。というか、、、リセットしてね~、を投げっぱなし、、、、というか、、、
for 文などでまわすと、どんどんリセットがはじまります。
ここにノートカードを読み込む llGetNotecardLinedataserver イベントが非同期処理的に複数動き始めるわけですから、、、

これも、普通(何をもって普通、、、というか難しいですが、、、)はどんどんノートカードを読み込んで、アニメーションの存在チェックをしていくのですが、クラフターズカップなどが開催されてプリム数やスクリプトがSIMに多くなっている状態の雷神などはスクリプト・リセット時にノートカードが読めなくなり、エラーになることもしばしばありました。
親スクリプトによる全スクリプト・リセットを使わず、ダンス制御スクリプトをひとつひとつリセットしていくことで回避はできたのですが、これも、、、美しくないですよね、、、。
この「順番にスクリプトのリセットをかける」は、あまり難しくないように思われる方もいると思いますが、なにを悩んでいたかというと、MLDU の基本コンセプトは「スクリプトを動的に追加可能にする」だったんです。

たとえば、ダンススロットを 15 から 30 に増やしたい場合は、danceSlot というスクリプトをプリム内のコンテンツフォルダーに追加分をコピー(ドラッグ&ドロップ)するだけ、、、ダンスセットを増やしたければ、ノートカードとダンス制御スクリプトをコピーするだけ、、、というものです。

親スクリプトはいったい自分がいくつのスクリプトを管理するかは、、、決めうちじゃなく、動的にとれるようにしたかったんです。

これは、、、いろいろなやり方があるとは思いますが、最終的に私がとった方法は以下でした。

1) 親スクリプトは子のスクリプトのリセットをかける前に llGetInventoryName  と  llSubStringIndex などを使って、ダンス制御スクリプトの数を取得します。ダンス制御スクリプトは SynchManager という名前でコピーしていくと SynchManager 1,  SynchManager 2 と連番が振られますが、必ず SynchManager という文字列は含みますから、それを拾うわけですね。

2) その数ぶんだけ、親スクリプト内の slotStat という名前の List に "1" を入れます。6つあれば ["1","1","1","1","1","1"] となります。

3) 親スクリプトは llListFindList を使って "1" を slotStat から探します。

4) 一番はじめは 0 (つまり、一番最初)が戻り値としてくるので、0 の場合はなにも付け加えずに synchManager をリセットします。

5) 子スクリプトのダンス制御スクリプトはリセットが完了したら、llMessageLinked を使って、「正常に完了しました」 というメッセージと、自分の名前についている番号を投げます。番号がないときは 0 を投げます。

6) 親スクリプトは「正常に完了しました」をうけとったら、同時にもらった番号を index として使って、slotStat の中の "1" を llListReplaceList を使って "0" にします。そして、もう一度上記の 3) に戻って "1" を探します。その後は 3) ~ 6) の繰り返しです。

これで順次スクリプトリセットを可能にしてみました。途中でエラーが起こった場合はこの処理は止まります。ええ、とまっていいんです。そこは割り切りました。それでも上述のコンセプト的には80点はとれるんじゃないかなぁ、、、と、ちょっと自画自賛(笑

ちなみに、、、フリーのものも含めて、同じようなダンススクリプト、同期ダンススクリプトのソースは一度も見たことがありません。(というか、探せなかった?)
なので、上級者(プロ)の人にしてみればかなり「原始的」な処理もあると思います。ただ、半年以上のテストを比較的多くの Avatar が集まる、状況の厳しいクラブ雷神で続けてきた結果、まだまだ改善の余地はあるものの、エラーはあまり発生しない同期ダンス制御ユニットになったのかなぁ、、、と思います。
私にとっても、実践的な LSL ということで、とても勉強になりました。
クラブ雷神 : たぶん世界で一番クールなダンスを踊れます(笑
Snuript Library : MLDU 3.2 うってます。でも ネトラジ・チェンジャーが一番おすすめ(笑
[追記: 現在 MLDU は OEDO City SIM の Studio4D さんのお店にベンダーを設置しています]
このブログ「シリーズ」を書こうと思ったのは、実は、、、ダンス制御ユニットのパーソナル版を作ろうとしていて、ちょっとアイディアにつまったからでした。(笑
パーソナル版でやりたいことがこのブログを書く過程でだんだん固まってきたので、、、、お楽しみに。
でも、完成まではまだまだ先は長そうです。スクリプトって、どうしても売るの躊躇するんですよね、、、。

2008年5月19日月曜日

セカンドライフのアニメーションを操る (番外編)

512 日記念(?) ということで Sine Wave Island で女性用、男性用のダンス・アニメーションがフリーで配られていて、大変な混雑になっています。

0

SIM に入るのも大変なのですが、SIM に入った後でアニメーションを受け取るのも大変です。
単純に SIM が重い、ラグだからなのかな、、、と思ったのですが、、、どうもスクリプトに問題ありそうな気がします。

インベントリの中をちょっと見てみました。
1 

配るダンス・アニメーション・ファイルが2つと、1つのスクリプトが入っています。プリムはリンクしていないようですから、このスクリプトのみだと思います。
たまたま運よく weloveyou-girl の(というか、girl しか手に入らなかった・・・)ダンスを貰うことができましたが、そのダイアログの流れは以下、、、、
1) タッチしても反応しないときが多く、根気強くがんばると以下のダイアログが表示されます。
2
Male (男性)用、Femal(女性)用のどちらがよい?と聞いています。
2) 好きなほうのボタンを押すと、しばらくして以下のダイアログが表示されます。
3
もちろん、[維持] を押します。これでしばらくするとインベントリにアニメーションファイルが追加されます。

プリムのコンテンツフォルダには1つのスクリプト、そして上記の流れ、、、多くのアバターが一斉にクリック(Touch)、、、場合によっては誤動作を発生させる、処理がたまる可能性があるスクリプトではないかと思います。

事実、Female をもらったあとで何度 [Male] を押しても [Female] しかもらえなかったり、、、(おかげで、、、weloveyou-girl が8個も、、、)

たぶん、llDialog を使わず、単純に男性用のアニメーションを配るベンダーと女性用のアニメーションを配るベンダーにしてしまったほうがよかったのだと思います。上記 2) だけであれば、スクリプトいらずで、料金を 0L$ にするだけでいいわけですからね。
SIM に 40 の avatar がやってきて、一斉にあるパネルをクリックしている状況なんてなかなかないですから、、、ただ、こういう状況が想定される場合の touch_start と llDialog はちょっと注意しなくてはいけません。

touch_start イベントではタッチしたアバターの数をうけとることができます。 integer total_number がそれにあたります。

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

だれがタッチしたかを知るためにおおよそ llDetectedKey(0) とやりますが、これって最初に触った人、、、最初???と思われるでしょうし、ほとんど llDetectedKey(0) で問題ないのですが、こんなに一斉にタッチされるとなると、、、タッチを無視されるアバターも相当発生してしまいますね。つまり llDetectedKey(1) や llDetectedKey(2) は存在するのです。

touch_start(integer total_number)
{
     llDialog(llDetectedKey(0), "Hi, let us know what", ["Male", "Female"], 12345);
     llSetTimerEvent(10.0); //タイマーでのキャンセルもやってないような・・・
}

こんな感じなのかなぁ、、、
やるなら

touch_start(integer total_number)
{
    integer i = 0;
    for (;i<total_number;i++)
    {
       llDialog(llDetectedKey(i), "Hi, let us know what", ["Male", "Female"], 12345);
    }
}

これでその瞬間にタッチしたアバター全員にダイアログを投げる処理になります。
そして、Dialog の返信をうけとって処理する Listen のイベントは、上記のサンプルより チャンネル 12345 しか聞いていないとすれば、

listen(integer channel, string name, key id, string message)
{
    if (message == "Male")
    {
        llGiveInventory(id, "weloveyou-boy");
    } else if (message == "Female")
    {
        llGiveInventory(id, "weloveyou-girl");
    }
}

とにかく、message の Male/Female を判断して、無条件に llGiveInventory を使ってダイアログの返信をくれた id に対してファイルを投げる、、、
うわぁ、、、なんかキューにたまりそう・・・・

チャットの遅延って混んでいる SIM ではよく見かけるし、、、この場合遅延があっても大丈夫でしょうが、、、

で最終的には、、、boy もゲットしましたが、、、、その場である Avatar が「Someone has the dance girl? I have the boy.」(だれか girl 持ってる?私は boy を持っているんです)といっていたので、girl と boy を交換しました。(笑
配付されているアニメはコピー可なんです。
ですから、、、、今は持っている人からもらうのが一番かも。もうしばらくすると落ち着くとは思いますが。。。
それにしても Sine Wave 、、、すごい人気ですね~。

2008年5月18日日曜日

セカンドライフのアニメーションを操る その6

シリーズものも第6回になってしまいました。(笑

こんなことしたい~、を実現するスクリプトはすぐに作れたとしても、前回書いたようにエラー処理や例外処理みたいなものをどんどん追加していくことになるんですよね。

まぁ、最初からそれらを入れて、、、というのが本来あるべき姿なのでしょうが、どんなことがおこるかその時は(今でも?)わかっていませんでしたから、雷神で何か問題があれば LINZOO さんから連絡をいただき、対処する、、、ということが数か月続いたわけです。

エラー処理、例外処理、メモリが足りない、、、

根本的にロジックがおかしい、、、というのはダメダメだとして(笑)、MLDU で私が経験させてもらった代表的なものは以下です。

1) llStopAnimation しようにも、Avatar がいない、、、

その SIM に Avatar がいない状況で Permission を持っているスクリプトが llStopAnimation を使ってダンス・アニメーションを止めようとするとスクリプト・エラーが発生します。「びょ~ん」とあのエラーマークがプリム上に現れます。

 0

このマークはそのうち消えてしまうのですが、どうにも美しくないですよね。
センサーを使って確認する、、、なんて、最初考えたのですが、、、センサーリピートでぐるぐるまわす、、、それもどうかな、なんて考えていたらお友達からヒントをもらいました。
その Avatar が SIM にいないと本来機能しない LSL の関数、さらにエラーにならず、「いない」ということを戻り値として返してくれる関数、、これを聞いて「あっ!」と気がつきました。

llKey2Name です。[2009.5.19追記:こちらを参照ください]

llStopAnimation の直前に llKey2Name を使い、もし戻り値が NULL だったら llStopAnimation をぜずに、llRequestPermissions を行ったスクリプトを初期化して、他のアバターに使わせるようにすることでスクリプト・エラーを回避することができました。

2) ダンス・アニメーションをコンテンツフォルダーに入れられない、、、

MLDU の基本的な仕様はダンスを自由に操る、、、だったので、プリムのコンテンツ・フォルダに入れられたダンス・アニメーションは LIST に読み込むようにしていました。
ところが、LINZOO さんの所有しているアニメーションの数は 100 どころか 200 近く、、、よく使うアニメーションだけに絞ったとしても、たとえば「スローダンス・セット」、「グラマラスダンス・セット」などなど、1 セットに 20 前後のダンスを登録して、それが6セットとかになると 120 ものダンス・アニメーションをいれることになり、さらに新しいアニメーションを追加、、、、となると、、、

もともと、このエラーの原因になっていたのは、すべてのアニメーションを順番に固定の再生時間で動かす、というモードのためでした。しかし、LINZOO さんの使い方だとほぼいらない仕様だということ、さらに順番に動かすのであれば LIST にアニメーション名を入れる必要がない、ということから以下のような方法にしました。多くのダンス・アニメーションのスクリプトは、この方法が多いかもしれません。

- llGetInventoryNumber(INVENTORY_ANIMATION) でアニメーションの数を取得
- llGetInventoryName を使って 0 から取得したアニメーションの数-1まで順番にアニメーションの名前を取り出して、llStartAnimation にわたす
- timer() では上述の llKey2Name を使ってアバターチェックをした上で llStopAnimation/llStartAnimation を行う

全ダンスモードはこれでメモリー不足のエラーを回避できるようになりました。ダンスセットのノートカードに多くのダンスが記述された場合は上記の方法では対処できませんが、ノートカード読み込みの時に llGetFreeMemory を使い、メモリーが足りなくなりそうになったら警告を出すようにして、ノートカードの読み込みを中断するようにし、エラーを回避するようにしました。

3) アニメーションのつなぎでダンスがとまり、アバターが棒立ちになる、、、

この原因はスクリプトのせいだけではありません。アニメーションが SIM や PC にキャッシュされることで、つなぎがスムーズになることがほとんどなのですが、この「アニメーションのロード時間」というものは少なからず発生します。これが「棒立ち」の原因です。
アニメーションがキャッシュされていない時の「棒立ち」を回避する方法、、、これ、ある条件の下ではあるんです。

もし、利用するダンス・アニメーションの「優先順位」がすべて一緒ならば、、、、以下の方法がベストでした。

- llStopAnimation の前に、次に開始するアニメーションを llStartAnimation で開始する
- llSleep でスクリプトをちょっと止める
- llStopAnimation で「前の」アニメーションを止める 

キャッシュされれば llStartAnimation で指定したアニメーションがすぐにはじまり、キャッシュされていない状況だと、その前のアニメーションが動いている、、、、
これ、良いアイディアだったのですが、、、はまりました。

キャッシュされる前のロード時間は長くても 5 秒くらい、、、ということで当初は llSleep で 5 秒を指定しました。これにより棒立ちは回避されたように見えました。
ところが、あるダンスの動きが予想しているものと違う、、、という話しがでました。
そこで前回ご紹介した「現在動いているアニメーションの表示方法」を使って確認してみると、、、優先順位が低いアニメーションがあるではありませんか。。。それも、、、OWENIMATIONS のものが優先順位 3 だったり、、、他のショップのものは 4 のものが多いのです。

これだと、動かすべきアニメーションがキャッシュされても、その前に動いていた優先順位の高いもののほうが常に 5 秒長く動くので「あれれ?」という動きになるわけです。
5 秒は長すぎ、、、ということで 0.5 秒くらいにしています。Stop-Start よりも Start-Stop のほうがロード時間を少しでもカバーできるのは確かです。llGetAnimPriority みたいな関数があればいいのですが、、、(笑

4) 使えるメモリーがどんどん少なくなる、、、

このようにエラー回避処理、メッセージの追加、メッセージの日本語化を行っていったら、どんどんアニメーション・リストのために使いたいメモリーが少なくなってきました。(= Stack-Heap Collision エラーが出やすくなってきた、、、です。)
以前に投稿しましたが、劇的にメモリーの節約になったのは以下の方法です。

- メッセージは直接日本語入力をする (以前の投稿はこちら) あと今ならこちらの方法も参考に
- llMessageLinked の引数の key の指定で NULL_KEY を使っていたところを "" にする (以前の投稿はこちら
- List 操作の関数を使うときは一度 LIST を空にしてから代入する (以前の投稿はこちら

MLDU を作って良かったのは 16KB というメモリのサイズを意識するようになったことと、そして、ロジック上可能であれば、スクリプトをわければよい、ということを学んだことでしたね。

エラーがでちゃうと迷惑をかけてしまうので、MLDU は対面販売のみ、、、としていたのですが、今はベンダー販売をしています。最後の最後までベンダー販売したくないなぁ、、、と思っていた例外処理の対応ができたからでした。
Snuript Library ***SUZAKU***, SUZAKU (113, 230, 27)
[追記 2008.11] 現在は OEDO CITY の Studio4D さんにベンダーをおいています
Studio4D Dance Animations のブログ
ラグ(SIMが重い、動きが遅い状態)のときのノートカードの読み込み、、、この対策ができたのが、ベンダー販売をしてもいいかな、と思った最後の対応でした。
つづく?(笑

2008年5月14日水曜日

セカンドライフのアニメーションを操る その5

その5、、、です。ちょっと小難しいスクリプトの話が続いたので、今回はアニメーションそのもののお話になります。(笑

MLDU1 and 2 (Massive Link Dance Unit version1 and 2)  ができたのは、LINZOO さんに「作ってみるー」と言ってから結構早かったんです。
ダンススロット(同時に Avatar が踊れる数)は 50 越えで、踊るダンスの組み合わせのセットは3つ、オーナーにはダイアログが表示されて、ダイアログのボタン操作でダンスセットを切り替え、アバターが踊っているダンスを変更する、ノートカードにダンスの順番、それぞれのダンスの再生秒数を指定する、、、など、現在の MLDU3 の基本仕様(というか、LINZOO さんの要求w) を含んでいました。

そのときのテスト模様は、、、こちらにあったり

0
雷神を使った MLDU テスト。この時、同期ダンス 50 人を達成しました。

が、LINZOO さんから一言。「ダンスセット、3つじゃ足りないなぁ~」(笑

MLDU1 and 2 は1つのノードカードにタグ形式でセットを記述するタイプでした。
こんな感じ、、、

<Set1>
10.0, dance1
12.0, dance2
.....
.....
.....
8.0, dance3
</Set1>
<Set2>
18.0, dance4
....
....
10.0, dance1
</Set2>
<Set3>
8.0, dance3
16.0, dance5
....
....
12.0, dance2
</Set3>

なので、本当に安易にこのノートカードにダンスセットを追加していきました。
でも、、、LINZOO さんの持っているダンスアニメーションの数が、、、半端じゃなかったんです。
そのときで 200 以上は持っていて、、、当然ノートカードの項目も長くなります。
なので、スクリプトのメモリーが足りなくなってノートカードが読めなくなったんです

アニメーションを操る、、、という意味でいうと、ノートカードに順番を入れるのはともかく、なんで秒数までいれるの?と思われる方も多いと思います。おおよそダンス・アニメーションとセットで配られているアニメーション再生スクリプトは 20秒から30秒くらいの「固定間隔」でダンスを切り替えます。これでも十分楽しいのですが、LINZOO さんがこだわったのは「ダンス終了後の立ち位置と、次に開始されるダンスの立ち位置の違い」でした。


高品質ダンス・アニメーションは開始位置と終了位置が一緒

フリーで配られているダンスの中にもすばらしいものもありますが、とくに Latin (ラテン) ダンス系のフリーものはダンスの開始位置と終了位置が大幅にずれているものがあります。ダンス・アニメーションはループアニメーションとして登録されている場合がほとんどなので、そのアニメーション単体を試してみるとすぐにその「不自然さ」がわかると思います。

最初、ラテン、サルサといったダンスはどうしても移動するので仕方ない、、、と思っていました。でも、ショップの有料ダンス・アニメ (ほとんどが 150L$ ~ 300L$ ですね) を見ると、、、これが見事に一致して、さらにはじめからループすることを見越して作っているようで、ループしても「切り替わった」ということを意識させないつくりになっています。
ですから、本来アニメーションがもっている「再生時間」を使ってダンス・アニメーションをつなげていくと、多くの場合は「基点」に戻るのでスムーズにダンスがつながって見えるのです。
せっかく基点にもどってきているのに、一定間隔で無造作に切り替えると台無し、、、というわけですよね。

また、開始位置と終了位置が違うものでも、もし、ダンスの移動中に開始位置に近い場所にくることがあれば、その時点でダンスを切り替えるとスムーズにダンスがつながってみえるわけです。

ただ、この作業、、、現在手作業でしかできませんね~。 LINZOO さんはストップウォッチ片手に計測しているみたいです。
llGetPos() を使って同じ位置近くにくる時間を自動的にとる、、、なんて最初考えましたが、アニメーションで動いているように見えても、実は Avatar の位置って、もともと立っていた位置の Vector 値を返します。スポットライトのスクリプトでアバターを追いかける、、、なんてのも、アバターを動かして歩いているのであればいいのですが、アニメーションによる動きだともともといた場所しか返さないので追いかけることができなかったりします。
このダンスの長さの情報、、、実はショップによってはきちんと公開しているところもあります。

Animazoo の場合

Animazoo は プロパティの Description にいろいろな情報があります。以下のようなものです。プライオリティ(優先順位)と秒数(赤字)が書かれています。
[Animzoo animations - Animazoo dance 25.0 - priority 3 - easing 1.0 - 9.15s l Chevvie dance 15.0]
[Animzoo animations - Animazoo dance 22.0 - priority 3 - easing 1.0 - 11.4s l Chevvie dance 8.0]

Sine Wave の場合

Sine Wave の場合は Animazoo のようにプロパティの Description に情報がないので大変、、、だったのですが、最近ものすごいことになっています。Sine Wave が配付している AO1.2 で Sine Wave の Web サイトと連携するようになりました。 Sine Wave AO 1.2 を Wear した状態で「/1 activate」とチャットすると Sine Wave Web サイトの自分専門の Page のリンクが Say されますので、それをクリックすることでそのページが開きます(最初はパスワードとかのセッティングが必要です)。

ページには Sine Wave が販売しているダンス・アニメーションのリストがあり、かつ、AO 1.2 に入れたダンス・アニメーションにチェックが入っていて、それぞれのアニメーションの時間まで、、、、Web 上で確認できます。(ただ、、残念ながら PlayList の使い方を把握しきれていないので、、、このサイトの使用はダンス・アニメーションの時間の確認のみですが、activation した上で AO を使うとそれぞれのダンス・アニメーションの再生時間はもっとも最適なものになっているのがわかります。)
0

OWENIMATIONS、Abranimations の場合

情報ないのでストップウォッチで計測するしかみたいですね、、、
と、ノートカードによるダンスセットの記述は手間がかかるものの、ダンスがスムーズにつながったり、曲調にあわせてダンスが切り替わるのを見ると時々「ぞくっ」とすることがあるくらい、綺麗に見えます。

万人向けじゃない、、、ですが、クラブでより多くの人に楽しんでもらいたい、と考えると、LINZOO さんの無茶な要求もわかるというもの、、、です。
話は戻って、、、メモリー不足への対応ですが、1枚のノートカードの情報を1つのスクリプトで読みきれないのであれば、ノートカードとスクリプトをそれぞれ分ければいい、、、とすぐに思いつき、それをやってみたわけです。それが MLDU2 となって LINZOO さんにお渡ししたわけです。

が、、、スクリプト、LSL 的には、ここからとっても勉強させられることになります。
とにかく、、、メモリが足りない、ノートカードにそれほど多くの情報がないのに Heap/Stack エラーになる、ちょっとでも SIM が重い・ラグな状態になるとノートカードの読み込みができない、、、、などなどに対応していくことになりました。。。
続く・・・かなぁ、、、(笑

2008年5月12日月曜日

セカンドライフのアニメーションを操る その4

アニメーションを操る、、、ということでシリーズもの(?)になってしまいました。
前回からの続きです、、、

LINZOO さんお得意の「つぶやき」にまんまと引っかかり(笑)、でも、今考えると本当に「安易」にダンス玉を作るといってしまった、、、と思います。

同期ダンスの仕組みはおおよそ予想がついていました。ちょうど大運動会のイカロス順位表示スクリプトを作ったので、メッセージを使ったスクリプトの連携などをすでに経験していました。なので、当時のエントリにもあるように llMessageLinked で「これ踊って~」というメッセージを投げ、それを複数のスクリプトが拾って llStartAnimation を Avatar に対して行う、この繰り返しでしょう、、、くらいの理解でした。

ビデオ玉音楽玉もすでに作っていたので、複数の人がひとつのスクリプトを利用する問題点と対応方法、ダイアログの使い方、ノートカードの読み込ませ方などもある程度わかっていたつもりでした。

0
当時のビデオ玉のダイアログ

スクリプトでアニメーションを操作して、アバターにダンスやポーズをさせる場合、Permission が必要だという話しはすでに書きましたが、この permission 、、、ちょっと危険な香りがする function なんです。それと (複数の人を対象としたダンス・スクリプトとしては、、、逆にかなり難しいですが) 複数の人がひとつのスクリプトを使った場合の llRequestPermissions の動きって、ちょっとトリッキーなんです。すぐに気がつきましたが、アニメーションを操る上では理解しておかないといけないポイントがいくつかあります。


llRequestPermissions... 許可をするときは覚悟が必要?(かも)


llRequestPermissions を使ったスクリプトは実はこれが初めてではありませんでした。はじめて llRequestPermissions を使ったのは「詐欺スクリプト」を検証してみた時だったんです。

詐欺注意 2007年6月23日の投稿です。

お金に絡む Permission の場合はダイアログが黄色になる、、、みたいな改善がその後行われてきましたが、いずれにせよ、この llRequestPermissions によるいくつかの制御の許可 (自分たちにしてみれば制御権限の委譲) は結構慎重にならなくてはいけないのかもしれません。

たかがダンス、、、といっても、スクリプトの書きかたが十分でないと、、、ダンスがとまらない、、、なんてことになっちゃうんです。


ポイントを以下に列挙します。
1)llRequestPermissions でスクリプトが取得した「許可」は一番最後に許可したアバターのもの (許可を受けとったもの) だけが有効。それ以前に許可した人については忘れてしまいます。(笑

2)「アバターに動きをつける」というダイアログの意味はアニメーションを開始させる、のほかに「アニメーションを停止させる」の意味も含みます。

3)上記からアバターのアニメーションの「開始」「停止」の両方を制御するためにはダンスするアバター分のスクリプトが必要になります。(実はそれだけではなく、llSetTimerEvent と timer() を使うのであれば、個別にスクリプトを用意する必要があります。)

4)停止方法が明記されてなくてもメニューの「ツール」-「アニメーションをすべて停止」からダンスアニメーションを止めることができます。しかし、それは自分のビュワーで止まって見えるだけで、他の人のビューワーでは動いて見えています。アニメーションの処理はそれぞれのクライアント・ビュワーでの画像処理になっているようです。

5)「許可をするときは覚悟が必要」もしくはスクリプトを書くときに注意しなくてはならない理由は、一度もらった(与えた) llRequestPermissions への許可は、スクリプト・リセット、そのスクリプトが無くなる、もしくは SIM リスタートによる SIM の全スクリプトのリセット以外に取り消すことができません。

6)ダンスアニメーションの場合のほとんどは llStartAnimation / llStopAnimation を llSetTimerEvent を使って何度も開始させています。ですので、上述の4)の方法でダンスを止めても、また、ログインしなおしても、そのスクリプトが「許可」を保持し続けている限り(きちんとしたエラー処理をすればするほど)スクリプトによる「アニメーションによる制御」がスクリプトリセットまで続きます。

7)この状態になってしまったら、プリムと同じ SIM にいる時は、ほとんど「奴隷」状態です。。。(ローリング・リスタートの有難みが・・・)
Permission については、以下のスクリプトを試してみるとわかると思います。試す場合はダンスアニメーションをスクリプトがあるプリムのコンテンツ・フォルダにドラッグ&ドロップして、以下のスクリプトの "Clube Dance 4" を該当するアニメーションの名前にしてくださいね。

key avatarKey; //プリムにタッチしたアバターの Key を格納するための key 変数宣言
default
{
    state_entry()
    {
        llSetText("",<1,1,1>,0);
        integer handle = llListen(0,"",NULL_KEY,""); //あえてオープンチャンネルの 0 を使ってます。
        llListenControl(handle, TRUE); //上記の Listen を開始します。
    }
    touch_start(integer total_number)
    {
        avatarKey = llDetectedKey(0); //タッチしたアバターの Key を取得します。
        llSay(0, "Touched by "+llKey2Name(avatarKey)); //タッチしたアバターの名前を Say します。
        // タッチしたアバターにアニメーションのパーミッションの許可を要求してダイアログを表示させます。
        llRequestPermissions(avatarKey, PERMISSION_TRIGGER_ANIMATION);                   
    }
    run_time_permissions(integer perm) //パーミッションのダイアログへの返信のイベント
    {  // もし返答が「はい」(許可する)だったら、
        if (perm & PERMISSION_TRIGGER_ANIMATION)
        { //プリムの上に現在パーミッションの許可をもらい制御可能なアバター名を表示
            llSetText(llKey2Name(llGetPermissionsKey())+" under control.",<1,1,1>,1);
            llStartAnimation("Club Dance 4"); //制御可能なアバターに対してダンスをスタートさせます。
        }
    }
    listen(integer chan, string name, key id, string msg)
    {  //この場合、オープンチャンネルの、そこにいる誰の発言でも、最初の 6 文字が /start だったら、
        if(llGetSubString(msg,0,5)=="/start")
        { // 発言した人が制御下にあるアバターのアニメーションを開始する、と言い、開始させます。
            llWhisper(0,llKey2Name(id)+" が "+llKey2Name(llGetPermissionsKey())+" のアニメーションを開始します。");
            llStartAnimation("Club Dance 4");
        } else if (llGetSubString(msg,0,4)=="/stop") // 発言の最初の 5 文字が /stop だったら、
        {  // 発言した人が制御下にあるアバターのアニメーションを停止する、と言い、停止させます。
            llWhisper(0,llKey2Name(id)+" が "+llKey2Name(llGetPermissionsKey())+" のアニメーションを停止します。");           
            llStopAnimation("Club Dance 4");
        }
    }
}

スクリプトを書く人は必ずアバターにアニメーションの開始・停止の機会を与えて、アバターが意図しないときに勝手にアニメーションを開始するようなことがないようにしなくてはいけませんし、利用するほうは、ダンスに限らず 「許可をする」系のダイアログの返信についてはよくよく考慮した上で返信([はい]を押す)をしたほうが良いでしょうね。

なので、海外に多い [Sit] タイプのダンスは安心ができる、、、と前の投稿で書きましたが、これはアニメーション停止の方法がわかりやすいだけであって、暗黙的ながらも上のスクリプト同様にパーミッションの許可を与えていますから、llSetTimerEvent を使った timer() によるアニメーション・コントロールをされてしまうと、、、、立ったにもかかわらずアニメーションが開始されてしまいます。

[追記] お金に関する PERMISSION_DEBIT はこの 「暗黙的許可」はありません。Sit しても Wear しても、今は黄色いおおきめのダイアログが表示されます。

と、、、パーミッションについてはこれくらいにして、、、(続く)

2008年5月10日土曜日

セカンドライフのアニメーションを操る その3

前回からの続きで「その3」になりました。
チャットキーボードの次は立ち姿の AO (Animation Override) を、、、と思ったわけですが、スクリプト以前にポーズというものが面白くて、QAvimator などを使って自分でポーズや短いアニメーションを作ってみたりしました。ポーズは Free のものでも相当の数、そしてなかにはクオリティが高いものが出回っていて、Secondlife を始めたころはひとつひとつ試してみたり、「その1」でご紹介したジェスチャに登録して使っていました。

アニメーションとポーズ、、、これは同じものなんですよね。
そのあたりは「ポーズは腰が命 全4回」(笑 や 「QAvimator って面白い」のエントリの中で紹介しています。 QAvimator の使い方、bvh ファイルの作成とアップロードの方法からわかってきました。

でも、自分の作ったポーズ(つまり、フレームを 2 つしか使っていないループアニメーション)って切り替えると「パッ!パッ!」とそのポーズになって、それが「不自然」ということに最初は気が付いていませんでした。それに気が付いたのが Maitreya のポーズを試してみたときでした。

MaitreyaPose21
Maitreya - CCRunwayPose21

それはポーズというよりも、立派なアニメーションでした。

これ、フォトだとまったくわからないと思いますが、「きめのポーズ」になるまでの体の動きがものすごくしなやかなんです。そして、数秒たったら、また違うポーズに変化する、、、、というものもありました。

アニメーションを操る、、、という意味では、 AO を設定し使うためのツールが提供されているのでまずはそれを使いこなすことですね。 ZHAO (もしくは ZHAO-Ⅱ) というツールが Secondlife では有名です。
ZHAO の使い方はいろいろなブログやサイトで詳細に説明されているので割愛しますがポイントは、

1) 地面上に ZHAO を Rez します。装着したままだとアニメーションをドロップできません。

2) 編集から ZHAO の [コンテンツ] フォルダを開き、購入したアニメーションをドロップします。

3) Empty や Default といった名前のノードカードがあるので、それを開いて AO させたいセクション(Walking や Standing)の直後にアニメーションの名前を書き込みます。アニメーションのプロパティを開いて名前をコピーしてノートカードに貼り付けるのがいいでしょうね。

4) 上記の設定が終わったら Take して、HUD として装着したら LOAD というボタン(もしくはダイアログのボタン)を押してノートカードを読み込ませ、アニメーションを有効化させます。

実は ZHAO ってあまり好きじゃなかったんです。それは、機能うんぬん、、、というより見た目でした。後でわかるのですが、ZHAO はいろいろな人、ショップがカスタマイズして提供しているので、それぞれ見た目は結構変わるんですよね。
でも、Secondlife をはじめた時に最初に見たのが以下の左側、、、
0
向かって右側のは Maitreya で配られている ZHAO です。最初に Maitreya の ZHAO を使っていたら、自分で AO 作ろうなんて思わなかったかもしれません。ちなみに ZHAO-ll だとダイアログを使ったメニューになっていますね。
とりあえず Standing のアニメーションだけオーバーライドさせたかったので、そんなに難しくないかも、、と考え、前回ご紹介した方法で作ってみようと思ったわけです。でも、そんな単純なものではありませんでした。(笑
(やっと本題?)

AO させるには Permission が必須

はじめて ZHAO を使った時 (もちろんスクリプトの中なんて見ません(笑)) まったく意識していなかったのですが、アバターに対してアニメーションをスタートさせるときはかならず llGetPermissions ([修正] ごめんなさい。許可をもらうのは llRequestPermissions です。)を使ってアバターから「許可」をもらわないといけません。
タッチしてダンスを踊るタイプのものだと以下のようなダイアログを見たことがあると思います。
1
「て・に・を・は」がちょっとおかしいですが、オブジェクト 'MLDU' がアバターを動かそうとしていますがいいですか? と聞いているわけです。([追記] 誤解ありそうな表現なので追記します。アニメーションをスタートさせることだけではなく、停止するにもこのパーミッションが必要なことから、animate you の部分は「(停止を含めた)動作をつける」という意味だと理解してくださいね。)

海外のダンスホールやクラブだとダンスフロアに配置されているダンスボールに Sit (パイメニューでは llSetSitText を使って "Dance" になっていると思います) するものが多くて、このダイアログってあまりみたことがありませんでした。ZHAO の AO も自分に「装着」しているのでこのダイアログはでません。

そうなんです。Sit もしくは装着しているとスクリプトは Permission をもらったとして処理し、このダイアログは表示しないんです。
でも、スクリプトの中ではきっちりと llGetPermissions llRequestPermissions が使われています。

この省略はとっても合理的だと思います。Sit でアニメーションが開始されて「やめたいな、止めたいな」と思ったときは Stand Up すればいいわけです。HUD や Dance Ring の場合は 取り外せば いいわけですよね。(llGetPermissions llRequestPermissions におけるダイアログ・タイプの注意点(恐怖?)は後日に・・・)
このとき作成した AO Ball (また、、、小さな玉でした、、)のソースを今みると、、、、ひどい・・・(笑

自分だけ、かつ、装着での使用なので問題ないのですが、run_time_permissions で PERMISSION_TRIGGER_ANIMATION がとれてなければ「また」llRequestPermissions をやっていたり、、、自分専用だからいいけど、、ちょっと公開するにはあまりにひどいので、、、ポイントだけ。
自分専用単機能 AO ボールのポイントは

1. attach(key id) イベントで id が NULL_KEY でなければ処理をします。NULL_KEY の場合は「はずされた」という意味です。
2. その処理では
a) for 文と llGetInventoryName(INVENTORY_ANIMATION, i) を使ってコンテンツフォルダにあるアニメーションの名前をすべてリストにいれる。
b) llRequestPermissions(id, PERMISSION_TRIGGER_ANIMATION) を使ってアニメーション開始の許可を id (装着している Avatar ) に申請する。
3. 装着の場合は暗黙的に許可が下りるので run_time_permissions(integer num) のイベントでは llSetTimerEvent を使って、0.1 秒や 0.2 秒といった間隔のタイマーをかける。
4. イベント timer() の中では
a) llGetAnimation を使って現在動いている Animation を取得
b) 現在の Animation が "Standing" だったら Override したいアニメーションの名前を List から llList2String で取り出す。
c) llStartAnimation を使ってアニメーションを開始する。
d) 上記 a)b)c) の処理のあと一定間隔後に、llStopAnimation で現在動かしているアニメーションをとめて、次のアニメーションを List から取り出し、開始させる。
e) "Standing" の状態でなくなったら、即時に llStopAnimation でオーバーライドしているアニメーションを停止する。

こんなところでしょうか。
当時の恥ずかしいスクリプトは、、、結構強引(無駄)なことをやっていたりしてます。
相当悩んだのが 4-d の「一定間隔後に止める」だったと記憶しています。llSetTimerEvent で 0.1 - 0.2 秒で timer() イベントを開始させる、というのは「続けなければならない」わけですから、llSetTimerEvent を使って 20 秒後にアニメーションを止める方法は 1つのスクリプトの中、1つのステート (State: 通常は default ) の中ではできないわけです。

今だったら、llResetTimellGetTime もしくは llGetAndResetTime を使うのでしょうが、当時はそれらを知らなくて、たとえば 0.2 秒ごとに timer() が呼ばれるなら、そこでカウントをとっていって、カウント数 X 0.2 が 20 以上になったら、、、みたいな処理をしてました。@@

状態監視については、ZHAO および ZHAO (改)などはもっと手の込んだことをしているようです。 ZHAO のソースは見ていませんが、どうやら llGetAgentInfo や llGetAnimationList のほかに control などを使って状態を監視しているようです。

これで、Permission の取得とアニメーションの開始、停止の基本ができたので、ははん、、、これでダンス・アニメーションを扱うスクリプトも書けるかなぁ、、などと「安易に」ぼんやり思いながら クラブ雷神で踊っていたら LINZOO さんの「10人でいっぱいになっちゃう同期ダンスユニットはねぇ、、、もっとたくさんのひとが踊れるのほしいよね」という言葉を聞いて「作ってみるー」と言ってしまったのでした、、、。
続く、、、え?まだ続くの?笑)

2008年5月8日木曜日

セカンドライフのアニメーションを操る その2 (でしょう、、

前回の投稿でチャットキーボードを作ることでスクリプトによるアニメーション操作を意識した、、、と書きましたが、チャットキーボードをつくった当時は「意識」しただけで、スクリプトが何をやっているのかほとんど理解していませんでした。(笑

チャットキーボードはアニメーション理解の原点(かな?)

チャットキーボード、、、チャットをしているときにアバターがキーボードをタイプするような動き(アニメーション)をするわけですが、せっかくキーボートをタイプしているような動作をするなら、キーボードだしちゃえ!っというのが出発点で、そのうちタイプしているアニメーション自体を変更(このアニメーションの変更を Animation Override (AO: アニメーション・オーバーライド)といいます)して違う動きにしちゃおう、などなど、本来提供されている動き・アニメーションをもとにいろいろなカスタマイズができちゃうわけです。

キャット・ウォークとかセクシー・ウォーク、つまり、飛んだり、走ったりするアニメーションを違うアニメーションに入れ替える AO も、基本このチャットキーボードの仕組みと同じものです。一番はじめにこの単純な「チャットのアニメーション」を利用・変更するということにトライしたのは、今考えると最初の入り口としてはとても敷居が低くてよかったんでしょうね。

ちなみにそのとき作ったチャットキーボードは以下です、、、
0

この時、同じ「アニメーション」でも「テクスチャ・アニメーション」というものの存在を知りました。黒の背景に緑の文字がばらばらと流れるものをこのテクスチャ・アニメを使って作りました。簡単に言うと、プリムに貼り付けるテクスチャも アニメーション GIF みたいに「動きがある」ものを使うことができて、それをスクリプトの llSetTextureAnim でコントロールすることができるんですよね。llSetTextureAnim も実は奥がとっても深くて、それだけで結構ながーいエントリになるかもしれません。アニメーションだけじゃなくて、たとえば瞬時に画像を切り替えたい場合などは llSetTexture で個別の画像を切り替えるより、llSetTextureAnim と使用する複数の画像を一枚にしたものを使うと、画像切り替え時に灰色になることを避けることができたりします。もちろん、、、画像サイズにもよりますが。

(脱線、脱線、、、)話しを戻して、、、


チャットキーボードのときに参考にさせてもらったのが以下のスクリプトでした。
赤のテキストは私の補足です。
// the first free keyboard script
// by nonnux White
// free to mod, sell, erase, explode, burn :)
list anims = []; //その時点で動いているアニメーションをすべていれる空のリストを宣言
default{
    state_entry() {
        llSetTimerEvent(.2);  //0.2秒の感覚で time() を動かす=動き続けます!
    }
    timer() {
        // オーナー(使用者)の動いているアニメーションすべてを anims リストにいれる
        anims = llGetAnimationList(llGetOwner());
// "c541c47...." というアニメーションが anims リストの中にあったら...
        if(llListFindList(anims,[(key)("c541c47f-e0c0-058b-ad1a-d6ae3a4584d9")]) != -1)
        {
// このスクリプトが入っているオブジェクト上に表示されているテキストを(この場合は)空にして
        // リンクされているオブジェクトのすべての面を表示する(Alphaを1.0にする)

            llSetText("",<1,0,0>,1);
            llSetLinkAlpha(LINK_SET,1.0,ALL_SIDES);           
        }
// "c541c47...." というアニメーションが anims リストになかったら...
        if(llListFindList(anims,[(key)("c541c47f-e0c0-058b-ad1a-d6ae3a4584d9")]) == -1)
        {
        // テキストを空にして、すべての面を透明化(Alphaを0)する
            llSetText("",<1,1,0>,1);
            llSetLinkAlpha(LINK_SET,0.0,ALL_SIDES);
        }
    }
}
使用するスクリプトの関数は後々良く利用するものばかりでした。特に llListFindList といった List 操作系の関数は「なんらかの操作をする」場合によく使うことになりました。
でも、アニメーションを操作する、、、、ということでのここでのポイントは List 系の関数の話しではなく、
"c541c47f-e0c0-058b-ad1a-d6ae3a4584d9" というアニメーションの Key がタイピングのアニメーションを指し、llGetAnimationList はそのとき動いているアニメーションすべてをとる関数、、、ということです。

これも、、、運ですよねぇ、、、実は AO のための「今、何をしているか」を取得するスクリプトとしては、このとき私が参考にしたものよりも一般的なのは以下のような llGetAgentInfo を使う方法だと思います。if をネストしないのは浮きながらタイプする、、、など同時にその行為が行われている可能性があるからです。llWhisper の部分を上のようなオブジェクトの Alpha の操作に変えればいいわけです。(もちろん、、、このままではだめで、すでに Override しているなら何もしない、、、とかの処理が必要になります。あと、これをみたら AO って短い時間にぐるぐるまわるから、混んでいる SIM などでははずしたほうがいいことがおわかりになると思います。)

default {
    state_entry() {
        llSetTimerEvent(0.2);
    }
    timer() {
        integer bits = llGetAgentInfo(llGetOwner());
        if (bits & AGENT_TYPING) {
            llWhisper(0,"Now I'm typing!!!");
        }
        if (bits & AGENT_WALKING) {
            llWhisper(0,"Now I'm walking!!!");
        }
        if (bits & AGENT_FLYING) {
            llWhisper(0,"Now I'm flying");
        }
        if (bits & AGENT_IN_AIR) {
            llWhisper(0, "Now I'm hovering");
        }
    }
}

この方法を当時知らなかったので、逆に「"c541c47f-e0c0-058b-ad1a-d6ae3a4584d9"ってなに??」から始まり、llGetAnimationList って何???となったわけで(笑
ビルトイン・アニメーションの Key については secondlife wiki で確認することができます。(今は有志による日本語化された文書があるので、、、すばらしいですね)

でも、、、その後わかるのですが、アニメーションを操る上では、アニメーションの Key (UUID) って実はあまり使えない、、、のです。LSL は key でいろいろな操作が可能です。 llSetTexture なども貼り付けるテクスチャは、テクスチャの名前(string)だけじゃなくて、key (UUID) を指定することで利用できますが、アニメーションは llStartAnimation で Key の利用はできません。

と、、長くなってきましたが、最後に llGetAnimationList と動いているアニメーションの確認に関して。

今どんなアニメーションが動いているのかな?というのは、この関数を使わなくても確認することができます。この方法は「何が動いている?」を知るのによく使う方法ですが、もうひとつ重要なのは動いているアニメーションの優先順位を確認することができる点です。これも後々悩むのですが、ショップで売っているアニメーションの優先順位って結構バラバラだったりします。アニメーションのプロパティを見てもそのアニメーションの優先順位ってわからないんですよね。(少なくても私は、、、他の方法を見つけられてません) なので、よくダンス・アニメーションがうまく開始されていない、、、などという場合はこの方法で本当にアニメーションが開始されているか、邪魔している優先順位の高いアニメーションは他にないか(よくあるのが ポーズなどの AO をつけたままダンスを踊ろうとしている人とか、、、)を確認します。

1. Ctrl+Alt+D (Windows) で [Advanced] メニューを出します

2. [Advanced] メニューから [Character] を選び、[Animation Info] をクリックしてチェックをいれます

これだけです。
すると、画面上の「すべてのアバター」の頭の上に現在動いているアニメーション名(一部 Key)とそれぞれの優先順位が表示されます。
1
この情報を llGetAnimationList は取得してるんですよね。
で、、、、チャットキーボードを出展しましたが、ひとつも売れませんでしたね~
私はとても気に入っているので今でもつかってますけどね(笑
次にショップからアニメーションを購入して Animation Override を作ることにトライしました。といってもダンス・アニメーションじゃなくて「スタンディング・ポーズ」のアニメーションです。チャットキーボードが Typing の状況を監視してオブジェクトを出したり消したりしていたので、スタンディングの状況を監視して購入したアニメーションを開始させればいいはず、、、と考えたわけです。
このつづきは、、、その3かな?

2008年5月6日火曜日

セカンドライフのアニメーションを操る その1(かな)

ASUKA の雷神に設置させてもらっている MLDU (Massive Dance Link Unit) を作ったことで、Secondlife 内の「アニメーション」や「ダンス」、動きはないけど仕組みとしては一緒の「ポーズ」などをスクリプトで扱う方法をそこそこ理解できるようになってきました。

Free のダンスもいろいろありますが、Sine Wave や Animazoo、OWENIMATIONS といったアニメーション専門店で素敵なポーズやダンスを見て思わず買ってしまった、、、なんて経験がある方も多いのではないでしょうか。

このアニメーションを使うために AO (Animation Override) ユニットを配付しているショップもありますが、英語での説明だったり、コンテンツフォルダに保存したアニメーションを名前順に同じ時間間隔で再生するといった単機能だったりして使用勝手が、、、と思われている方もいると思います。

そこで(どこで??笑)アニメーションを扱う方法についてこれまで私が経験したことをちょっとまとめてみようと思いました。はい、急に思い立ちました(笑

アニメーション操作のファースト・ステップ 「ジェスチャ」

フルパーミッション(コピー可、プレゼント可、修正可)のダンス、アニメーション、ポーズならばジェスチャ作成してカスタマイズするのが一番でしょう。マクロ(?)みたいな感じですが、スクリプトを書くよりはものすごく簡単に、アニメーション、サウンド、チャットの組み合わせをひとつのジェスチャの中に登録することが可能です。時間を指定して次の動作に移ったり、同時にアクションを開始したり、、、とアイディア次第ではかなり凝ったことができます。ビルトイン・アニメーションも使えますので、たとえばビルトイン・アニメーションを流用した「クチパク」などはスクリプトを組まなくてもジェスチャ登録することで作成することが可能です。「あ」とか「い」といった母音の発音の口の形に近いジェスチャを作って Shift+F5, F6, F7 とかに登録しておき、それらをタイミングよく連打すると話しているように見えます。

アニメーションには実行時の優先順位というのがあり、同時に複数のアニメーションが動くと、高いものが優先されて動きます。また、複数のアニメーションを同時に動かすと、アニメーション指定が重なっていない「部分」などは複合して動きます。クチパクなんかも優先順位の同じビルトイン・アニメーションを複合させると思いもよらない表情をみせてくれることがあります。

以下の「お」という発音のクチパク・ジェスチャの例では「Open Mouth」というアニメーションと「Kiss」のアニメーションを同時に動かして、0.2秒後にそれらを止める、という Steps を登録したものです。
 1

すると、、、ちょっと間抜けですが、以下のような顔になります(笑
0
これ、Kiss アニメーションの目と Open Mouth のクチが組み合わさっているんですよね。
[Wait] を追加して [アニメーションが完了するまで] のチェックをはずした状態で明示的に再生秒数を指定して、その直後にアニメーションを停止(STOP)させるステップをいれると最初の「0.2秒だけ」アニメーション(それも複合)を再生することが可能になるわけです。
ジェスチャの基本については以下を参考にしてください。

http://help.secondlife.com/jp/avatar/gestures.php

思えば1年くらい前にはこのジェスチャくらいしかアニメーションを操る方法を知らなかったんですよねぇ。。。フリーなものしか持ってなかった、、、というのもありますが。
残念ながら、ショップのダンスなどはコピー不可になっているものがほとんどですから、このジェスチャ機能は使えないわけです。
そこでスクリプトによる操作、制御、、、というのが出てくるわけですが、私がはじめてスクリプトを使って「アニメーション操作」を意識したのはクラフターズカップの「チャットキーボード コンテスト」でした。

って、、、長くなったので次回に続く、、、、かな?(笑

2008年5月3日土曜日

ネトラジ・チェンジャー

商売っ気がまったくない、、、といえばないのですが、、、(笑
いろいろな「玉」を作ってきましたが、お友達から予想以上に評判がいいのが ネットラジオ・チェンジャー (NetRadioChanger - NRC) です。

やっぱり、自宅、お店、クラブなどなど、、、音楽があったほうが楽しいわけで。
でも、いちいち土地情報開いて、、、なんてめんどうだったり。

そこで、llSetParcelMusicURL を使って、ノートカードに登録している URL をダイアログに表示して、ボタンで切り替える、、、という「玉」を作って、お友達にお渡ししていたわけです。

といっても、あまりエラー処理とか日本語のメッセージとかにしてなかったので、それらをいれて SUZAKU の "Snuript Library" にベンダーとしておきました。 [追記 2009: 今はなくなっています。もうしわけございません。]

といっても、、、 100 L$ ですけど(笑
nrc9
(青いグローな玉です、、、、って、パッケージングとかほんと、手抜き、、、)

でもね、実は、この単純な NRC2.2 は Snuript の技術を結集、、、(笑

1) ノートカードへの記述が増えれば自動的にダイアログのページも増えます
現時点で 75 のネトラジが登録されていますが、減らすことも増やすことも可能です。ノートカードにフォーマット通りに追記してもらえれば、ダイアログのページは自動的に増えます。
nrc3
登録する URL の長さにもよりますが、118 局、ダイアログで 14 ページまで追加できました。
nrc6
メモリーが足りなくなるくらいの長いノートカードになったときは、その旨メッセージがでますので、ご安心ください。

2) ノードカード変更後のスクリプトのリセットを簡略化しました
Change イベントを拾って、ノートカードが変更されたときに「コンテンツが変更されたので、スクリプトをリセットしてください」は当然の処理だとしても、オブジェクトの編集を選んで、パーミッションのないソースを開いて [リセット] ボタンって、あまりユーザーフレンドリじゃないと思っていました。そこで、Change イベントが発生したら、通常のダイアログの [Close] ボタンを [RESET] にして、そのボタンを押すことでスクリプトのリセットをかけるようにしました。
ノートカードの変更・局の追加はそこそこ発生しますからね~。
nrc5
3) 土地・区画のオーナー情報を表示するようにしました
これは、、、一番最初しか使わないのですが、ネトラジ・チャンジャーは土地・区画のオーナーもしくはオーナーになっているグループの所有でないと動きません。今までは llGetLandOwnerAt(llGetPos()) とオブジェクトのオーナーを比較して、違っていたら「オーナーエラーです」だけでしたが、だれがオーナーなのかを表示するようにして、その人にオブジェクトを渡して設定してくださいー、というメッセージを出すようにしました。設定してもらえれば、その土地・区画のオーナーじゃなくても音楽を切り替えることが可能になります。
こんな感じ、、、
nrc2a
で、意外に難しかったのがグループ所有の場合。Key はとれるんだけど、llRequestAgentData だとアバター名はとれても、グループ名ってとれないんですね、、、
でも、やり方、見つけちゃっいました。
で、とったのが以下。
nrc1a
world.secondlife.com に llHTTPRequest で GET メソッドを使う方法です。プロフィールの画像をとる方法の応用ですね。プロフ画像の取り方をご存知ない方はこちらなどを参照にしてみてください。 llHTTPRequest などは NRC の隣にポン、、、と置いてある非売品の辞書の応用でもありますが、、、(笑
あとは、、、スクリプト作る人の自己満足的な、、、(笑
[追記 2009/10] 今はこの方法は使えません。スクリプトからのアクセスって制限されたようです。

4) llDialog の問題を解決してみようと、、、
過去のエントリにありますが、llDialog って一言でいっても検討する余地が結構ありました。
だれでも使えるようにしてあげて、ダイアログから選択させる、、、という処理の場合は、タイムアウトを設定しなきゃいけない、、、そうすると最後にタッチした人にタイムアウトが設定される、、、[無視] をおされたら Listen チャンネルが残る、、、など。
NRC は、他の人がダイアログを開いていると「今使用できません、しばらく待ってください」というメッセージを表示して、一時点で一人しか対応しないようにしてます。でも、これ、dialogSlot というスクリプトを増やせば、その数だけ使える人数が増えていく仕掛けです。(NRC だと意味ないですが 笑)
ダンス玉の応用ですね~

と、、、 うーん、100L$ のわりには結構スクリプトのテクニックが詰め込まれて、、、って、MusicURL 変えるくらいだと、こんなにこだわらなくてもよかったのかな(笑
なお、SUZAKU のお店でご購入いただく際はパイメニューの [購入..] からお願いしますー。
nrc8
最後に、、、参考として付属しているネトラジの URL や内容、それが利用可能かどうか、、、などなどに関してはまったく関与していませんので、その点ご了承ください。いろいろな方からの情報、いろいろな方のご協力をもとに NOTECARD の内容が構成されていますが、NOTECARD の内容については一切お答えできませんのでよろしくお願いします。

SUZAKU の "Snuript Library" すみません~、いまは販売してません~^^;

p.s.
あ、そうそう、このネトラジ・チェンジャーですが、概観などは Mod 可能です。もっといえば、スクリプトを抜いて、他のオブジェクトにいれてしまうことも可能です。「玉」が気にいらない人はかっこいいオブジェに変えてください。