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が重い、動きが遅い状態)のときのノートカードの読み込み、、、この対策ができたのが、ベンダー販売をしてもいいかな、と思った最後の対応でした。
つづく?(笑

2 件のコメント:

  1. llKey2Name参考になりますねー^^
    私の場合、「if((string)llGetAgentInfo(touch_id) != "0"){・・・}」 で、やってましたw
    ありがとうございましたw

    返信削除
  2. ちなみにその頃からもうちょい検証が進んで、
    llGetObjectMassが最も高速にチェックできるという結論になっております。
    理由は戻り値の型がfloatなんでシンプルだからですな。

    返信削除