2009年07月24日
llDetectedTouchST
先日Gonbeの店舗にあるマルチベンダーを入れ替えましたが、その際に使ったテクスチャの位置を把握するスクリプトを参考に書いておきます。
使った関数はllDetectedTouchSTです。
詳しい解説はコチラを参照してください。分りやすいと思います。^^
スクリプターズカフェ/ログ/llDetectedTouchUVとllDetectedTouchST
この関数自体はMONO対応と同時期に提供されていましたが、非MONO対応ビューアが公式ビューアとして残っていたので、ずっと使わずにいました。
現時点では公式ビューアでは非MONO対応版は使えなくなっていますので、今回切り替えたと言う事です。
今回のマルチベンダーでは、11個の商品を扱えるようにしてあります。
プリム数は2プリムですね。
ルートプリムは販売パッケージのテクスチャを貼り、右クリックで支払を選択して購入するための物です。
そして子プリムとして、購入可能な商品一覧の背景パネルがあります。
背景パネルは、こんな感じですね。↓
最下段の「Prev」と「Next」はルートプリムに表示される商品を次又は一つ前に切り替えるための、順送り用です。
数字の書いてある部分には、実際の販売商品パッケージの縮小画像等を貼り付けて使います。
この背景パネルは雛形で、実際にはPhotShop等で予め、このレイアウトに合うように販売商品の絵等を位置合わせして作っておく必要があります。
あくまで背景パネルに貼れるテクスチャは1枚ですから。
こんな感じですね。
※本当は1枚の板に複数枚のテクスチャを縮小して位置指定で貼れるともっと便利なのですけどね。^^;
そしたらGonbeは、これを商品として販売するのですが・・・
そして中央の黒い部分に、ルートプリムのBoxが入るようになります。
背景パネルの数字部分をクリックすると、ダイレクトに販売商品の選択ができて、ルートプリムの表示内容が切り替わると言う物ですね。
非常に便利です。^^
さてGonbeの場合、ルートプリム側にはベンダースクリプトを入れており、背景パネル側には何番が指定されたかをルートプリムに伝達するだけのスクリプトを入れています。
実際に使っているのは、11マルチ、14マルチ、16マルチ兼用のスクリプトなので、掲載スクリプトとはちょっと違うのですが、とりあえず基本的な内容は同じなので、簡単にするため、11マルチ固定のスクリプトサンプルにしておきます。
また、スクリプトは効率とか、パフォーマンスとか、分りやすさとか言う観点では書いていません。
あくまでGonbeが自分で使う範囲で適当に書いてますから、その点はご了承下さい。^^;
では、スクリプトサンプルです。
float list_no=5;// マルチベンダーの分割数(5X5分割にしているので5)
integer x_no;// タッチした場所に対応する縦の列番号(0~4)
integer y_no;// タッチした場所に対応する横の行番号(0~4)
string send_no;// タッチした場所を示すメッセージ用変数
default
{
touch_start(integer total_number)
{
vector touch_pos=llDetectedTouchST(0);// タッチした場所のVector座標を取得
float temp_x=touch_pos.x;// Vector座標のX値を取得
float temp_y=touch_pos.y;// Vector座標のY値を取得
integer i=0;// iの初期化
x_no=0;// 縦番号の初期化
y_no=0;// 横番号の初期化
integer flg_x=0;// 縦番号判定フラグの初期化
integer flg_y=0;// 横番号判定フラグの初期化
for(;i<list_no;i++){// 最大5回ループさせる
if(flg_x==0&&temp_x<((float)i*(1.0/list_no)+(1.0/list_no))){// タッチした縦の番号判定
x_no = i;//タッチした縦の番号をセット(0~4)
flg_x=1;//縦番号が特定できたのでフラグをONに。
}
if(flg_y==0&&temp_y<((float)i*(1.0/list_no)+(1.0/list_no))){
y_no = i;//タッチした横の番号をセット(0~4)
flg_y=1;//横番号が特定できたのでフラグをONに。
}
if(flg_x==1&&flg_y==1){// 縦横両方の番号が特定できたか?
i=(integer)list_no;//特定できていたら、それ以上回す必要が無いから、iに最大値を入れてループアウト。
}
}
if(y_no==0&&x_no==0){ //Prevの位置か?
send_no="prev";
}else if(y_no==0&&x_no==4){ //Nextの位置か?
send_no="next";
}else if(y_no==0&&x_no>=1&&x_no<=3){ //最下段のタイトル位置か?
send_no="non";
}else if((y_no>0&&y_no<4)&&(x_no>0&&x_no<4)){ //中央のルートプリムの場所
send_no="non";
}else if(x_no==4&&y_no<4){// 9番~11番の位置の場合
send_no=(string)(8+(x_no-y_no));
}else{ // 1番から8番までの場合
send_no=(string)(x_no+y_no);
}
if(send_no!="non"){
llMessageLinked( LINK_SET, 0, send_no, NULL_KEY);
}
}
}
概略はスクリプト内コメントで判断下さい。
ポイントだけ書いておきますね。
llDetectedTouchST(0)ですが、取得できるのはVector型の値です。(X,Y,Z)と言う値ですね。
今回の場合はテクスチャですから2次元の平面に対応しています。
従って、使う値はXとYの二つになります。
テクスチャのタッチした位置とXとYの値の関係は、先ほど示したBlog記事を読むとわかります。
スクリプターズカフェ/ログ/llDetectedTouchUVとllDetectedTouchST
ここでは左下が(0,0)で左上が(0,1)で右上が(1,1)で右下が(1,0)と言う事でご理解下さい。
この値を元にして、タッチされた場所が、何番に該当するかを判定しており、それに対応した番号等をルートプリムにメッセージで伝達しているのです。
temp_x<((float)i*(1.0/list_no)+(1.0/list_no))
の部分が判定式ですね。
これはタッチされた場所のXの値が i*(1.0/list_no)+(1.0/list_no)) の計算結果より小さい場合に、そのiの値を縦番号として記憶する式です。
今回は1枚のパネルを5X5分割した状態で判定していますから、list_no=5になっています。4X4分割なら4になります。
この式で言うと、最初i=0ですから、1を5で割った数、0.2よりもタッチしたXの値が小さければ、x_noは0になります。
例えばタッチしたXの値が0.58だったら、1*0.2+0.2の計算結果0.4よりは大きいですが、2*0.2+0.2の計算結果0.6よりも小さいと言う事になりますから、x_noは2がセットされます。
同様にYの値も評価して、対応する値をy_noにセットします。
両方の値が決まったら、それぞれに対応したパネル上の位置情報に変換します。
x_no=0でy_no=0の場所は「Prev」ですから、"prev"の文字を送るメッセージにセットしています。
パネル上の1番から8番に関しては、単純にx_no + y_noの値と同じになるので、その範囲はx_no + y_noの計算結果を文字列変換してセットしています。
9番~11番に関しては、8+(x_no-y_no)の計算結果に一致するので、同様に結果を文字列に変換してセットしています。
パネル下段のタイトル部分は、タッチしても商品の切り替えを行う必要が有りませんから、"non"の文字列をセットして、メッセージを送る場合に除外しています。
そして一番最後にリンクメッセージの送信を行って終わりです。
llMessageLinked( LINK_SET, 0, send_no, NULL_KEY);
当然ルートプリム側では、このリンクメッセージを受け取れるようになっていますし、送られてきたsend_noの内容によって、表示商品のテクスチャや価格設定等が切り替わるようになっています。
そちらに関しては、ここでは触れません。
マルチベンダーに関しては、以下のページが分りやすいと思いますので、そちらと合わせて研究して見て下さい。^^
ベンダーを作ろう(初級スクリプト第十回)
お金を扱う(初級スクリプト第十一回)
とりあえず、背景パネルのどの位置がタッチされたか分れば、それに対応して商品を切り替える事は可能になります。
そして、NextやPrevでの順送りもボタン用プリムを使わずに実現できますから、結果的には2プリムで11商品の販売ができる事になります。
6X6分割では、14商品とか16商品も可能になります。7X7なら・・・凄い事になりますね。^^;
レンタルモール等の場合は、使用プリム数によって費用が変わってきます。
その意味で、低プリムのマルチベンダーはありがたいものです。
Gonbeの場合は、レンタル店舗に関しては、プリム数が今までの3分の2に減少しました。
マルチベンダー部分が全て半分になったからです。
しかも以前よりも、グンと利用しやすくなったのですから、大満足です。^^
最後に、この関数や内部的な判定はFloatの値を元にしていますが、非常に精密なタッチ判定を行う場合には、適さないと思います。判定結果には多分に誤差が出ます。
あまり細分化してしまうと、判定結果に狂いが出ることもありえますので、その点はご注意下さい。
いや~スクリプトって面白いですね。^^
2009年07月24日
llAddToLandPassList
例えば、アクセス制限をかけた土地に対して、一時的に入るのを許可する物です。
これは土地の設定でもできます。

パブリックアクセスを禁止して、入場許可を販売にチェックを入れると、該当の土地を右クリックしたパイメニューに「入場許可購入」と言うのが出てきます。
そこで設定されているお金を払うと、設定時間内だけ入れるようになります。
設定時間を過ぎると、強制的にBANされます。
入場許可販売状態や、完全にアクセス禁止している土地に対して、スクリプトで入場許可を与える事ができます。
それがllAddToLandPassListです。
簡単な例で言うと、タッチしたら3分間だけ入場できるスクリプトを示します。
default
{
touch_start( integer total_number )
{
llAddToLandPassList(llDetectedKey(0),0.05);
llSay(0, "You are allowed three minutes to enter.");
}
}
文法としては、 llAddToLandPassList(key agent, float hours) となります。
Key agentの部分に対象AVのUUIDを入れます。 上記の例では、タッチした人のUUIDをセットしています。
float hoursは入場許可時間です。単位は時間です。ここを0.0にすると時間無制限に許可されます。
上記の例では0.05時間なので、3分間ですね。
下限値は0.01だそうです。36秒ですね。
llSayは許可した事をチャットに発言しているだけです。
このスクリプトは「通行許可証の販売」設定がされていても、お金を払う事無く入場できるようになります。
パスリストにはアクセス可能残り時間が着いて、名前がセットされている状態になります。
この残時間は、ちゃんと減少していくようです。
そして時間が過ぎると、パスリストから名前が消えて、BANされてしまいます。^^;
また、次のようにパブリック・アクセスが許可されていると、最初から入れるので、スクリプトからは何も設定されません。

パブリックアクセス許可の下にある、「支払情報登録者」や「年齢認証」にチェックが入っていた場合も、このスクリプトでは許可が得られません。
llAddToLandPassListとは逆にBANリストへ追加する関数がllAddToLandBanList(key agent, float hours)です。
使い方は一緒です。
これを試した理由は、ある条件を満たしたら土地に入れるようにする方法を検討しているからです。
色々なやり方がありますが、これだと確実にブロックできます。
ただ、欲を言えば。。。
このパスリストの値がスクリプトで取得できれば良いのですけどね。^^;
Gonbeが調べた範囲では、その値を取得する方法は見つかりませんでした。
もしパスリストが取得できれば、そこに記載されている人だけがフリーアイテムをGetできると言うシステムも可能と思ったからです。
残念ながら、それを行うには、やはり外部サーバーへ自分で許可者を記録しておいて、管理する方が良さそうです。
それならば、あえてllAddToLandPassListを使う必要も無いかもしれないな・・・とは思いました。^^;
余談ですが、良くアクセスを禁止している人が居ますよね。
ノンビリ寛いでいる時に、いきなり部屋の中へ入ってくる無礼者も居ますから、気持ちも分らないでも無いですが、Gonbe的には不愉快ですね。
アクセス禁止エリアが一杯あるSIMなんて、絶対に立ち入りたく無いです。
SL内でのプライバシーに対する考え方がGonbeとは全く違うのでしょうね。
Gonbeの土地は全てフリーアクセスです。
物を出すこともできます。ただ無制限に置けると不味いので、オブジェクトのリターン設定は10分間にしてあります。
これだけで、不届き者の悪戯はほどんと防げています。
まあ、作業中にいきなり飛んでこられて、話しかけられたりするのは、余り良い気はしませんけど、それはアクセス禁止にしても、話かけてきたり、変なオブジェクトを送りつけたりする輩は居ますからね。
嫌だと思ったら、BANしてしまいますし。^^;
さて、この関数はあまり使えそうも無いけど、場面によっては面白いかも知れないので、一応記憶にとどめておきたいと思います。^^
2009年07月21日
【注意】Bulk Permissions機能は使っては駄目!
現時点で確実に言える事は!
「Bulk Permissions機能」は、リンデンからBug Fixのアナウンスがされるまで使わないで下さい。
と言う事です。
尚、以下の内容はNaviSL内で報告されている事や、知人からの報告、JIRAの内容を参考にして、Gonbeなりにまとめた物です。
「Gonbeの解釈」も含まれている事を予めご了承下さい。
<問題となった現象>
クリエーターが製作し、Bulk Permissions機能を使って、オブジェクトのパーミッション変更を行い、それを販売物として売り出すと、購入者側の手に渡った時に、クリエーター製作時のフルパーミッションに戻ってしまうと言う事です。
Bulk Permissions機能とは、以下の絵(よねまるさんの絵を勝手に借用。^^;)

オブジェクト編集のコンテンツ・タブにViewer1.23から追加されたボタンで、これを押すとリンクオブジェクトも含めて、一括してパーミッションの変更ができると言う便利な機能です。
Gonbeは、この機能の存在すら知らなくて、今回の事件で初めて知りました。@@
<現状の注意点>
昨日リンデンからも正式に以下のような注意が出されています。
http://status.secondlifegrid.net/2009/07/19/post696/
リンデンも「Bulk Permissions機能は当面使わないで下さい」と言う内容です。
まあ、今更・・・と言う感じもしますが。。。^^;
今回の現象に関しては、「Bulk Permissions機能」を使用した場合に、再現性のある現象です。
潜在的Bugで、パーミッションが変わってしまうと言うものもまだ有りますが、そちらと混同はしないようにして下さい。
それらは、原因が特定されておらす、再現性も確認されていない物です。
今回の問題になった現象は、確実に再現できる現象です。
「Bulk Permissions機能」は、リンデンからBug Fixのアナウンスがされるまで使わないで下さい。
と言うのが、現時点での結論です。
<関連情報>
1.Viewerに関して
この現象が確実に再現されると言われているのは、リンデンの公式Viewer1.23とRCです。
他のViewerに関しては、「大丈夫」とか「いや、これも駄目だ」とか、まだ情報が錯綜しています。
もしリンデンの公式Viewer以外を使って要る人は、誰も保証はしてくれませんので、「自己責任で使いたいなら使う」と言う事になります。
2.フルパーミッションになるとは限らない
今回の現象関連での報告を見ていると、「Bulk Permissions機能でフルパーミッションになる」と言う以外の報告もあります。
コレに関しては、まだ確証は無いのですが、例えば自作の物以外がリンクされていたり、コンテンツ内に自作以外のスクリプトが使用されている場合、それらのパーミッション状態によって、フルパーにはならないケースがあると言うもののようです。
概ね、クリエーターが製作時点で使ったパーミッションに戻ると言うもののようです。
この辺の詳細は、JIRA等を丹念に読み解く以外は無いと思います。
今言える事は、「フルパーになろうが、なるまいが、「Bulk Permissions機能」を使うなら、自己責任で!」と言う事です。
3.クリエーターとしての心得
今回の件に関しても、各クリエーターが以下の事を確実に実行していれば防げたかもしれません。
・製作物は必ず自分以外の人に渡して、動作及びパーミッションのチェックを行う。
・チェックがOKだったら、Inventory内でコピーとかせず、渡した物自体を箱詰めして販売する。
・最後に念を入れて、実際に誰かに購入してもらい、動作及びパーミッションの確認をする。
リンデンのBugで一番厄介なのは、クリエーター本人では発生しないBugがあると言う事を知ってください。
Gonbeもそのような問題で、酷い目に何度もあっています。><
かならず自分以外の人(セカンドAVでも良い)に渡してチェックし、それを使うように心がければ、かなりの確率で安全と思います。
4.パーミッションが勝手に変わる現象は、他にもある。
くどいようですが、今回の事件はリンデンの公式Viewerで「Bulk Permissions機能」を使った場合に発生しています。
これ以外にも、「パーミッションが勝手に変わった」と言う現象の報告はあります。
しかし、それらは再現性が明確では無く、潜在Bugとして見られています。
「あれもこれも・・・」と混在した情報を流す人も居るのですが、今回の件は、「Bulk Permissions機能」を使った場合ですから、混同しないようにお願いします。
「Bulk Permissions機能」を使っていないのに、パーミッションが勝手に変わったと言うのは、別なお話として、別途調査をして見て下さい。
そして、確実に再現できる手順が分ったら、JIRAへ掲載するか、日本語サポートに報告してください。
最後に、俄然賑わっているJIRAのページを記載しておきます。
https://jira.secondlife.com/browse/SVC-4444
賛同できる人は、Vote(投票)をして支援してください。
尚、この記事は、この場で議論するためのものではありませんので、コメントは「承認後受け付ける」に設定します。
議論をするならば、リンデンの該当するフォーラム等で発言する事をお勧めします。
Gonbeに言っても、何も変わりませんから。^^
以上です。
2009年07月19日
HTTP-INを使ってみた。
やりたかった事は以下の図のような内容です。

要は、お賽銭箱とお地蔵さんを、天神福岡と小笠原に置いて、当たりが出たら、メインランドにあるGonbeの土地に置いてあるコンテンツBOXから配布すると言うものです。
従来は、各お地蔵さんに景品を入れておいてと言う事になりますが、それだと景品を入れ替えるたびに、アチコチと飛び回って入れ替えないと行けません。
今回の方式なら、景品はGonbeの土地のコンテンツBOX内だけ入れ替えればすみます。^^
まあ、これはテスト的に行っているので、一般的には自動アップデート・システム等で使う事が多いでしょう。
7Seasの釣り竿とかは、アタッチした時とか、使用中のバージョンより新しい物が出ていると、自動で新バージョンが送られてくると思いますが、そう言う類で使う事が多いと思います。
尚、HTTP-INに関しては、まだ使えるようになったばかりで、関連記事も少ないのですが、以下の記事が色々と関連ページへのリンクもあって、便利と思うので紹介しておきますね。
http://blog.innx.co.jp/vw/secondlife/lsl/2009-07-11-http-in-comes-main-grid-1-27
一応簡単なサンプルは以下に書いておきます。
お時間があればご覧下さい。 続きを読む
2008年10月22日
オブジェクトへの指示
1.ダイアログ
2.HUD
3.チャット・コマンド
これらに関しては、基本的にはListenを使って、アバターとオブジェクト間でメッセージを交信しているもので、似たような使い方ができます。
しかし、それぞれに特長もありますので、簡単に書いておきたいと思います。
1.ダイアログ
詳細な設定等を行う場合に使われます。

一番の特徴としては、Detected系のイベントと組み合わせて、イベントが発生した時にダイアログを表示させて使うと言う事ですね。
Detected系とは、touch、collision、sensor系のイベントで、検知したアバター等の情報を取得できる関数の事です。
詳しくは、Makapu@BlackSheep-LSLまたはBlackSheep-LSL@Wikiを参照下さい。
http://miz.slmame.com/
http://www21.atwiki.jp/mizcremorne/
具体的には、「使いたい時に」、「使いたい人が」、「アクションを起こした時」と言う形態になります。
つまり、アバターが何らかのアクションを起こした時に、はじめてListenが起動されて、ダイアルログが表示され、ダイアログからの指定にそって、オブジェクトがメッセージを聞き取り動き出すと言う事ですね。
要は常時使用はしないけど、必要があれば、何時でも設定画面を呼び出して、指示を出せると言う形態のものに適しています。
また、複雑な組み合わせの設定を行う場合も、ダイアログを使う方が望ましいと思います。
従って、Gonbeの製作する商品類は、最初設定したら、そうそう設定を変えませんから、ダイアログ形式が多用されています。
2.HUD
これはHUDオブジェクトを作り、HUDオブジェクト内に操作対象のオブジェクトへのメッセージを仕込んでおいて、HUD上のボタン・オブジェクト等にタッチする事によって、仕込んだメッセージを対象オブジェクトに伝達する方式です。
これも、対象オブジェクト側はListenでメッセージを受け取ります。

この場合は、対象オブジェクト側は常時Listen状態で居なくてはなりません。
ダイアログが、対象オブジェクトをタッチした時にListen状態になるのと、この辺が違います。
更にダイアログの場合は、Detected系で取得したアバター情報を元に起動しますから、場合によっては不特定者に対しても、操作を可能にできます。
勿論オーナーのみとか、オーナーと同じグループの人のみとかの制約をつける事もできます。
しかし、HUDは基本的には装着して使うので、装着者=所有者しか操作できないと言う事になります。
もっとも、HUDもオブジェクトですから、Rezして設置しておけば、不特定者に対してHUD操作(もはやHUDとは言えない?)を可能にもできますが。。。
このように、HUDを使う物は、頻繁にオブジェクトを操作したいと言う場合です。
アバターの装着物等で、会話等の合間に、装着物にアクションさせたい場合とかは、一々装着物をタッチして、ダイアログを表示させ・・・なんてやっていると、タイミング良く機能を発動できません。
HUDならワンタッチで瞬時に伝達でき、効果的な演出が出来ることになります。
この事から、HUDが使われるのは、頻繁に操作が発生するような類の物と言う事になります。
良く有るのは、レーダー系や翻訳機系、TP支援等のものですね。
AO等に関しても、頻繁にアクションを切り替えたいという場合には、HUD経由で操作したほうが効率的です。
HUDは頻繁に使用し、ワンタッチでアクションを起こせる程度の設定に対して有効です。
ダイアログのように、多段階の複雑な設定には、あまり向かないと思います。
ただし、ライティング設定を変えたり、音楽のボリューム調整や、スピーカの出力指定等の、視覚的に連動しながら、瞬時に切り替えていくような物に対しては、複雑な構成にはなりますが、HUDで全てを連携させて状態を視覚化し、瞬時に操作できるようにした方が良いでしょう。
乗り物系の操作HUDも同様ですね。
高度計やスピード計、レーダー等、その状況に合わせてHUD内に表示させ、操作系ボタン等で指示を出しながら操縦すると言う形態になると思います。
ダイアログでは間に合いません。><
3.チャットコマンド
本来は、この形式が基本形で、一番に理解すべき内容でしょう。
良く使われるのは、"/9 stop"等のように特定チャネルを指定して、簡潔なコマンドをチャットから発言するものです。
この対象オブジェクトも、常時Listen状態で、指示を受け取れなくてはなりません。
実はダイアログやHUDも、チャネルの使い方次第では、このチャットコマンド形式との併用が可能になります。
では、HUD、ダイアログとの決定的な違いは何でしょうか?
一番の違いは、チャネルの使える範囲になります。
チャットコマンド形式に関しては、"-9"のようなマイナスチャネルは使えません。
ダイアログとHUDでは、マイナスのチャネルも使用できます。
また、チャットの場合は、一々手打ちすると言う事から、あまり桁数が多く、複雑なチャネルは使えません。
例えば、"1987547093チャネルを使う"と言われたら、この数字を覚えていられるでしょうか?
Gonbeには不可能です。
ダイアログやHUDの場合は、"-34875629034"と言ったややこしいマイナス数字を使ったり、ダイアログならRez時に乱数で適当なチャネルを生成して使用したりもできます。
しかし、チャットコマンド形式では、せいぜい2桁か3桁程度のプラスの数字程度しか使えない事になります。
要は、チャットコマンド形式は、単純なコマンド指定で、単純な指示を出すだけの場合には適していると言う事になります。
このように、すべてListenを介して、アバターの指示をオブジェクトが聞き取る形態なのですが、それぞれに特性があり、最適な場面と言う物が存在します。
また、一つのオブジェクトでも、用途に応じて、チャット、HUD、ダイアログを併用している物も多々有ります。
概ね、ダイアログが複雑な設定を行う場合に使い、通常頻繁に使う指示系統はHUDにまとめ、滅多に使わないが、単純な指示ですむ部分はチャットコマンドで済むような仕組みにしたりします。
また、チャットコマンドをトリガーにして、"/9 menu"とか発言すると、ダイアログが出てきて、本格的な設定場面に移行するという使い方もできます。
逆にタッチでダイアログを表示し、ダイアログ側のボタンを押すと、「30秒以内にペットの名前を発言してください。」とメッセージを出して、チャットコマンド待ちになるような使い方も有ります。
まずは、これらの操作性や、利用制限事項を把握し、適材適所に使い分けられるようにしましょう。
2008年09月25日
ペットを作るには(6)
で、公開したペットスクリプトで良ければ・・・と言う事で参加する事にしました。
ただ先に公開したスクリプトだと、フォロータイプの事が書かれていないので、今回は典型的なフォロータイプのスクリプトを作成して、公開しようと思います。
両方を上手く組み合わせると、本当のペット仕様として満足できるようになるでしょう。
と言っておいてなんですが・・・この2つを組み合わせるには、かなりの工夫も必要で、難易度高いかも?
移動方式が両者では違うので、先の歩行型にフォロー機能を入れ込むのは、けっこう厄介なんですね。
でも、そこまで入れ込んだスクリプトにすると、複雑になってしまうから、今回は別々に紹介したと言うわけです。><
まあペット作りの参考になればと思います。
今回の作品は「トンボ」です。

こんなオブジェクトを作成しました。
顔の部分にメインスクリプトを入れてます。
面倒なので他のパーツにはスクリプトは入れていません。
羽根を動かせば、けっこう本物のトンボのような動きになります。
これは実は1年ほど前に、ANIMANIAでハチドリとトンボの動きを見て、「あ~。。。これなら簡単に作れるな~。。。」って思って、その後トンボを作る気が無いから、作らなかった物なんですが、仕組み的には簡単なものです。
移動にはllSetPosを使ってますから、非物理オブジェクトですみますし、トンボのような物は動きが早いので、歩行型のように1歩1歩進めるなんて事をしなくても、一気に飛ばしても不自然になりません。
ハチドリやトンボ、ハチ等の昆虫類のように動きの早いタイプには、このスクリプトで十分でしょう。
詳しくは続きを見て下さい。 続きを読む
2008年09月07日
ペットを作るには(5)
そして、説明用のサンプルスクリプトを入れたものを見て、なんと!満足してしまったようです。^ ^;
まあ、一般の人から見ると、サンプル用のスクリプトレベルの動きでも、「凄いー!」と言う感じなんでしょうね。
そこで、この記事の締めくくりと言う意味で、歩行型のサンプル・スクリプトを公開してしまいます。^ ^
まず次のような感じのオブジェクトを作ってください。

4速歩行のペットになります。
SSの物はサンプル用に通常プリムだけで、適当に作りました。
ネコなのか熊なのか???
まあ、頭と胴体と足があれば何でも良いです。
ちなみに2速歩行でも構いません。
気をつけて欲しいのは、後で示すサンプルスクリプトの場合、ルートオブジェクトの向きによって、正しい姿勢で動かない場合があります。
これは方向を向かせるのに、llLookAt()と言う関数を使っているからです。この関数の場合、正面がZ軸方向になります。
分かりにくいので、簡単に正面を正しく向かせる方法を書いておきます。
まず作成で三角錐等を地面に出して下さい。下の絵のように、とがった方を上に向けて出てくると思います。
写真は分かりやすいように、各面に色をつけてあります。

このとがった方角(=Z軸方向)が、このオブジェクトの正面になります。
そこで、水平方向にオブジェクトの正面が向くように、Y軸を横に90度回転させます。

これでとがった先が水平方向を向きました。
この状態で、プリムの形状を球にでも変えてしまえば良いです。
このプリムをルートオブジェクトにしておけば、常に青い面を上にしてとがった先の方向に移動してくれます。
実際に試して見て下さい。
ちなみにサンプルでは顔の球をルートプリムに指定していますが、別に胴体でも構いません。
ルートプリムに後から記述する、メイン・スクリプトを入れてくれれば良いです。
で、サンプル・スクリプトを入れたペットは、次のような動きになります。
ランダムに歩いたり、走ったりして勝手に動き回ります。小さめに作ると、けっこう可愛いです。^ ^
スクリプトに関しては続きをご覧下さい。 続きを読む
2008年09月06日
ペットを作るには(4)
お弟子志願の人が製作したネコをモデルに、どうすれば販売できるレベルのペットになるか。。。
その辺の実践的な内容を書きたいと思います。
まず志願者の人が製作したネコと、それを元にGonbeが少し加工したネコです。

左がGonbeが加工したもの。右がオリジナルです。
背中に変な三角錐が着いていますが、これはフリームーブ系のスクリプトを動かす場合、オブジェクトの正面の向きを合わせておかないと、正しく移動してくれないからです。
彼が作ったオブジェクトだと、逆立ちした格好で動き出してしまうので、ルートに向きを合わせた三角錐をつけています。
違いは足にあります。
オリジナルは歩くアニメーション効果の為に、各足が2本ずつあり、可視化と透明化を交互にスクリプトで切り替えて、足が動いているように見せています。
このテクニックは、良く使われるもので、色々なペットでもこのような形態の物が見られます。
対して、Gonbeの物は足は4本です。
各足は全体の動きに合わせて、足自体が前後に動いて歩く姿を示します。
ペンちゃんの足の動きや羽根の動きも同様になっています。
単に歩き回るだけ。。。又は単純にフォローとしてアバターの傍にいるだけならば、オリジナルの作りでもかまいません。
しかし、高度な動きまで表現しようと思ったら、この方式では行き詰まります。
具体的には、今回のネコには次のダイアログのような機能を入れてみました。

停止(ステイ状態)、歩く、走る、寝ると言う基本動作パターンの4つです。
オリジナルの場合、停止と歩くは実現できるでしょう。
しかし、次のような動画の動きをさせるのはどうでしょうか?
もしオリジナルでも、このような動きを取り入れようと思ったら、今の足の数では足りなくなります。
更に今回は、寝ると言うポーズも入っています。

このように、高機能なペットの場合は、色々な行動パターンを再現していきます。
こうなってくると、単純にオリジナルのような構造では実現できなくなってしまいます。
つまり、本物と同じように手足を動かすスクリプトで対応しないといけないと言う事です。
このオリジナルにはもう一つ問題点があります。

今回パーツはオリジナルのものをそのまま使っています。
写真の後ろ足のパーツですが、オブジェクトの中心点(赤、青、緑の矢印の中心)が、足のパーツの中央にあります。
本来足は、足の付け根を中心に回転するように動きます。
今の作りでは、足を前後に回転させると、付け根の位置がズレてしまします。
そこで今回は内部的に、回転させると同時に付け根の位置も合うように、同時に動かして調整しています。
仮にパーツの中心が足の付け根の部分に来ていたら、足は単純に回転動作させるだけで済みます。
スクリプトの負荷も当然軽減されると言う事です。
更にステイ状態の時は座ったポーズにしたい場合、今の後ろ足の形状では不自然になってしまいます。
歩いている時、走っている時、寝ている時、座っている時と、基本パターンだけでも色々な形状に変化していきます。
それらをちゃんと反映できるモデリングをしないと、無駄にスクリプトに負担をかける事にもなりますし、不自然なポーズになってしまう事にもなります。
ペットにどのような動作をさせたいのか?。。。と言う事は最初に決めておく必要があります。
モデリングの最初の段階で、簡単なスケッチ等を書いて、実装すべき機能に合わせたポーズを書き出し、それらを一番効率的に実現できるパーツ構成を考えて作っておく必要があるのです。
そして、その際には、スクリプトで動かせる動きとは?。。。と言う事も、常に頭の隅においておかないと、適正なモデリングも出来ないと言う事です。
ふ~。。。けっこう面倒な仕事ですよね。^ ^;
さて、お弟子候補さんはついてこられるでしょうか?
2008年09月06日
ペットを作るには(3)
今までのが、基本はアバターへの装着系が主だったのに対して、こちらはいわゆるフリー・ムーブ系に該当する設置型のものです。

スクリプトとしては、もっとも難易度の高いもので、サンプルスクリプトすら、ほどんと出回っていません。
従って、このタイプの商品は高額商品が多いです。
最低でもL$300以上。一番多い価格帯は、L$500~L$800程度だと思います。
さて、この自立運動型を考える場合、実現すべき行動パターンと言う物を理解する必要があります。
一般的には次の行動が基本パターンになります。
(1)フォロー
アバターについて来る機能です。
現在ペット系で実装している機能としては、もっとも多いタイプと思います。
フォローだけの機能であれば、スクリプト的にはそれほど難しくはありません。
と言っても、自立運動型自体の難易度が上級レベルなんで、かなりのスクリプトの知識が無いと作れないと思います。
先にも書きましたが、唯一フリーで公開されたスクリプトも存在しています。
多くは、アバターが動いていると、歩いたり走ったりして着いて行き、アバターが止まると、横でステイ状態や、長時間停止していると、スリープ状態へと遷移させたりする複合型もあります。
(2)フリー
アバター等には関係なく、設定された行動範囲を、勝手気ままに動き回るタイプです。
これが多分一番難しいと思います。
基本はフォローと同じですが、フォローが常にアバターの位置をターゲットに動いているのに対して、こちらは移動目標自体から、自分自身で設定して動き回らないといけないのです。
ある意味、本当の命をオブジェクトに吹き込むようなものだと思ってください。
フリーの場合にも、「歩く」、「走る」、「飛ぶ(ジャンプ)」等のバリエーションがあります。
これらのバリエーションが豊富であり、それがランダムに実施されるほど、本当の生き物の様に見えてきます。
(3)ステイ
基本的には置物タイプと同じような状態です。
完全に停止しているか、あるいは耳や目等、パーツの一部だけを動かして、その場にジッとしている状態です。
(4)スリープ
眠っている状態です。
ペンちゃんでも採用してますが、最近のペット系では必須の機能になっています。
ペットの寝顔ほど、我々を癒してくれるものは無いかも知れません。^ ^
現状ですと、この基本4機能すら、完全に網羅しているものは少ないでしょう。
フォローかフリーのどちらかだけの機能の物が多いです。
ただ、今後はこれらの機能は網羅したタイプのペットが増えてくると思います。
更に進化系の機能もあります。
(5)HUG
抱っことかおんぶとかに該当します。
先の装着型とは違い、地面等で動いている状態から、いきなり装着してしまう機能です。
この機能を実装しているペット類は少ないです。
今話題になっているコーギーは、この機能が実装されています。
スクリプト的にはそれほど難しい訳では無いのですが、フリーやフォロー機能を持っているペットの場合、装着することによって、スクリプト制御が異なるため、上手く切り替えられず、スクリプトが停止してしまったり、装着を外しても動かない状態になってしまうことが起こりやすいです。
この機能はGonbeも既にテストでは実装して試しています。
その際に、前述の問題があったために、まだ販売物には実装しないで居る状態です。
しかし、魅力的な機能ではあるので、今後は取り入れる方向で進めています。
(6)食事
これもコーギーでは実装されていますが、餌を与えると、それを食べる機能です。
食事中のペットと言うのも、やはり可愛いものですから、この機能も今後は実装しようと思っていました。
(7)お喋り
お喋りペンちゃんで、簡易的な機能は実装しましたが、本当は有る程度会話になると良いように思います。
ただ、それを実現するには、キーワード管理等とデータベース化も必用になります。
ペンちゃんレベルの独り言が現状では妥当と思ってます。
(8)マイハウス
これもヨチヨチペンちゃんの「良い子」バージョンで実装しましたが、自分のホームポジションを記憶しておいて、寝る時は必ずその場所に戻って眠ると言う物です。
発展系としては、排泄する場合は、決まった砂場へ行って行うとか、食事に関しても、決まった場所へ持っていって食べるとか、色々とあると思います。
(9)排泄
コーギーで実装されていますが、もともとはネタ系の機能になります。
まあ、可愛いペットの排泄物ですから、その世話をする事にも喜びは感じるでしょう。
Gonbeの構想には入っていない機能です。
(10)番犬
これはフォローの拡張機能になりますが、主人ならば尻尾を振って甘えますが、他の人の場合は、牙をむき出して威嚇したり、飛び掛ったりするような機能です。
これも当初からの構想にあったものですが、実際には色々と難しい部分もあって、まだ実装はしていません。
サメでこの機能を実装させようと思っていました。
(11)遊ぶ(追加項目)
コーギーでも取り入れられていましたが、遊ぶという機能もあります。
コーギーはボールを出すと、それに飛びついて遊びます。
有名なフリスビー犬は、フリスビーを投げるとそれをキャッチします。
ネコ型だと、ネコじゃらしを前で動かすと、手を動かして遊ぶなんてのもあります。
これも様々なバリエーションが考えられ、魅力的な機能の一つです。
さて、一口にペットと言っても、実に多彩な機能に分類される訳ですが、実際には、これらが複合的に実装される事が多くなると思います。
そして、機能が増えれば増えるほど、スクリプトは複雑化してきます。
それでも、今回のコーギーが先陣を切ってしまいましたが、今後は益々高度なスクリプト制御が組み込まれた、人工生命体のようなペットが出てくるでしょう。
ただ・・・その分スクリプト負荷も大きくなります。
その点も考慮して、過度の設置は迷惑行為にもなりますから、気をつけましょう。
また、これからペットスクリプトに挑戦する人は、単に動けば良いのでは無く、販売したあとのフォローの事や、SIM環境を悪化させるようなパフォーマンスの悪いスクリプトにならないよう、十分に注意が必要と思います。
今後弟子希望者の人に、ネコの製作を通じて指導してみたいと思います。
その結果、分かりやすい内容とかが整理できたら、またスクリプト等も含めて、こちらに掲載して紹介したいと思います。
さてさて、どうなるでしょうね。^ ^
2008年09月06日
ペットを作るには(2)
2.回転タイプ(装着型・設置型)
今はやりの釣りで釣れる魚等が該当します。

単純に回転するだけのペットです。
魚系に多いです。
装着して頭の周りをグルグル回ったり、設置して使ったりもできます。
これもスクリプト的にはもっとも簡単なものです。
写真の右側に移っている黄色い○がルートオブジェクトになっています。
そして魚は○にリンクされた状態で居ます。
○の中には以下のような簡単なスクリプトを入れれば、魚が○の周りを一定スピードで回り始めます。
もっとも初歩的なスクリプトです。
llTargetOmega(<0,0,0.7>,1.0,1.0);
勿論周囲を回る魚の方にもスクリプトが入っており、それで各パーツ等は動かしています。
そちらの方は、それぞれに違うので、動きを見て研究するしか無いですね。
3.抱っこ・おんぶタイプ(装着型)
抱っこ(おんぷ)ペンちゃん系が該当します。

基本的には肩乗りと同じなのですが、こちらの場合はアバターにアニメーションをつけるケースが多く、その分難易度は高くなります。
4.置物タイプ(設置型)
設置したその場にとどまり、動き回ることはありません。

ただ、首をかしげたり、耳を動かしたり程度はします。肩乗りタイプや抱っこタイプを、そのまま置いたようなものとも言えます。
スクリプト的には、それほど難しい事は無いでしょう。
ただ、各パーツは微妙に動かさないといけないので、それなりにモデリングとスクリプトの関連性は理解しないといけないでしょう。
類型パターンとして、シット・ポーズが組み込まれたタイプがあります。
このタイプでは、スクリプトよりもモデリングとテクスチャのクオリティが大きな要素になります。
モデリングがよければ、置いておくだけでも存在感を示しますので。
駆け足で書いてきましたが、次は自立運動型のペット(フリームーブ)に関して書きたいと思います。
尚、スクリプトサンプルは出てきませんので、あしからず。^ ^;
2008年09月06日
ペットを作るには(1)
で、実際にお会いして話を聞くと、「最近物造りに目覚めて、ネコとかイルカを作ってみようと思ったのです。」と言う事で、Gonbeの店の水槽を見て、「素晴らしい」と思ってくれたので、「弟子入り」を打診したそうです。
そこで、お弟子志願者への説明用と言う意味で、しばらくはペットの作り方に関して整理してみようと思います。
彼は試作品のネコとイルカを持っていたので、それを見せてもらいました。
で、何が困っているのか?と聞くと、やはりスクリプトが分からないと言うことでした。
彼は現在、フリーで出回っているスクリプト等を使って、それを組み込んで製作しているようでした。
ネコに関しては、鳥のペットスクリプトを転用して使ったみたいですが、思うように動かないと言う事でした。
スクリプトを見ると、中身は乗り物系のスクリプトを使ったもので、恐らくアバターに着いて回るタイプなのだと思います。
乗り物系スクリプトを、ペットへ転用することは、現在Gonbeも研究中なのですが、正直言って一番難易度の高いスクリプトです。
本来乗り物系はアバターによる操作を基本としています。
ペットへの転用と言うのは、自動操縦をさせるスクリプトにすると言う事になります。
アバターが操作する場合でも、イメージどおりに動かすには、パラメータの調整等が難しい分野です。
まして、自動操縦で生き物の動きを表現するのですから、Sランク難易度になってしまいます。
ペットを動かすスクリプトは、一般的にはほどんと公開されていません。
仮にされていても、そのまま使うのは難しく、生き物に合わせて個別調整をしないと、とても使えません。
そして、総じてスクリプトは複雑ですから、内容を理解せずに単純に転用しても、様々なトラブルに見舞われて、とてもサポートできないでしょう。
正直言って、誤った使い方でもされると、SIMパフォーマンスにまで影響を及ぼしかねない要素も含んでいます。
そんな事もあって、Gonbeはペットスクリプトは公開していませんし、それなりにスクリプトを理解できる人で無い限りは、指導もし無い方針です。
と言っても、ペットにも色々有りますので、タイプによっても難易度は変わってきます。
今回はその辺をまずは説明しておこうと思います。
1.肩乗りタイプ(装着型)
肩乗りコペン等が該当しますが、もっとも多いタイプのペット類です。

アバターが装着して、肩や頭の上に乗せて連れて歩くと言うものです。
スクリプト的には、簡単な部類にはいります。
基本的には、以下のようにアタッチイベントを検知するスクリプトを入れておき、アタッチされたらリンクメッセージで、各パーツへアタッチされた事を伝達します。そして各パーツが動き出すと言う簡単なものです。
default
{
attach(key attached) {
if (attached != NULL_KEY) {
llMessageLinked( LINK_SET, 11, "attach", NULL_KEY);
}
}
}
肩乗りタイプの場合は、スクリプトよりもモデリングの良し悪しが大きな要素になります。
また、装着を前提にしていますから、プリム数も豊富に使う事ができます。
Gonbeの場合は、設置型が主体で作っており、装着型は単に設置型のオブジェクトを装着型に流用しているだけなので、プリム数は少ないですが、装着型をメインに考えるならば、プリム数を減らすよりも、プリム数が増えても精緻なモデルを作った方が良いかも知れません。
次回は回転タイプを書き留めておこうと思います。
2008年08月02日
ペンコレ用のダンスボール
この手のスクリプトは得意では無いので、イマイチ不安だったのですが、どうやら思うとおりに出来ました。
ここでちょっとLSLの癖がある事が分かりましたので、書いておきます。

その前に御礼を兼ねて、今回アニメーションを提供いただいたお二人を紹介させていただきます。
今回用意したダンスアニメーションは、タイニー宇宙展でタイニー用のジェスチャー集を配布してくれていた、Zig Marchさんから特別にジャスチャーの元になったダンスアニメーションを提供いただき使っています。
またもう一人、前回映像撮影時にもお世話になった、タイニー職人さんのロンちゃんも、ペンちゃんをイメージしたアニメーションを製作してくれ、わざわざ送ってくれました。
そちらも使いたいと思ってます。
ロンちゃんのBlogはコチラです。↓
http://ron.slmame.com/
お二人には本当に感謝しています。この場をかりて御礼申し上げます。m(._.)m
さて、スクリプトのお話に戻ります。
まず仕様ですが、今回は所定の位置で、それぞれが踊って欲しいので、ボールに座った時にダンスアニメーションを開始するようにしたいと思いました。
そして、使ったスクリプトは以下の内容です。
********************************************************************
string animation_name="zig-dance2";
key siton = NULL_KEY;
vector sit_pos = <0.0, 0.0, 0.4>;
vector sit_rot = <0.0, 0.0, 0.0>;
default {
state_entry(){
llSitTarget(sit_pos, llEuler2Rot(sit_rot * DEG_TO_RAD));
}
changed(integer change){
if (change & CHANGED_LINK) {
key av = llAvatarOnSitTarget();
if (siton != NULL_KEY) {
if (av == NULL_KEY) {
llStopAnimation(animation_name);
llSetAlpha(1.0, ALL_SIDES);
siton = NULL_KEY;
}
} else {
if (av != NULL_KEY) {
siton = av;
llSetAlpha(0.0, ALL_SIDES);
llRequestPermissions(siton, PERMISSION_TRIGGER_ANIMATION);
}
}
}
}
run_time_permissions(integer perm) {
key perm_key = llGetPermissionsKey();
if (perm_key == siton) {
if (perm & PERMISSION_TRIGGER_ANIMATION){
list anms = llGetAnimationList(siton);
integer i;
for (i = 0; i < llGetListLength(anms); i++){
llStopAnimation(llList2Key(anms, i));
}
llStartAnimation(animation_name);
}
}
}
}
********************************************************************
これは単純にボールに座ると、アニメーションの実行許可イベントへ行き、現在稼働中のアニメーションを全て停止して、指定したアニメーションを実行すると言うものです。
単純なスクリプトなのですが、このままだと「動いたり動かなかったり」と動作が一定しません。><
そこで色々と原因を調べていたのですが、困った時のMakapu@BlackSheep-LSL頼み。
何となくポイントはllAvatarOnSitTarget()でのキー取得にあるような気がしたので、そのページを参照してみました。
http://miz.slmame.com/e11372.html#llAvatarOnSitTarget
すると!
サンプルスクリプトを見ると、そこには魔法のお呪いが書いてあるでは無いですか。!@@
そうです。
例によってスクリプトのタイムラグを埋めるお呪い。llSleep(0.5)です。
で、このサンプルのように、 if (change & CHANGED_LINK) と key av = llAvatarOnSitTarget();の間に、llSleep(0.5);を記述してみたところ、メデタク問題解消しました。^ ^
どうもLSLの場合、処理によって取得のタイムラグが発生する場合が多く有ります。
そんな場合は、適時お呪いを埋め込んであげなくてはなりません。
とりあえずこれでペンコレ本番も安心して迎えられそうです。
メデタシ・メデタシ。
2008年05月19日
整数計算と浮動小数点計算のミス

実は本店の水槽に設置時点で気が付いていたのですが、クマノミが泳がずに上を向いてアワアワしているのです。><
その原因が分かりました。
原因は遊泳するための目標地点座標計算部分にありました。
x_axi = pos_rand((integer)(x_max*10.0),(integer)(x_min*10.0))/10.0;
この計算式です。コレは修正後です。修正前は↓
x_axi = pos_rand((integer)x_max*10,(integer)x_min*10)/10;
クマノミは小さいですから、遊泳範囲の設定も0.5m刻みになっています。
そして最小値も0.5mなので、最小範囲は1m四方と言う事になっています。
今までの海洋生物は大きいので、最低が2m四方で、1m刻みの設定になっていました。
その点がカクレクマノミの場合は小さくなっているのです。
で、先の式ですが、変更前の場合、x_max=1.5,x_min=0.5とした場合次のようになります。
(integer)x_max*10=1(1.5が整数へ変換されるので1になる)×10=10
(integer)x_min*10=0(0.5が整数に変換されるので0になる)×10=0
結果として、0~10の間の乱数を求めると言う事になり、値は0~9.999999・・・と言う事になります。
でその値を10(整数計算と認識される)で割ると・・・自動的に整数扱いになりますから、答え=0となります。
つまり、何度計算しようとも、答えは常に0なんです。
だから、クマノミは天を仰いでアワアワしているだけで泳がなかったんです。><
修正後の式ですと、
(integer)(x_max*10.0)=15(1.5×10.0=15.0を整数へ変換するから15)
(integer)(x_min*10.0)=5(0.5×10.0=5.0を整数へ変換するから5)
つまり5~15の乱数結果なので、5.0~14.99999・・・となります。
それを10.0(浮動小数点計算と認識される)で割ると、0.5~1.49999・・・と言う結果になります。
このように数式には値の扱い順と「暗黙の型変換」と言う厄介な規則がある訳です。
10と言う数字は整数なので、「暗黙の型変換」が適用されて、計算結果は「整数」に自動的に変換されてしまいます。
10のような数字は「定数」と言いますが、扱いとしては強いんですね。
だから浮動小数点計算をしたい場合は、明示的に10.0としてやらないといけなかったのです。><
で、式を修正したら、クマノミちゃんがアワアワする事無く、メデタク狭い範囲でも嬉しそうに泳ぎ回ってくれました。^ ^
この「暗黙の型変換」に関しては、一般的なプログラミング言語を知っている人にとっては、「当たり前」の事象ですが、IT業界以外の人には分かりづらい概念と思います。
IT業界でも、「定数を式等へ直接書かずに、型宣言して定数用変数へセットして使え」と良く指導したりしてました。
でも、自分で書くと安易に使うんですよね~。。。^ ^;
プログラミングの世界では、整数と浮動小数点と言う違った性格の数字があり、これらを明示的に認識して扱わないと、思わぬ結果になってしまいます。
気をつけましょう。
2008年05月11日
足の形状は男と女で違うのか。
まずは男性アバターの足。

かなりフィットしている状態まで大きさ等を調整しました。
そして、そのまま女性アバターに変身させると・・・

当然、このようにブカブカになってしまいます。
で、大きさの調整を行ってフィットさせようとしたのですが・・・

このように、どうにもフィットしません。><
これは男性アバターに比べて、女性アバターの足先が細くなっているからです。
男性の足は、普通に考えた足幅よりも広めの感じがします。靴で言うとEEEEサイズみたいな感じですね。
それに比べて女性の足は、先端が細くなっています。こちらは普通に考えたよりも狭い感じです。
で、鼻緒の形状をモデリングから調整しなおしました。
その結果がコレ↓

やっと綺麗にフィットするようになりました。^ ^
たかがギョサンと侮っていたのですが、意外と靴と言うものも面倒な物ですね。
やっぱ地道に確認しながら製作しないと駄目なようです。
また一つ勉強になった。@@
2008年04月17日
ちょっと仕組みをバラしてしまおうかな?
実はこのモードだと、かなり自由に「自分だけのオリジナルペンちゃん」も作成できるのです。
とは言っても、簡単な訳では無いです。
例えばチンドンの場合は歩く度に、パーツの相対位置も少し移動させています。
もし、今のと違うパーツを組込もうと思ったら、そのパーツも動きに合わせて相対位置を移動させてあげないといけません。
それと、どのタイミングで移動させれば良いか?と言う問題も発生します。
そこで今回は、この各パーツの移動タイミングや相対位置指定の方法を書いてしまいます。^ ^;(良いのか?)
まず一番重要な、各パーツの同期方法に関してですが、これはルートプリム内のメインスクリプトでコントロールしています。
方式は一般的なリンクメッセージを使用しています。
<リンクメッセージの仕様>
リンクメッセージは以下のような設定で使っています。
llMessageLinked( LINK_SET, status, msg, NULL_KEY);
この中で実際にコントロールに使っている部分は、statusとmsgの部分です。
このstatusは、各種状態変化のたびに、その状態を表しており、それがリンクメッセージとして各パーツに伝達されています。
と言っても、状態自体は少ないので、実は簡単なものです。
1.設定状態(status = 9)
Rez又は装着時には、必ず設定状態になります。又タッチした場合も設定状態に遷移します。
設定状態とはダイアログが表示されている状態です。
この状態は、動作が停止した状態になります。
従って、各パーツともデフォルトの状態が設定されるようになっています。
2.行動状態(status=1)
チンドンなら歩行状態になりますし、抱っこペンちゃんなら、起きて羽根をパタパタ動かしながらお喋りしている状態になります。
チンドンの場合は、この状態の時に更に歩行と看板の上下をコントロールするリンクメッセージがタイマーで送信されます。
抱っこタイプなら、羽根の上下をコントロールしています。
3.お眠り状態(status=99)
抱っこペンちゃんのお眠りモードに入る場合のリンクメッセージです。
このメッセージが来ると、お眠りポーズに各パーツが設定され、Z・Z・Zのハートのパーティクルが出始めます。
帽子付の抱っこペンちゃんの場合は、帽子の位置も移動しますので、その辺の位置移動も、このメッセージを受信して実行しています。
お眠りモードから自動でお目覚めモードになった場合は、status=1で再度行動状態へと戻る事になります。
4.タッチした時の扱い
各状態共に、タッチした時はタッチイベント内で
touch_start( integer total_number )
{
if(llDetectedKey(0)==key_id){
status = 9;
llMessageLinked( LINK_SET, status, msg_end, NULL_KEY);
}
}
が実行されますので、設定状態へと遷移する事になります。
5.パーツ位置設定(status=51,msg=1 or 2)
他の状態と異なり、パーツの位置設定にはmsg部分も使っています。
具体的には以下のようなメッセージを飛ばしています。
llMessageLinked( LINK_SET, 51, (string)k, NULL_KEY);
(string)kとは、内部でinteger kの値を、タイマーイベント内で、1と2を交互に入れ替えています。
各パーツは1の場合と2の場合で、それぞれ自分の相対位置や相対回転値を保有しており、それをセットして位置を移動させています。
チンドンの羽根のスクリプトは以下のようになっています。
list wing_rot = [<-0.55059, -0.77752, -0.15117, 0.26357>,<-0.49991, -0.81747, -0.27601, 0.07512>,<-0.55059, -0.77752, -0.15117, 0.26357>];
default
{
link_message(integer sender_num, integer st, string msg, key id){
if(st == 51){
llSetLocalRot(llList2Rot(wing_rot,(integer)msg)); // msgの値をintegerに変換して、リストから該当値を取得してセット
}else if(st==1||st==9){
llSetLocalRot(llList2Rot(wing_rot,1)); // 本当はデフォルトの0にする予定だったが、値の配列を間違えて、1になってしまった。0番目の値は要らないジャン。><
}
}
}
6.サイズ変更時(status=20,msg=サイズ変更比率)
ダイアログからSmall.Middle,Bigのサイズ変更ボタンが押された場合ですが、この時は各パーツへもサイズ変更による相対位置の変更指示が飛びます。
llMessageLinked( LINK_SET, 20, (string)f, NULL_KEY);
ここで、問題になるのは(string)fです。
f = 変更後のサイズ÷変更前のサイズ
と言う計算結果が入っています。
この比率をメッセージとして送信して、受信した各パーツがfloatの値に再変換して、自分の相対位置を比率に従って調整し直しています。
例として、帽子のスクリプトを以下に掲載しておきます。
list hat_rot = [<-0.15323, -0.15257, 0.68834, 0.69241>,<0.08608, 0.08651, 0.70010, 0.70354>];
vector pos_0=<-0.12301, -0.00040, 0.01611>;
vector pos_1=<-0.12600, 0.00050, 0.04190>;
float f=1.0;
default
{
link_message(integer sender_num, integer st, string msg, key id){
if(st==1||st==9){ // 設定状態、行動状態の場合の帽子の位置
llSetLocalRot(llList2Rot(hat_rot,0));
llSetPrimitiveParams([PRIM_POSITION, pos_0]);
}else if(st==99){ // お眠り状態の帽子の位置
llSetLocalRot(llList2Rot(hat_rot,1));
llSetPrimitiveParams([PRIM_POSITION, pos_1]);
}else if(st == 20){
f = (float)msg;
llSetScale(llGetScale() * f); // 自分自身の大きさを変更
llSetPrimitiveParams([PRIM_POSITION, llGetLocalPos() * f]); // ルートプリムからの相対位置を調整
pos_0=pos_0*f; // 起きている状態の相対位置の変動を記録
pos_1=pos_1*f; // 寝ている状態の相対位置の変動を記録
}
}
}
少々格好は悪いのですが、予めデフォルトの相対回転値と相対位置を定義してあります。
この値がMiddleサイズ時の基準値になっています。
で、サイズ変更が起こると、リンクメッセージに従い、変更比率から自分自身の大きさを変更し、更にルートプリムからの相対位置も変更比率に沿って変わるので、位置も調整してます。
そして最後に、変更後の起きている状態と寝ている状態の相対位置も記録し直しておきます。
こんな感じで、大きさが変わるたびに、各パーツも位置調整をしたりしている訳です。
と言うような感じで、各パーツの位置を本体の移動や大きさに合わせて調整しながら動いている訳です。
けっこう位置合わせは面倒です。><
勿論、羽根の上下動とかであれば、回転角度で指定して上下に動くようにも出来ます。
ただ、今回に関しては、単純なパターンでしか無かったので、制作上は粘土アニメーションのような感じで、各ポジションの座標を求めて、固定値として埋め込んでしまいました。
その辺は汎用性を求めるなら、回転角度だけをパラメータにする方式の方が良いでしょう。
ただどちらにしろ、動きが複雑になればなるほど、これらのバリエーションは増えていく訳で、スクリプト的にはどんどん面倒な内容になっていくと思います。
できれば、簡潔な動きだけで表現した方が、私は優れた製作物だと思っています。
これを見て、オリジナルのペンちゃんを作れる人は、そうザラには居ないでしょうが、今後は「編集可」のタイプはまず販売しないと思いますので、もし今のバージョンを入手していて、スクリプトの知識も中級レベル以上有るならば、オリジナルペンちゃんの作成にもチャレンジしてみて欲しいと思います。
ちなみに、編集可の「ちんどん赤ちゃんペンギン」は今月一杯で販売終了となります。
また、現在販売している「お喋り抱っこペンちゃん」に関しては、今週末には「編集不可」のバージョンに入れ替えると思います。
従って、これを書いても今後はオリジナル品は作れないと言う事です。^ ^;(だから書いた?)
そだ!面白いアイデアのオリジナルペンちゃんが作成できたら、ペンギン・ビレッジのブランドで販売し、売れれば共同製作者として、一定の金額を即時配布することも出来ますので、「これは!」と言うものでも製作したなら、ご一報いただければと思います。
ではではこれで。
2008年03月10日
自動オブジェクト配布機
今回の対象者は100人ちょっと居ました。そして渡すオブジェクト総数は180ちょっと・・・アワワ。
けっこう対象を抽出して慌てました。^ ^;
まあ、これだけ多くの人が購入してくれていたと言う事ですよね。だから、しっかりサポートもしなくては。
で、色々考えたのですが、以前サメシリーズの不具合の時みたいに、いきなり送信しても、このご時勢では「受け取り拒否」される危険性も高いと思いました。
かと言って、一人ひとりにIMで連絡して、事情を説明して配布と言うのでは、とても時間が足りません。
また、自分のIN時間帯は日本時間の午後9時~11時程度の2時間が精一杯なので、時間帯の合わない人も多いと思います。
実際に購入記録を見ると、大部分が私が寝ている間に発生しています。^ ^;
そこで、今回は本店内に自動配布機を置いて、来店して受け取ってもらう方式にしました。
要求事項は次のようになります。
1.購入者に対してのみ配布する。
2.コピー不可の商品が多いから、配布は1回だけに制限したい。
3.配布した記録を残したい。
4.できるだけ簡単な操作で受け渡しをしたい。
と言うところです。
1,2を満足させるには、次のようなデータが必要になります。
1)顧客名
2)購入商品名
3)受渡しフラグ
1)と2)はTransaction Historyのデータから抽出して取り出せます。これが180件ちょっとある訳です。
そして3)の受渡しフラグは、スクリプトで商品を渡した事を、内部的に記録する部分です。
未渡し時=0、 渡し済=1と言う感じで記録して管理します。
次に3ですが、これも少々難問でした。
一番簡単で確かな方法は、SLのTransaction Historyに記録される方式で渡す事です。
その為には、「0L$の支払い」と言う方式を取らなければなりません。要は支払いスクリプトを入れて制御する方式です。
でも、これは4の要件には少々反します。「支払い」をクリックして、「0L$」をクリックしてもらう必要があります。
そして更には渡す際にダイアログが出てきて、それもクリックしないと駄目です。
できればパネルにタッチするだけで、GiveInventoryで渡してしまいたいと思っていました。
GiveInventoryですが、相手のプロフィール画面やアバター直接の場合は、Transaction Historyに記録が残るのですが、スクリプト内で行ってしまうと残らないのです。
そこで、今回はE-mail機能を使って、引渡しが完了したら、自分宛にE-mailを送信して、メール上で記録が残るようにしました。
これらに基づいて作成した物が次のような仕様のものです。

アバターがタッチすると、タッチイベント内でllDetectedKeyとllDetectedNameでタッチした人の名前とUUIDを取得します。
最初に名前から、コンテンツ内の顧客リスト(ノートカード)を1件づつ読み込んでマッチングします。
該当する名前が存在したら、その人が購入した商品も同時に読み込まれていますので、対応する商品をコンテンツから相手にGiveInventoryします。その際、スクリプト内のリストに「受渡しフラグ」を持たせておき、そこに済みマークを記録します。
そして「サンキュー・メッセージ」を出すと同時に、自分宛にE-mailを送信すると言う仕組みです。
当初は、1台で全ての顧客、全ての商品を対応させる予定でした。
その方がお客様には分かりやすいですからね。
ところが、まず180件もの購買記録は、スクリプト内部には保持できない。
また、受渡しフラグだけでも・・・と思ったのですが、それだけでも100件も入らないと言う事が分かりました。
リストに保持できるデータ量って、思っていた以上に小さいのですね。正直言って「困った」状態でした。><
まあ工夫すれば、180件程度のフラグは内部で管理できるかもしれませんが、今回は正攻法で取り組んでいたので、そこまでは考えるのを止めました。
そこで止む無く、商品別に顧客リストを分割しました。
それでも「顧客名、商品名、受渡しフラグ」にすると入りきりません。結局内部的には「受渡しフラグ」だけ保持して、後は外出しでノートカードを都度読み込んで処理する事にしました。
利用する側としては面倒なんですけどね・・・止むを得ません。
とりあえず、こんな感じで対象6商品分ですから、6台の配布機を作成して設置しました。
単純な構造にしたので、それぞれの機械は全て同じスクリプトになっています。違いは顧客リストの中身とコンテンツの中に入れた配布する商品だけです。そん点では汎用的で、今後も色々と使えるでしょう。
まあ、こう言う用途では2度と使いたくは無いのですが・・・^ ^;
なかなか皆さん来てはくれないでしょうが、出来れば早く渡しきってしまいたいと思います。今月中には終わらせたいな~。。。
2008年03月09日
お知らせ自動配信機
その内容に関してメモしておきます。
まずは要求事項。
1.顧客リストを元にIMとノートカードを自動配信する。
2.今回は起動はオーナータッチで起動すれば良い。(将来的にはタイマー起動も欲しいかも?)
と言う事で、結論から言うと、以下のような仕様のスクリプトを作成しました。

オーナーがタッチすると起動し、顧客リスト(ノートカード)を1件づつ読込、顧客名を取得してLinkメッセージを使って子スクリプトを起動します。
子スクリプトは受け取った顧客名から、HTTPリクエストを行い、WEB経由でアバター名からUUIDを取得します。
取得したUUIDを元に、顧客のアバターへIMを自動送信し、更にコンテンツの中のノートカードを送信します。
送信したら「送信完了メッセージ」を親スクリプトへLinkメッセージで返します。
親は完了メッセージを受け取ると、5秒待ってから次のデータを顧客リストから読み込みます。
これを顧客リストの最後まで繰り返すと言う仕組みです。
ここでポイントになった事は、スクリプトからアバターへ、IM送信(llInstantMessage)、ノートカードの提供(llGiveInventory)共に、アバター名では無くアバターのUUIDを指定しなければならない事です。
ちなみに対象顧客リストは、SLのTransaction HistoryデータをEXCELで取得し、ACCESSに登録してあるので、そこから抽出しています。
しかしTransaction Historyにはアバター名は記録されてますが、当然アバターのUUIDは分かりません。
ここではUUIDが必要になります。
スクリプトの関数としては、UUIDからアバター名を取得する関数(llKey2Name)が存在しますが、その逆は存在しません。
しかし、痒い所に手が届くMakapuでは、ちゃんと逆パターンの取得方法が紹介されていました。
それがWEB経由でアバターのUUIDを検索できるサイトから取得する方法です。
今回は、そちらを利用させてもらってUUIDをスクリプト内に取り込んで処理しています。
ただ、HTTPリクエストで取得した場合、全員のUUIDは取得できませんでした。20件ちょっとがエラーになって取得できませんでした。
後から、直接HPへ行って、個別にアバター名を入力して検索したら、何故かちゃんと取得できました。
この辺は英語のサイトなので、どう言う風になっているのかまでは分かりません。
これでIMとノートカードの配布は自動的に、次々と処理されていきました。
ここで、もう一つ注意が必要な事は、今回の仕様では、IMとノートカードを送信した結果を受けて、次のデータを顧客リストから読み込んでいるのですが、スクリプト内部で送信完了として処理していても、実態はタイムラグもあるようで、間をおかずに進めると、途中で「スピードが速すぎる」と言ってスクリプトが落ちてしまいました。
どうもWEBとのやり取りが早過ぎて駄目だったようです。
そこで、例によって「間」を5秒ほど空けて、次のデータを読み込んで処理しました。
2秒でも十分だったのですが、途中でふと思ったのです。
「100件以上も連続で機械的にWEB接続かけたら、それってスパム行為と思われないかな~・・・」と言う事です。
まあ、5秒空けても一緒なんですけどね。気持ちです。^ ^;
と言う事で、めでたく処理は完了しました。
ちなみに、スクリプトを2つに分けたのは、1つのスクリプトだと連続的な処理構造が複雑になってしまうからです。
仮に顧客リストを内部のリストに格納してからであれば、一つのスクリプトで完結できたと思います。
しかし、100人以上の顧客名のリストは、残念ながら内部のリストに格納しきれんませんでした。
そこで、1件づつ読み込んで処理させたのです。
ノートカードを読み込む場合、読み込む命令を発行して、実際にデータを取得する部分は、dataserverイベントで行われます。
そして、HTTPリクエストをした場合、その結果を取得するのは、http_responseイベントになります。
一つのスクリプト内で書く場合は、双方のイベントでキックし合うような構造になってしまいます。
そこで、処理を単純化するために、「顧客カードを読み込む処理」と「HTTPリクエストする処理」を別スクリプトとして分離しました。双方のやり取りにはLinkメッセージを使ってます。
これだとループ的に処理させても、ループ部分はカードデータの読込部分だけになるので、比較的分かりやすく記述できると思います。
今回作ったスクリプトは汎用性も高いと思いますので、今後の顧客管理等にも上手く活用できるかも知れません。
ただ、一つだけ気になった事は、「アバターのUUIDって、勝手に調べて利用して良いの?」と言う事です。
う~ん。。。こう言うのって悪用する人が居なければ良いが・・・と思ってしまいました。
だって、例のテロオブジェクトを無差別に自動配布するなんて事もできてしまうのですよね。
勿論最低アバター名が分からなければ駄目ですけどね。
まあ、そんなこと言っても、SL内のアバター検索で、適当に検索して、プロフィールから送信もできてしまうのだから、気にしてもしょうがない話ですが。^ ^;
2008年01月29日
JIRAにコメントを出してみた。
しかし、対策はまだ見出せないので、一旦コピー版も販売を停止しました。T T
写真は条件等を変えたものを並べて検証中の風景。(泣ける><)

また、JIRAにも同様の現象が上がってましたので、そちらにもコメントを書いてみました。上手く伝わるかどうか?分かりませんが、個人的にはお手上げ状態ですから、藁にも縋る思いです。><
JIRAのページはこちらです。
http://jira.secondlife.com/browse/SVC-1184
<検証結果(中間報告)>
鯉は体長1mが基準サイズで、その場合の胸鰭パーツは厚さ1cm以下です。
体長に比例してパーツも大きさが拡大縮小されます。
体長=1.5m:発生しません。
体長=1m:4~5日程度で全リンク解除
体長=0.5m:2~3日程度で全リンク解除
体長=0.3m以下:1日~2日程度で全リンク解除
胸鰭を厚くすると、体長1mでも発生しなくなります。(まだ様子を見る必要は有る)
しかし、それ以上は厚くできないので、1m以下の場合は発生してしまいます。(魚では無くなってしまうから)
また、胸鰭のアニメーションを止めるとサイズが小さくても発生しないようです。(現在最終確認中)
そして、アタッチして使用する場合は、サイズが小さくても発生しません。
今の状態ですと、コイは調整しても最低1mサイズが限界と思います。
クマノミは1mサイズにはできないので、方式を変えるしか無いでしょう。
現在胸鰭のアニメーションを止めて、プリム数は増えますが、胸鰭を両側に1つづつにして、それを回転系の関数で処理する事も検討中です。
しかし、一番自然な動きはアニメーションさせることなので、この機能が使えないのは、実に残念です。
2008年01月15日
マンタより大きな鯉
まあ、起こらないに越した事は無いのですが・・・
で、現在店の水槽と海底では、テスト用に10秒毎にリンク状態をチェックし、リンクが解除されてしまったら、その時刻が分かるようにスクリプトを入れて試していいます。
が、一昨日にその対応してからは、何故か一向に発生しません。不思議ですねー。。。
ここまでの現象を整理すると以下のようになります。
1.発生対象
コイとカレクマノミ(単純回転タイプもフリームーブタイプも両方発生)のみに発生している。
サメ、ナポレオンフィッシュ等には発生していない。
また、コイも体長が1.5mのBigに設定してあるものには発生していない。
2.現象
強制的に全リンクが解除されてしまっている。
ヒレとヒゲが消失したのは、物理属性のため、リンクが解除されるとヒレとヒゲは浮力を失って落ちてしまうからで、ヒレの一部は回収できた。が、何故かヒゲは全く何処にも見当らず回収できていない。これも謎。
3.その他
気がついたのは1月1日にSASUKEで回転カクレクマノミのリンクが解除されて止まっていた時が最初だが、コイに関しては12日に初めて気がついた。恐らく1日~12日までの間に発生している。
更に最初に発生したのは、1固体を除き全て0.5m以下の小さいサイズであった。
13日には体長1mのMiddleサイズの物にも発生している。
上記の事から、どうも大きさにも関係があるように思えます。
そこで、現在はテストとして、ナポレオンフィッシュも体長0.5mにして試し始めました。
また鯉も体長3mと10mの巨大な物を作成して泳がせ始めてみました。
これらで暫く様子を見てみたいとも思います。
で、コレが体長10mの鯉。マンタよりも大きいよー><

それと、同様の現象は既にJIRAにも上がっているようです。
知人から情報がありました。私はまだその情報を見つけられずに居ます。やはりSculptedアニメを使ったサルのペットのようです。知人にURLを聞いて、見てみたいと思います。
とにかく、今月中は調査をしてみて、もし発生しないようなら、コピー不可の普及版の販売も再開したいと思います。
あ~しかし、疲れるなー
2007年12月29日
パーツズレの結論
<現象>
llMoveToTargetで移動している状態で、同時に2つのパーツがSculptedアニメで動いている場合に、リンクされた子プリムの位置がズレてくる。
ズレるのは、Sculptedパーツだけでは無く、リンクされている通常プリムのパーツも同様にズレる。
ズレは非常に少しづつズレて行くようで、時間の経過と共にズレは大きくなる。
ズレる方向は一定しており、空中よりも水中の方が著しくズレる。水中では1時間程度でズレを認識できるが、空中だと1日以上経過しないと認識できない。
1週間泳がせ続けた結果がコレ↓

あれから検証用に状態を変えた物で色々と試した。検証風景はコレ↓

その結果は以下のようになった。
<検証>
1.サメやイッカク等llMoveToTarget移動時に本体が同時にSculptedアニメで動いていても発生していない。
2.ナポレオンフィッシュで胸鰭の動きを止めて泳がせた場合にもズレは発生しない。
3.同様に尾びれの動きを止め、胸鰭だけ動かしてもズレは発生しない。
4.胸鰭と尾びれを同時に動かしても、llMoveToTargetを止めて動かないようにした場合はズレは発生しない。(物理属性でも)
5.胸鰭と尾びれがSculptedアニメで動き、目玉とか他のパーツには動くスクリプトが存在しないカクレクマノミでも同様の現象が発生した。
6.非物理のまま胸鰭と尾びれを動かしながらllSetPosで移動させ続けてもズレ無い。
7.X軸方向のみ往復させた場合、ズレは発生するが程度は小さい。(空中と同程度かそれ以下)
8.Y軸方向のみ往復させた場合、ズレの程度は大きく、短時間でズレが確認できる。
9.各子プリム・パーツに10分間隔で相対位置をチェックし、規定位置からズレて居た場合、元に戻すスクリプトを入れるとズレは補正され、ズレた状態にはならなくなる。
<結論>
llMoveToTargetで移動している状態で、同時に2つのパーツがSculptedアニメで動いている場合に発生する。
ズレは水中でY軸方向への移動時に著しく発生し、X軸方向への移動及び空中での移動時にはズレは少ない。
ただし、何故このような状態の時に、リンクプリムの位置がズレるのか?と言う事は分からない。
この辺はリンデン社に問い合わせるべきなのだろうか?
と言う事で、非常に限られた条件で発生するようなので、一般的には認識されていない現象と思う。
で対処としては、ズレが一気にズレるのでは無く、徐々にズレて行くことから、適当な時間毎に、リンクプリムの相対位置をチェックして、ズレが認められたら、強制的に補正する事にで解決できる。
まあ、こんな所でしょう。
このようなオブジェクトを作る人は、他には居ないと思うのだが、仮に上記条件に該当するようなオブジェクトを作った場合は、ズレるので気をつけましょう。