2009年01月23日
物々交換できる箱を作りたい
スクリプト、いくら考えても調べても、自分でやると機能しますが、
他人がやるとうまくいきません。
何が悪いのか、教えていただけると助かります。
簡潔に要旨を書きます。
自分が作って販売した初期のアニメーションが気に入らないため
買っていただいた人に改良したものと交換できる箱を設置したい。
llAllowInventoryDrop( TRUE );
だけでは、誰がドロップしたか判定できないので、まずタッチしてもらい
タイマーをかけて一時的にドロップ可とした。
他の人にやってもらうとこの部分は機能している。
ドロップされたアニメ名とUUIDが一致すると新作アニメを渡す。
違うアニメをリネームして該当アニメに見せかけても受け付けない。
ドロップされたままコンテンツを放置すると次にドロップしたものに
1, 2, 3,・・・と次々と名前の後に自動的に番号が振られ、
アニメ名が一致しなくなるため、ドロップされるとすぐ
llRemoveInventory("アニメ名");
で消去するようにした。
自分でテストすると全て機能するが、他人がやるとどれも機能しない。
おそらく、他人ではコンテンツの中身を消去できないのではないか?
以下、ソースです。このまま使ってもうまくいきません。
-----------------------------------------------------------------------------------------------------
key avatar;
string animation_name = "アニメのUUIDをここに入れる";
default
{
touch_start(integer total_number)
{ avatar = llDetectedKey(0);
llAllowInventoryDrop( TRUE );
llSetTimerEvent(30);
llSay(0, "Drop 'アニメ名' animation here within 30 seconds\n 30秒以内に'アニメ名'アニメをドロップしてください");
}
changed( integer changed_flag )
{ key chk = llGetInventoryKey("アニメ名");
if ( changed_flag & CHANGED_INVENTORY ) {
if(chk == animation_name)
{
llSay(0, "OK");
llGiveInventory(avatar , "渡すアニメ名");
llRemoveInventory("アニメ名");
llSetTimerEvent(0);
llAllowInventoryDrop( FALSE );
}
else{
llSay(0, "NO");
llRemoveInventory("アニメ名");
llSetTimerEvent(0);
llAllowInventoryDrop( FALSE );
}
}
}
timer()
{
llAllowInventoryDrop( FALSE );
llSetTimerEvent(0);
llSay(0, "Time out. Touch again");
}
}
-----------------------------------------------------------------------------------------------------
うまくいく方法がありましたら宜しくお願いします。
他人がやるとうまくいきません。
何が悪いのか、教えていただけると助かります。
簡潔に要旨を書きます。
自分が作って販売した初期のアニメーションが気に入らないため
買っていただいた人に改良したものと交換できる箱を設置したい。
llAllowInventoryDrop( TRUE );
だけでは、誰がドロップしたか判定できないので、まずタッチしてもらい
タイマーをかけて一時的にドロップ可とした。
他の人にやってもらうとこの部分は機能している。
ドロップされたアニメ名とUUIDが一致すると新作アニメを渡す。
違うアニメをリネームして該当アニメに見せかけても受け付けない。
ドロップされたままコンテンツを放置すると次にドロップしたものに
1, 2, 3,・・・と次々と名前の後に自動的に番号が振られ、
アニメ名が一致しなくなるため、ドロップされるとすぐ
llRemoveInventory("アニメ名");
で消去するようにした。
自分でテストすると全て機能するが、他人がやるとどれも機能しない。
おそらく、他人ではコンテンツの中身を消去できないのではないか?
以下、ソースです。このまま使ってもうまくいきません。
-----------------------------------------------------------------------------------------------------
key avatar;
string animation_name = "アニメのUUIDをここに入れる";
default
{
touch_start(integer total_number)
{ avatar = llDetectedKey(0);
llAllowInventoryDrop( TRUE );
llSetTimerEvent(30);
llSay(0, "Drop 'アニメ名' animation here within 30 seconds\n 30秒以内に'アニメ名'アニメをドロップしてください");
}
changed( integer changed_flag )
{ key chk = llGetInventoryKey("アニメ名");
if ( changed_flag & CHANGED_INVENTORY ) {
if(chk == animation_name)
{
llSay(0, "OK");
llGiveInventory(avatar , "渡すアニメ名");
llRemoveInventory("アニメ名");
llSetTimerEvent(0);
llAllowInventoryDrop( FALSE );
}
else{
llSay(0, "NO");
llRemoveInventory("アニメ名");
llSetTimerEvent(0);
llAllowInventoryDrop( FALSE );
}
}
}
timer()
{
llAllowInventoryDrop( FALSE );
llSetTimerEvent(0);
llSay(0, "Time out. Touch again");
}
}
-----------------------------------------------------------------------------------------------------
うまくいく方法がありましたら宜しくお願いします。
テクスチェンジのHUDについて
モール用のプリムカウンターを探しています
連続するアニメーションの処理
オブジェクトの上にフローティングテキストを出す。
チャットログの盗聴について
椅子に座った後で位置調整できるスクリプト
モール用のプリムカウンターを探しています
連続するアニメーションの処理
オブジェクトの上にフローティングテキストを出す。
チャットログの盗聴について
椅子に座った後で位置調整できるスクリプト
changedで CHANGED_INVENTORYではなく
CHANGED_ALLOWED_DROPなども見てみてください
詳しいことは、portalとかどうぞ
http://wiki.secondlife.com/wiki/Changed
UUID固定だからどんなアニメ入れてもNG判定になるんじゃないですかね?
自分でコピーしてもしかり。
すでにやってらっしゃるかもしれませんが
これ、ところどころにOwnerSayとかいれて
どこまで実行されてるかとか見てみると
問題の切り分けができると思います。
がんばってください。
仕様について
こういうケースも考えられるんじゃないでしょうか
1)ある人Aがタッチ
2)別の人Bがタッチ
3)Aがいれる
4)BにGiveしてしまう
交換機の近くで待ち伏せしてると、タダでアニメが手に入ります
処理中は、別stateで処理するなど、
なんらかの対応が必要かもしれません。
また、こちらは動作上問題はないのですが
全く無関係のアニメやオブジェクトを
大量に投入されても、Removeが名前指定なので
処理後、ゴミが残ります。
教えていただいたwikiにCHANGED_INVENTORYだと、次のようにありますね!
Prim inventory has changed (owner adding inventory only).
「オーナーだけ」・・これが原因に違いなさそう。
CHANGED_ALLOWED_DROPでやってみます。
なるほど、アニメ投入前に別の人が連続タッチするとそっちに権利が移りますね!
ごみは手動で掃除しようと思ってました。渡すためのアニメだけは残ってもらわないといけないので、全部消去したらまずいです。
「~以外を消す」ってできましたか?
llGetInventoryType( string name );
あたりでコンテンツ内の名前をとってきて「もし~以外があれば全部消す」って感じでしょうか?
> arz Nitely さん、TBH さん
アニメのUUIDはいくらコピーしても、他人に渡しても変わりません。
古いものも新しいものも同じUUIDです。これを確かめた後でこのスクリプトを考えました。
>古いものも新しいものも
=同じアニメでインベントリに入れた時期が違っていても
つまりベンダーから最近自分で買ってみたものでも、最初のオリジナルでも、同じUUIDだったということです。
頭に焼き付いてました。
なんでわざわざ分けるんだー!って思いますよね。
「~以外を○○する」は、単純にループして
必要なものかどうかを判断して処理するしかないです。
正規表現とか使えるといいのになぁ
※2primにして、新バージョンは子primにいれておいて
そこから渡すようにすれば、簡単になるかもですね。
これは交換式のバージョンアップに便利な箱になると思います。
がんばってください。
おぉ、大変失礼しました!!
これは知りませんでした^^;
勉強になりました〜!!
思った通りの動作をしています。
教えてくださった方々、ありがとうございました。
別stateで処理するとタッチしたアバターのキーを保持できませんでしたので、一回キーをリストに格納しそれをllList2Key()で取り出して使ってみました。
これで一応操作中は他人がタッチできなくなりました。(他人がドロップはできるが、タッチした人に新作が渡される)
格納したアバターのキーは操作が終わるとスクリプトをリセットして消去しています。操作中の一人分しか覚える必要はないのでこれでいいかと。
(補足)私のアニメは全部フルパーミッションです。
以下に改良版を上げておきます。念のために余分に書いている部分もあります。ゴミ処理や2プリム化はやっていないです。
ご自由に改変してお使いいただいてかまいません。
----------------------------------------------------------------------------
list av_key = [];
string animation_name = "古いアニメのUUID";
default{
state_entry(){
llSay(0, "This can be used now.\n次の方、ご使用できます。");
llAllowInventoryDrop( FALSE );
}
touch_start(integer detected){
key id = llDetectedKey(0);
av_key += id;
state next;
}
}
state next{
state_entry(){
llSetTimerEvent(30);
llSay(0, "Drop '古いアニメ名' animation here within 30 seconds\n30秒以内に'古いアニメ名'アニメをドロップしてください");
llAllowInventoryDrop( TRUE );
}
changed( integer changed_flag )
{
key chk = llGetInventoryKey("古いアニメ名");
if ( changed_flag & CHANGED_ALLOWED_DROP ) {
if(chk == animation_name)
{
llSay(0, "OK");
key give =llList2Key(av_key, 0);
llGiveInventory(give , "渡す新作アニメ名");
llRemoveInventory("古いアニメ名");
llSetTimerEvent(0);
llAllowInventoryDrop( FALSE );
llResetScript();
state default;
}
else{
llSay(0, "NO");
llRemoveInventory("古いアニメ名");
llSetTimerEvent(0);
llAllowInventoryDrop( FALSE );
llResetScript();
state default;
}
}
}
timer(){
llAllowInventoryDrop( FALSE );
llSetTimerEvent(0);
llSay(0, "Time out. Touch again");
llResetScript();
state default;
}
}
ブログも11月から進んでないようでしたので心配でした。
コメントしていただけてとてもうれしいです。
自分だけで、コンパイル成功して、動作確認OKでも、こうやって見ていただくことによって色々修正点が出てきますので助かります。
いきなり正解を示されるより、自分で回り道してみたほうがずっと知識が定着しますね。
(1)
defaultのstate_entryで次の人に「使用できます」と言っているのは、Rezしたときか、処理が終わって戻ってきたときにしか発言しないからでした。
テスト中もわかりやすく簡単なのでこうしていました。
本設置では使用方法の説明テクスチャーが切り替わる仕様にするつもりです。
(2)
グローバル変数にkey型で持つやり方が間違っていたのか、うまくいきませんでしたので、こういう形に行き着いてしまいました。
でもこれでリストに追加するのと取り出し方法がわかりましたので勉強になりました。
(3)
まさにご指摘の通りで、違うものをドロップするとエラー表示が出ます。
でも間違った使い方したのが使用者にはっきり伝わっていいかな^^って。
尚、別のアニメをリネームして"古いアニメ名"に見せかけた場合はちゃんと削除されます。
(4)
「念のために余分に書いている部分」と前置きしたのはこれです。
最初の頃はスクリプトって答えが一つしかないものだと思ってました。
色々やっても同じ動作をさせることができるというのは、見た人にエッセンスを抜き出して行ってもらうにも有用かもしれません。
完璧じゃないものを提示して、いろいろな人にコメントをいただけるほうが、「教えて!」の趣旨としては合っていそうな気がします。
私も赤色で出るようにしています。
別アカウントアバターに非表示設定にしてやってみました。
チャットに非表示にしていてもオブジェクトの上にエラー警告マークが出ます。すぐ消えますが。
上記スクリプト中、グローバル変数をkey型にしてうまくいきました。
変更点のみ抜粋します。
1行目:list av_key = []; → key av_key;
10行目:av_key += id; → av_key = id;
28行目:key give =llList2Key(av_key, 0); 削除
29行目:llGiveInventory(give , "渡す新作アニメ名");
→giveをav_keyに
すべてのllResetScript();を削除
余分に書いていた部分を削除
それと、touch_startではなぜか反応が悪くダブルクリックが必要でしたので、touch_endに変えてみましたら一発で反応するようになりました。
ウチのマウスが悪いのかと思っていたけど何か違うようです。