ソラマメブログ
< 2008年07>
S M T W T F S
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    
アクセスカウンタ
オーナーへメッセージ
読者登録
メールアドレスを入力して登録する事で、このブログの新着エントリーをメールでお届けいたします。 解除は→こちら
現在の読者数 3人

2008年01月24日

シンクロアニメーション2(リンデンスクリプト Tips)

 前回に引き続きシンクロアニメーションのスクリプトです。前回は、シンクロアニメ
するすべての人がシンクロ用のオブジェクトを装着する必要がありました。今回は、指
令者だけがオブジェクトを装着してシンクロさせる方法の説明です。今回のスクリプト
では、自分を含む2人のアバターを同時にアニメーションさせることが可能です。

* 司令者側の画面
  周囲のアバターのリストが表示されます。シンクロしたいアバターを選択します。


* 相手のアバターの画面
 アニメーション実行許可のダイアログが表示されます。
 OKをクリックするとシンクロアニメがスタートします。
「スクリプト内容」

「メインスクリプト」 // // SHOP ZERO Tips21 SynChronAnimation MainScript v2.0 // // Created by Zero2000 Kid 2008/01/24 // integer ItemType=INVENTORY_ANIMATION; integer handle; string animation; list idlist; list namelist; key uid; integer input_ch = -21; // SENSOR RANGE(m) float range = 10; // SENSOR ARC FOR X float arc = PI; default { state_entry() { llRequestPermissions(llGetOwner(), PERMISSION_TRIGGER_ANIMATION); animation=llGetInventoryName(ItemType,0); } on_rez(integer int) { llResetScript(); } touch_start(integer t) { if (llDetectedKey(0)==llGetOwner()) { handle = llListen(input_ch, "", llGetOwner(), ""); llSensor("","",AGENT,range,arc); } } listen(integer ch, string name, key id, string message) { if (message=="STOP") { llMessageLinked(LINK_THIS, 4, animation, NULL_KEY); llStopAnimation(animation); llStartAnimation("stand"); } else { integer findIndex = llListFindList(namelist, [message]); uid = llList2Key(idlist,findIndex); llMessageLinked(LINK_THIS, 1, "", uid); } llListenRemove(handle); } link_message(integer sender_num, integer num, string str, key id){ if (num==2) { llMessageLinked(LINK_THIS, 3, animation, NULL_KEY); llStartAnimation(animation); } } sensor(integer total_number) { integer i; idlist=[]; namelist=[]; for (i = 0; i < total_number; i++) { if (i<11) { idlist+=llDetectedKey(i); namelist+=llDetectedName(i); } } namelist+="STOP"; llDialog(llGetOwner(), "PLEASE SELECT AVATORS", namelist, input_ch); llSensorRemove(); } }
「サブスクリプト」 // // SHOP ZERO Tips21 SynChronAnimation SubScript v2.0 // // Created by Zero2000 Kid 2008/01/24 // default { link_message(integer sender_num, integer num, string str, key id){ if (num==1) { if ((llGetPermissions() & PERMISSION_TRIGGER_ANIMATION) && llGetPermissionsKey() == id) { llMessageLinked(LINK_THIS, 2, "", NULL_KEY); } else { llRequestPermissions(id, PERMISSION_TRIGGER_ANIMATION); } } else if (num==3) { llStartAnimation(str); } else if (num==4) { llStopAnimation(str); llStartAnimation("stand"); } } run_time_permissions(integer perm){ if(perm & PERMISSION_TRIGGER_ANIMATION){ llMessageLinked(LINK_THIS, 2, "", NULL_KEY); } } }
「使用方法」 (1)適当なオブジェクトを作成し、地面に置きます。(箱でも球でもなんでもかまいません) (2)オブジェクトのコンテンツ内にメインスクリプト及びサブスクリプト及びアニメーション  ファイルをドラッグします。 (3)オブジェクトをTAKEし、装着します。(HUDとして装着した方が良いかもです) (4)シンクロしたい相手が10m以内にいるのを確認し、オブジェクトをクリックします。 (5)ダイアログが表示されるので、相手のアバター名称を選択します。 (6)相手の画面上にパーミション要求の青いダイアログが表示されます。 (7)相手がOKをクリックすると、シンクロダンスが始ります。 (8)再度オブジェクトをクリックし、STOPを選択するとダンスをストップします。 「スクリプトの説明」   今回のスクリプトで重要なポイントは、スクリプトを2つに分けている点です。  その理由は、llStartAnimationというコマンドの特性によるものです。  前回のtips20でも説明しましたが、llStartAnimationでアニメを実行する対象は、  llRequestPermissionsでパーミションを取得したアバターになります。  llRequestPermissionsでは、アバター1人分のパーミション情報を保持可能です。  というか1人分のパーミション情報しか保持できません。新しいパーミション情報が  入ってくると古い情報は上書きされてしまいます。つまり1つのスクリプトで、同時  に制御可能なのは1人のアバターのみとなります。   では、複数を同時に制御するためにはどうすれば良いでしょう。1つのスクリプト  で1人ならば、人数分のスクリプトがあれば可となります。  今回は、自分を含め二人のアバターを制御しますのでスクリプトが2つ必要になります。  前回のtipsで、工夫が必要だと言っていたのはこの点です。  おおまかなスクリプトの流れとしては、以下のような感じになります。    (1)自分自身に対して、アニメーション実行のパーミションを要求。  (2)センサーで周囲のアバターを検出。  (3)検出したアバター名称をダイアログ表示。  (4)ダイアログで選択したアバターに対して、アニメーション実行のパーミションを要求。  (5)相手からパーミションの許可が出たら、二人同時にアニメーションをスタート。    まずオブジェクトを装着するとstate_entryが呼び出されます。  ここでは、以下の2つの命令が実行されています。     llRequestPermissions(llGetOwner(), PERMISSION_TRIGGER_ANIMATION);       //自分自身に対して、アニメーションの実行要求を行う     animation=llGetInventoryName(ItemType,0);       //コンテンツの中のアニメーションファイル名を取得して、変数animationに格納する  こちらは、前回のtips20でも同様のことをやっています。詳しくはそちらをご覧ください。  次にオブジェクトをタッチするとアバター名のダイアログを表示する部分の説明です。  タッチですので、まずはtouch_startイベントが呼び出されます。この中では、リッスンコマ  ンド、センサーコマンドを実行しています。まずは、リッスンコマンドの実行です。     handle = llListen(input_ch, "", llGetOwner(), "");       //オーナー自身の発言をチャットチャンネルinput_ch番で監視する  こちらも前回のtips20で出てきましたので、詳しくはそちらを参考ください。  次は、センサーコマンドの実行です。     llSensor("","",AGENT,range,arc);  range及びarcは、スクリプトの最初でそれぞれ、range = 10,rc = PIと指定しています。  つまりこのコマンドは、半径を10メートルとする球体の範囲内に存在するアバターを検出  しなさいという意味のコマンドになります。球体の中心は、スクリプトを保持している  オブジェクトになります。詳しくは、llSensorをご参照ください。     センサーコマンド実行の結果アバターが検出されると、sensorイベントが発生します。  このイベントの中では、検出したアバターのUUID及び名称をリスト化し、さらにアバター  名称のダイアログを表示させています。順番に見ていきます。  まずリストの初期化です。     idlist=[]; // アバターのUUID格納用のリスト     namelist=[]; // アバターの名称格納用のリスト  リストの右辺に[]という値を指定すると、リストを初期化する意味になります。  次にこのリストの中に検出したアバターの名称及びUUIDを格納していきます。       for (i = 0; i < total_number; i++) {       if (i<11) {         idlist+=llDetectedKey(i);         namelist+=llDetectedName(i);       }     }     namelist+="STOP";   ここのtotal_numberには、検出されたアバターの数が入っています。つまり検出されたア  バターの数の分だけこのループ処理を実行することになります。   ループ処理の中では、idlist+=llDetectedKey(i)及びnamelist+=llDetectedName(i)  が実行されていますのでそれぞれのリストのにアバターのUUID及び名称が格納されることにな  ります。ちなみにこのループ処理の中でi<11という判定文を付けていますが、これは検出数が  11以上ある場合は、それ以上はリスト化しないようにしています。その理由は、ダイアログで  表示可能なボタンの数が最大12個だからです。   なのでリスト化するアバターの数は、11人で制限をかけています。あと残りの1個のボタンは、  STOPボタン用です。STOPは、ループ処理後にnamelist+="STOP"で追加してます。   次にダイアログ表示部分です。     llDialog(llGetOwner(), "PLEASE SELECT AVATORS", namelist, input_ch);   このコマンドは、オーナーに対して、namelistのボタンを配置したダイアログを表示する  意味になります。詳しくは、llDialogを参照ください。namelistには、前で説明したとおり、  センサーイベントで検出したアバタ名称が入っています。      ダイアログのボタンが押されると、チャットチャンネルinput_chを利用して押された内容  を発言します。チャットチャンネルinput_chについてはタッチイベントの中でllListenコマン  ドを実行して、すでに発言を監視状態にあります。つまりダイアログのボタンが押されるとリ  ッスンイベントが発生することになります。     * このようにllDialogとllListenはペアで使用します。llDialogを利用する際は、予め    llListenを実行しておく必要があります。     ここまででやっとスクリプトの流れの(3)まで説明したことになります。ひとつひとつ説明す  ると結構長いですね・・w。読むのも結構大変だと思います。しかし、このスクリプトで重要  なのはココからなのでもう少し頑張りましょう~!w   さてリッスンイベントの中には、どんなメッセージが入ってくるでしょうか。入ってくるのは、  ダイアログのボタン表面に表示されている文字列になります。つまり、アバターの名称もしく  は"STOP"というメッセージが入ってくることになります。  まず最初にアバター名称が入ってきた場合(messageの中身がSTOP以外のとき)です。       integer findIndex = llListFindList(namelist, [message]);     uid = llList2Key(idlist,findIndex);     llMessageLinked(LINK_THIS, 1, "", uid);   上記の3つのこのコマンドが実行されます。一行目は、ダイアログで選択したアバタ名称が、  namelistの何番目の要素かを調べ、そのインデックス番号を変数findIndexに格納しています。  2行目では、idlistからfindIndex番目の要素をkey型で取り出し、変数uidに格納しています。  namelist及びidlistには、検出された順でアバターの名称及びUUIDがそれぞれ格納されていま  すので、同じインデックスの要素同士は、それぞれ同一アバターの情報になります。つまり  変数uidには、ダイアログで選択したアバターのUUIDが入ることになります。   3行目では、リンクメッセージコマンドが実行されています。最初のパラメータがLINK_THIS  となっているので、自分自身に対してリンクメッセージを送信することになります。メッセージ内容は、  先ほどの"uid"の値と数値の"1"を送信しています。  (リンクメッセージについては、llMessageLinkedを参照ください)。  さてこのメッセージを受信するのは誰か?というと、送信先が自分自身だったので、自プリム  内に存在している全てのスクリプトが対象になります。今回の場合は、メインスクリプトとサブ  スクリプトの両方が受信することになります。それでは、それぞれのリンクメッセージの受信部分  を見ていきます。        // メインスクリプト受信部分     link_message(integer sender_num, integer num, string str, key id){       if (num==2) {         llMessageLinked(LINK_THIS, 3, animation, NULL_KEY);         llStartAnimation(animation);       }     }     // サブスクリプト受信部分     link_message(integer sender_num, integer num, string str, key id){       if (num==1) {         if ((llGetPermissions() & PERMISSION_TRIGGER_ANIMATION) && llGetPermissionsKey() == id) {           llMessageLinked(LINK_THIS, 2, "", NULL_KEY);         } else {           llRequestPermissions(id, PERMISSION_TRIGGER_ANIMATION);         }       } else if (num==3) {         llStartAnimation(str);       } else if (num==4) {         llStopAnimation(str);         llStartAnimation("stand");       }     }  内容を見ると両方のスクリプトとも受信メッセージの値(num)によって、処理を切り分けています。  今回は、数値の"1"を受信しますので、サブスクリプトの以下の部分が実行されることになります。     if (num==1) {       if ((llGetPermissions() & PERMISSION_TRIGGER_ANIMATION) && llGetPermissionsKey() == id) {         llMessageLinked(LINK_THIS, 2, "", NULL_KEY);       } else {         llRequestPermissions(id, PERMISSION_TRIGGER_ANIMATION);       }  ここの部分では、ダイアログで指定したアバターにPERMISSION_TRIGGER_ANIMATIONの  パーミションがあるかチェックしています。もしパーミションがない場合は、llRequestPermissions  を使用してそのアバターに対して、パーミションの要求を出します。このとき相手のアバターの画面  上には、パーミション要求の青いダイアログが出現しているはずです。ここで相手がダイアログでOKを  クリック(パーミションを許可する)すると以下のイベントが発生します。       run_time_permissions(integer perm){       if(perm & PERMISSION_TRIGGER_ANIMATION){         llMessageLinked(LINK_THIS, 2, "", NULL_KEY);       }     }  ここでまたリンクメッセージを実行しています。  こんどは、数値が2になっていますので、今度はメインスクリプトのリンクメッセージ受信部分の  以下の処理が実行されます。     if (num==2) {       llMessageLinked(LINK_THIS, 3, animation, NULL_KEY);       llStartAnimation(animation);     }  ここでまたリンクメッセージを実行し、llStartAnimationでアニメを実行しています。  リンクメッセージは、数値が3になっていますので、今度はサブスクリプトの  以下の処理が実行されます。     } else if (num==3) {       llStartAnimation(str);  メインスクリプトでは、llRequestPermissionsの発行先が、自分自身なので、スクリプトのオーナー  自身がアニメを実行します。サブスクリプトでは、llRequestPermissionsの発行先が、ダイアログで  指定したアバターなので、そのアバターがアニメを実行することになります。つまり二人のアバター  がほぼ同時にアニメを実行することになります。    ちょっとリンクメッセージの処理が分かりにくかったと思いますので、信号の流れを簡単に説明すると  以下のような流れになります。
メインスクリプト側サブスクリプト側
①相手に対するパーミション要求信号送信

②パーミション要求信号受信

③パーミション取得完了の信号送信
④パーミション取得完了の信号受信
⑤ダンス開始の信号送信

⑥ダンス開始の信号受信
⑦ダンス開始!
 ちょっと面倒なやり取りのように見えますが、こうすることにより相手がパーミションの許可を  出した時点で同時にアニメーションを実行することが可能になります。    ここまでが、スクリプトの流れの説明です。予想したよりもかなり長文になってしまいました。  ここまで読まれた方お疲れ様ですw今回は、二人同時でしたが、このスクリプトを応用すれば  5人,10人と同時にシンクロさせることも可能です。是非挑戦されてはいかがでしょうw リンデンスクリプト Tips Intexへ

この記事へのトラックバックURL

この記事へのコメント
こんにちは、はじめまして。
いつも興味深く拝見させていただいております。
最近ポーズアニメーション作りを始めたのですが、作れるようになるとだんだん望みが高くなるもので、素人のくせにシンクロアニメに興味を持ち始めました。
こちらの記事は本当にタイムリーでした!
感謝します!

そのうち、別々のアニメを二人で演じるようなシンクロ方法もできればいいなー(こちらで解説していただけるとよいな〜)と思っております(ヲイ)。^^;

あ、フライサポーターは大変重宝しています!^^
Posted by ちろ at 2008年01月25日 09:32
ちろさん

こんにちは^^
フライサポータお買い上げありがとうございます。
ご希望のスクリプトですが、今回のスクリプトを少し変更すれば可能です。
今回のスクリプトで、アニメーションの実行命令部分は、以下の2カ所です。

1. アニメーションスタート命令部分
------------------------------------------------------------
llMessageLinked(LINK_THIS, 3, animation, NULL_KEY); // 相手側命令
llStartAnimation(animation); // 自分側命令
------------------------------------------------------------
2. アニメーションストップ命令部分
------------------------------------------------------------
llMessageLinked(LINK_THIS, 4, animation, NULL_KEY); // 相手側命令
llStopAnimation(animation); // 自分側命令
------------------------------------------------------------

実行させたいアニメーションファイル名をそれぞれ
animeA(自分用)
animeB(相手用)
とすると上記命令部分を以下のように変更すればOKです。

1. アニメーションスタート命令部分
------------------------------------------------------------
llMessageLinked(LINK_THIS, 3,"animeB", NULL_KEY); // 相手側命令
llStartAnimation("animeA"); // 自分側命令
------------------------------------------------------------
2. アニメーションストップ命令部分
------------------------------------------------------------
llMessageLinked(LINK_THIS, 4,"animeB", NULL_KEY); // 相手側命令
llStopAnimation("animeA"); // 自分側命令
------------------------------------------------------------

2つのアニメーションファイルは、コンテンツの中にいれておきましょう。
ではでは。
Posted by ZEROZERO at 2008年01月27日 02:47
うぁ! さっそくありがとうございます!!!
試してみます〜!^^
Posted by ちろちろ at 2008年01月27日 07:25