2007年12月12日

あるオブジェクトに対して別のオブジェクトの位置を指定する


マスター・スレーブを使うのかわかりませんが
すでに置かれているある(親)オブジェクトに対して
別の(子分)オブジェクトを持ち物からドラッグして、
親オブジェクトの一部に設置できるようにしたいのですが
ドラッグしたときの位置の指定をするスクリプトが自力ではわかりません…。
どなたか教えていただけますでしょうか…。
また、そういったスクリプトはあるのでしょうか。
よろしくおねがいします。



Posted by gumco  at 18:58 │Comments(6)TrackBack(0)スクリプト関連

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

http://oshiete.slmame.com/t88196

この記事へのコメント
gumcoさん、こんばんは

もうちょっと具体的にどうしたいのかが分かれば、助言できると思いますが・・・。
とりあえず、読んで理解した範囲で考えると、

先に置かれているオブジェクトA(親と子だとリンクしているようなイメージなので、A、Bにします)が、はっきりしている場合(名前かUUIDが分かっている)、後に置くオブジェクトBで「Aを指定してセンサー」を起動して、見つかったらその位置を取得し、一定距離を計算して移動する
というのが、おっしゃってるイメージに近いのかなぁと思います。

オブジェクトBのスクリプトのon_rezイベントで
1.オブジェクトAを探す(llSensor)
2.見つかった場合、そのオブジェクトの位置を取得(llDetectedPos)
3.その位置に相対距離を算出(b_pos = a_pos + <相対距離>)
4.自分(オブジェクトB)を動かす(llSetPos)

とすれば、よいのではないでしょうか。
回転も必要ならllDetectedRotして、相対回転値を計算してllSetRotすればできると思います。

先に置かれているオブジェクトAの名前で探知したときに同じ名前のオブジェクトが複数あったり、名前やUUIDが分からないでセンサーで探知したときに、探知したものが違ったり、複数のオブジェクトを探知した場合にどうするかとか、考えなければならないことはありますし(というか、それだとどのオブジェクトが目当てなのか分からないですけどね)、もっと違うイメージなのかもしれませんが、とりあえず書いてみました。
Posted by ささぴささぴ at 2007年12月12日 21:27
ささびさん、ありがとうございます!

もっと具体的に書けば良かったですね。
いまやりたいのはレコードプレーヤーがあって
そこにレコードを乗っけるとちゃんとターンテーブルの中心に
レコードが置かれる、ということなんです。

まだ初心者で書いてくださった事がこれに当てはまっているのかも
自分でよくわからないのですが、どうでしょうか…。
Posted by gumcogumco at 2007年12月12日 22:07
A:本体。B:レコード。

プラン①SENSOR関数
B:持ち物から出した時に、AをSENSORで見つける、座標を得る、移動する。

プラン②LISTEN関数と会話チャンネル
A:本体がLISTEN待ち。Bの会話に対して、Bへ場所の座標を送信。
B:レコード取り出したREZ:発信(合言葉のようなもの)。本体からの会話待ちLISTEN。座標を受信、移動する。
(合言葉のようなもの)を決めて誤動作が起きないように考えます。


まず。
レコードプレーヤー:オブジェクトの一部として、レコードを、動かして、
ターンテーブルの中心に置いて、回転をさせる、プリムの移動と座標を制作します。
SETPOS、SETROT、TARGETOMEGA

依頼のイメージのように、持ち物から取り出した時に、本体の場所へ移動させる制作。

さらに、検討プラン
オーナーの持ち物だけに動作する場合。 どこでも誰でも動作できる場合。
新しく追加する場合に、前のオブジェクトを削除する仕組み。
レコードプレーヤー本体が見つからない場合は自分で消える。
SETTIMEREVENT、DIE、などを組み合わせると良いですね^^b
Posted by shinichidon at 2007年12月13日 09:54
>shinichidonさん
ありがとうございます!!
①SENSOR関数のほうが若干簡単そうですね。
でもたしかに検討プランに書いてくださったことも
必要になりそうですねー。
難しそうですが、やってみまーす!
また宜しくお願いします〜。
Posted by gumcogumco at 2007年12月13日 10:52
gumcoさん、こんにちは。

レコードプレーヤーなのですね。
なかなか難しいですね。というのは、リアルな見た目としてプレーヤーの蓋を開け、レコードを取り出してプレーヤーの上にセットし、針を動かしてレコードに乗せ、蓋をしめるという「儀式」を表現したければ、アニメーションを作って、その動作と合わせてオブジェクトを動かすようなことまで再現しなければなりません。

そこまでしないにしても、先におっしゃっているように、アバターがプレーヤー付近にREZするような場合だと、うまくREZ出来たとして、一瞬でプレーヤーの上に移動してしまいます。またプレーヤーの方でもレコードが乗ったことを認知しなければ、回転させて針を動かすことができなくなるので、常にチェックしなければならなくなります。

楽な方法としては、レコードをプレーヤーにドロップするというのはどーでしょう?
そうすればレコード側でスクリプトで何かするということが無くなります。
(後処理を考えると、やはりスクリプトは必要ですけどね)

プレーヤー側の処理として
【メイン】
1.初期設定(必要な処理をしておく)
2.オブジェクトのドロップの許可(llAllowInventoryDrop)
(MOD権限がない人もドロップ可能にしたい場合のみ)

【チェンジイベント】(changed)
1.チェンジした内容がCHANGED_INVENTORYまたはCHANGED_ALLOWED_DROPの場合(if)
(MOD権限がある人しかドロップ出来ないのであればCHANGED_ALLOWED_DROPは必要ない)
2.ドロップされたモノの名前の取得(llDetectedName)
3.ドロップされたモノのタイプを取得(llGetInventoryType)
4-1.タイプがオブジェクトの場合(if)
4-2.オブジェクトを指定の位置にREZする(llRezObject)
4-3.適当なチャンネルにPlayを発言(llWhisper)
4-4.針をレコードの上に動かす(llSetLocalRot)
4-5.タイマー起動(レコードかけている時間)(llSetTimerEvent)
5-1.タイプがオブジェクト以外の場合(else)
5-2.コンテンツから削除する(llRemoveInventory)

【タイマーイベント】(timer)
1.針を元の位置に戻す(llSetLocalRot)
2.適当なチャンネルにStopを発言(llWhisper)
3.コンテンツの中のオブジェクト(ドロップされたレコード)を削除する(llRemoveInventory)
4.タイマー解除(llSetTimerEvent)

レコード側の処理
【リッスンイベント】(listen)
1-1.内容がPlayだったら(if)
1-2.オブジェクトを回転する(llTargetOmega)
2-1.内容がStopだったら(else if)
2-2.回転を止める(llTargetOmegaで無回転指定)
2-3.数秒待つ(llSleep)
2-4.自身を削除(llDie)

これでだいたい出来ると思いますが、レコードをかけている間の針の位置(トーンアームの角度)を細かく動かすのであれば、タイマー間隔を短くして、その都度計算して動かさなければならないでしょうし、オブジェクトの作り方によっても計算の仕方が変わってくるし動かすプリム数も変わってきます。
可変部分(トーンアームあたり)だけを別オブジェクトで作成し、プレーヤーのコンテンツに入れておいて、プレーヤーがREZされたらスクリプトで所定の位置にREZしてしまえば、レコードの再生に合わせて徐々に動かすことは楽になります。トーンアームはプレーヤーとの支柱をルートプリムにして作成し、そこを軸にして回転すればいいわけです。

たとえば、

プレーヤー側
1.自身の位置取得(llGetPos)
2.自身の回転取得(llGetRot)
3.トーンアームの位置、回転の計算
4.トーンアームをREZする(llRezObject)

トーンアーム部分
【メイン部分】
1.現在の自身の回転値を取得(初期位置)(llGetRot)

【リッスンイベント】(listen)
1-1.内容がPlayだったら(if)
1-2.初期位置からレコードの端の位置まで回転する(llSetRot)
1-3.タイマーイベント起動(llSetTimerEvent)
2-1.内容がStopだったら(else if)
2-2.初期位置に戻す(llSetRot)
2-3.タイマー解除(llSetTimerEvent)

【タイマーイベント】(timer)
タイマー間隔と再生中の全体の動かす量、アームの長さによって計算値は変わります。
1.現在位置に増加分を加算(+)
2.動かす(llSetRot)

ただし、この方法だと、プレーヤーを設置後に移動されると位置がずれてしまう点と、プレーヤーをTakeした場合にトーンアームだけ取り残されてしまいますので、なんらかの工夫が必要です。

またレコードはプレーヤー側でもレコード側でも最後は削除していますが、COPY権限を持たないレコードがあったとすれば無くなってしまいます(削除できないかも?)
さらに凝ったことをするのであれば、両面を再生するために途中でレコードを裏返したり、45rpmと33 1/3rpmを使い分けたり・・・などなど考えられます。
Posted by ささぴ at 2007年12月13日 11:09
>ささびさん
丁寧なご解説に感謝します!ほんとにありがとうございます!

ただ、まだ初心者で複雑な事はできないので
とりあえずプレイヤーが置いてあって
そこにレコード自体が回転しているものを
ドラッグすると(ドロップ?)
プレーヤーに対して指定の位置に収まってくれれば
とりあえず万歳って感じなんです…。
針もふたも動かなくていいと思ってます。
(本当はできたら最高ですが、いまのところ欲は出さずに…)
まずは最低限クリアしたら少しずつ発展させていこうとおもいます。
のでとても参考になります。

最低限それをやるとしたらやはりセンサーを入ればいんでしょうか。
自力でスクリプトを書いた事がないので
試してだめだったらまたご相談させていただこうと思います。

ありがとうございますー!
Posted by gumcogumco at 2007年12月13日 22:38