Gonbe Shan
2008年09月07日 21:52
integer pos_rand(integer max, integer min){ // 乱数の発生。min~maxの範囲
return ((integer)llFrand(max-min)+min);
}
integer calc_target(){//移動目標地点計算関数
float x_axi;//計算用ワーク
float y_axi;//計算用ワーク
vector now_destination=destination;//今居る場所の座標をセーブ
x_axi = pos_rand((integer)(x_max*10.0),(integer)(x_min*10.0))/10.0;//移動先の相対増分X座標求める。基点は設置基準点になる。
y_axi = pos_rand((integer)(y_max*10.0),(integer)(y_min*10.0))/10.0;//移動先の相対増分Y座標求める。基点は設置基準点になる。
destination = now_locate+<x_axi,y_axi,0.0>;//設置基準点に対する移動先座標をセット
sp = llFloor(llVecDist(now_destination, destination)/sp_const);
//現在地と次の移動地点間の距離(m)を求め、歩幅で除算して、移動に必要な歩数を求める。
if(sp==0){//spが0だと次の式でエラーになるから補正
sp=1;
}
x_add = (destination.x - now_destination.x)/sp;//1歩毎のX座標増分
y_add = (destination.y - now_destination.y)/sp;//1歩毎のY座標増分
return (TRUE);
}
integer disp_menu(){//ダイアログ表示関数
llDialog(key_id, "\n<< Main Menu >>\n\n", main_menu, chanel);
return(TRUE);
}
default
{
state_entry()
{
key_id = llGetOwner();//オーナーのUUIDをセーブ
now_locate = destination = llGetPos();//Rezポイントを基点へセット
state set_menu;
}
on_rez(integer param){
llResetScript();
}
}
state set_menu
{
state_entry()
{
llSetPos(now_locate);//移動基点に位置を戻している。。
status = 9;
llMessageLinked( LINK_SET, status, "Stop", NULL_KEY);//各パーツへ停止を伝達
handle = llListen(chanel, "", key_id, "");
disp_menu();
}
touch_start( integer total_number )
{
if(llDetectedKey(0)==key_id){
disp_menu();
}
}
link_message(integer sender_num, integer st, string msg, key id){
if(st == 1){
k=0;
state move_set;
}
}
listen(integer ch, string name, key id, string message){
if(message == "Moving"){
llListenRemove(handle);
now_locate = llGetPos();//ボタンを押した地点を基点にセット
status = 1;
llMessageLinked( LINK_SET, status, "Start", NULL_KEY);//各パーツへ活動開始を伝達
}else{
disp_menu();
}
}
on_rez(integer param){
llResetScript();
}
}
state moving
{
state_entry()
{
t=0;//タイマー用カウンタの初期化
destination = llGetPos();//現在地を移動の起点にセット
llSetTimerEvent(tm);//タイマーセット
}
touch_start( integer total_number )
{
if(llDetectedKey(0)==key_id){
llSetTimerEvent(0);
state set_menu;
}
}
timer(){
if(++t>sp){//タイマーで移動した歩数tが、予定歩数を超えているか?
state move_set;//移動目標へ到達した場合、再度目標設定へ。
}else{//各パーツを交互に同期を取って動かすための掛け声セット。
if(k==1){
k=2;
}else{
k=1;
}
destination = destination+<x_add,y_add,z_add>;//次の一歩で進む先の座標をセット
llMessageLinked( LINK_SET, 51, (string)(k+r_cnst), NULL_KEY);
//各パーツへ掛け声を伝達。歩くの場合はk+0、走るならk+2
llSetPos(destination);//一歩進む。
}
}
on_rez(integer param){
llResetScript();
}
}
state move_set
{
state_entry()
{
llSetTimerEvent(0);//タイマー停止
if(pos_rand(3,1)==2){//乱数で「歩く」と「走る」の切り替え
sp_const=0.5;//歩幅を50cmにセット
r_cnst=2;//各パーツへの伝達用
tm=0.5;//歩く時の間隔
}else{
sp_const=0.2;//歩幅を20cmにセット
r_cnst=0;//各パーツへの伝達用
tm=1.0;//歩く時の間隔
}
calc_target();// 移動目標計算関数呼び出し
llLookAt(destination, strength, damping);//移動目標へ体の向きを向ける
state moving;
}
touch_start( integer total_number )
{
if(llDetectedKey(0)==key_id){
state set_menu;
}
}
on_rez(integer param){
llResetScript();
}
}
****************************************************************************************************
コメントが入ってますから、特に説明も必要無いと思います。
ポイントはcalc_target()の中にあります。
乱数を用いて、移動基点から任意のX,Yの相対座標を求めています。
その座標地点が移動目標になりますが、そのままllSetPosで移動すると、瞬間で移動してしまいます。
そこで、現在地点と移動目標地点間の距離を求め(llVecDistで求めている)、その距離を歩幅で割って、移動地点へ到達するために必用な歩数を計算しています。
そして、1歩毎に変動するX座標とY座標の変動値を求めておいて、後はタイマーを使って一歩一歩llSetPosで必用歩数分進んでいるのです。
このまま入れてくれれば、最初にダイアログが出ますので、「Moving」のボタンを押してください。
5m四方の範囲をランダムに歩いたり走ったりして動き回ります。
タッチすると停止してダイアログが表示されます。
次に4本の足に入れるスクリプトが2つあります。
1つ目は足の位置を調整するスクリプトです。
****************************************************************************************************
list wing_pos = [<0.20079, 0.05560, -0.08351>,<0.20078, 0.05560, -0.07229>,<0.20078, 0.05560, -0.10229>,<0.20079, 0.05560, -0.14829>,<0.17493, 0.05560, -0.03829>];
default
{
link_message(integer sender_num, integer st, string msg, key id){
if(st == 51){
llSetPrimitiveParams([PRIM_POSITION, llList2Vector(wing_pos,(integer)msg)]);
}else if(st==9){
llSetPrimitiveParams([PRIM_POSITION, llList2Vector(wing_pos,0)]);
}
}
on_rez(integer param)
{
llResetScript();
}
}
****************************************************************************************************
最初の部分のwing_pos と言うリストに、足の位置座標が直に書かれています。
0番目が停止した時の足の位置
1番目と2番目が歩行時の足の位置で、メインから1,2、1,2と合図によって切り替わります。
3番目と4番目が走る時の足の位置で、メインから3,4、3,4と合図が送られてきます。
この座標は実際の作成したペットの足毎に値を調べて書き換えてください。
このまま使うととんでもない場所にパーツが飛んでしまいますから。
次に足の角度調整のスクリプトです。
****************************************************************************************************
list wing_rot = [<0.00000, 0.00000, 0.00000, 1.00000>,<0.00002, -0.13919, 0.00001, 0.99027>,<0.00001, 0.11319, 0.00002, 0.99357>,<0.00001, 0.34201, 0.00002, 0.93970>,<0.00002, -0.48482, 0.00001, 0.87461>];
default
{
link_message(integer sender_num, integer st, string msg, key id){
if(st == 51){
llSetLocalRot(llList2Rot(wing_rot,(integer)msg));
}else if(st==9){
llSetLocalRot(llList2Rot(wing_rot,0));
}
}
on_rez(integer param)
{
llResetScript();
}
}
****************************************************************************************************
これも同様に、wing_rot と言うリストの中に、足の回転角度座標が書いてあります。
位置と同様に、
0番目が停止した時の足の位置
1番目と2番目が歩行時の足の位置で、メインから1,2、1,2と合図によって切り替わります。
3番目と4番目が走る時の足の位置で、メインから3,4、3,4と合図が送られてきます。
になっています。
こちらもリスト内の座標は、各足毎に実際に調べて書き換えてください。
問題は、リストの中の位置座標と回転角度座標の求め方ですが、Gonbeの場合はパーツが少ないので、非常に原始的な作業で調べてスクリプトの中に書き込んでいます。
具体的には、各足に以下のスクリプトを入れておき、ポーズを作るたびに、各足にタッチして座標を表示させて転記してます。
****************************************************************************************************
default
{
touch_start(integer total_number)
{
llOwnerSay("Pos="+(string)llGetLocalPos()+"Rot="+(string)llGetLocalRot());
}
}
****************************************************************************************************
これも単純なスクリプトです。
上のようなポーズを作り、そこで各足にタッチして、座標を表示させてメモしておき、スクリプトの中に記述してます。
もし、パーツが多いとか、面倒だーと思う人は、自分でもっと簡単なツールを作れば良いと思います。
尚、このスクリプトは商品等にも自由に使っていただいてかまいませんが、先に書きましたとおり一切のサポート等は行いませんし、このスクリプトにて発生した、いかなる問題に関しても、Gonbeは一切の責任は負いませんのでご了承下さい。
また、内容に関する問い合わせにも応じられません。
あくまで自己責任にてご利用下さい。
それでは、SL界に一杯可愛いペット達が生まれますように。^ ^