2009年06月29日
アナログストップウォッチ(スクリプト)
この記事、途中まで書いたら消えちゃった・・・・・
泣きそうな、なつです><
こんばんは^^
さてさて、
この前の記事に書いた、アナログストップウォッチのスクリプトですけど、
できたので、公開させて頂きます。
アナログストップウォッチ スクリプト の検索キーワード(私のブログでは、一番多いキーワード)で、
ここにこられた方に、大正解ではないにしろ、
すこしでも、ヒントになればと思います^^
まずは、ストップウォッチの画像です↓

文字盤とか、マジになって書いちゃってますけど、
商品では、ございませんのでm(__)m
機能説明
自動車レースとかの、何周もする周回毎のタイム計測用です。
よーいドンで、時計本体タッチします(計測開始です)
1周目計測ライン通過時に、再度、時計本体タッチします(1周目のタイムがチャットに「1周目xx時間xx分xx秒.xx」のように表示されます)
2周目以降、時計本体タッチで、同じことを繰り返します。
最終周回時(ゴールですね)のみ、黄色いボタンをタッチします。(最終周回タイム&トータルタイムを表示し、リセットします)
赤いボタンはリセットボタンです、計測中断に使用します。
一応、動く形にはなってますけど、
ちゃんとしたケースもなければ、レンズもありません。
これに、パーツを付け足すとか、分解して作り直すとか、ご自由にどうぞ^^
スクリプト(ざ~読んでもらってOKです、スクリプトは配布中です)
STOPWATCH(main)
integer onoff = FALSE; //計測中か?そうでないか?判定用
integer sec = 0; //針作動用の秒数カウンタ
float zan = 0.0; //前回までのタイム
integer cou = 0; //ラップ数カウント
stop_A()
{
cou = cou + 1; //ラップ数を毎回1加算
float Ntime= llGetTime() - zan;//スタートしてから現在までの稼動時間から前回のタイムを引く(現在のラップタイムを算出してNtimeに格納)
integer N = (integer)Ntime;//不動少数点数型(float)Ntimeを整数型(integer)に変換して N に格納(これで秒数だけ取り出せる^^)
integer H = N / 3600; //秒数Nを3600で割って、商(時間)を求め,Hに格納・・・(1時間に満たない場合は0)
integer M = (N - H * 3600) / 60;//全秒数Nから、時間分の秒(H*3600)を引いて、60で割った商(分)をMに格納
integer S = N % 60; //全秒数Nを60で割ったあまりをSに格納(秒)
float SS = (Ntime - N) * 1000; //少数以下をもとめる・・・不動少数点数型(float)Ntimeから整数部Nを引いて1000をかける
integer SSS = (integer)SS; //SSにまだ少数以下が含まれるので、整数型に変換して切捨て、SSSに格納
llSay(0,(string)cou +"ラップ "+ (string)H + "時間 " + (string)M + "分 " + (string)S + "秒" + " ." + (string)SSS);
//H,M,S,SSSを文字列型に変換し単位をつけて、チャット出力
zan = llGetTime();//現在のまでの時間を一時格納(次回のラップタイムの計算用)
}
start_A()
{
sec = 0; //針作動用の秒カウンターを0リセット
llResetTime(); //スクリプト稼動時間カウンタを0リセット
llSay(0,"START "); //スタートをチャットで宣言
onoff=TRUE; //タイマー判定を動いてる状態に
llSetTimerEvent(0.01); //タイマーイベントを0.01秒毎で開始
}
reset()
{
sec = 0; //針作動用の秒カウンターを0リセット
llResetTime(); //スクリプト稼動時間のリセット
onoff=FALSE; //計測状態の解除
llSetTimerEvent(0);//タイマーイベントを止める
llMessageLinked(LINK_ALL_CHILDREN, 0,"","");//全子プリムに対して、0を送信(針が12時にそろう
zan = 0.0;//変数をリセット
cou = 0; //変数をリセット
llSetText("TOUCH START", <1,1,1>, 1.5);
llSay(0,"RESET");
}
default
{
touch_start( integer total_number )
{
string pname = llGetLinkName(llDetectedLinkNumber(0));//タッチされたプリムの名前を格納
if(pname == "RESET"){//もしタッチされたプリムの名前がRESETだったら~(計測中断用)
reset();//resetを呼び出す
}
else if(pname == "S&S"){//もしタッチされたプリムの名前がS&Sだったら~(計測終了=最終ラップ用)
float Ntime= llGetTime();
stop_A();
integer N = (integer)Ntime;//不動少数点数型(float)Ntimeを整数型(integer)に変換して N に格納(これで秒数だけ取り出せる^^)
integer H = N / 3600; //秒数Nを3600で割って、商(時間)を求め,Hに格納・・・(1時間に満たない場合は0)
integer M = (N - H * 3600) / 60;//全秒数Nから、時間分の秒(H*3600)を引いて、60で割った商(分)をMに格納
integer S = N % 60; //全秒数Nを60で割ったあまりをSに格納(秒)
float SS = (Ntime - N) * 1000; //少数以下をもとめる・・・不動少数点数型(float)Ntimeから整数部Nを引いて1000をかける
integer SSS = (integer)SS; //SSにまだ少数以下が含まれるので、整数型に変換して切捨て、SSSに格納
llSay(0,"トータルタイム " + (string)H + "時間 " + (string)M + "分 " + (string)S + "秒" + " ." + (string)SSS);
reset();
}
else{
if(onoff==TRUE){ //タッチされた時に、計測中だった場合の処理-------------------------------
stop_A();
}
else{//タイマーが動いてなかった場合の処理 +++++++++++++++++++++++++++++++++++++++++++++++++++
start_A();
}
}
}
timer() //タイマーイベント
{
integer Nsec = (integer)llGetTime();//現在のスクリプト実行時間の秒数(整数値のみ)をNsecに格納
llSetText((string)llGetTime(), <1,0.2,0.2>, 1.5);
if (sec != Nsec){ //cseとNsecを判定、同じでなければ、次の行を実行(sec=初期値は0)
llMessageLinked(LINK_ALL_CHILDREN, Nsec,"",""); //前の秒数と違う場合のみ、全子プリムに秒数を送信
}
sec = Nsec; //secに現在の秒数を格納
}
}
-----------------------------------------------------------------------
SW-s(秒針用)
default
{
state_entry()
{
}
link_message(integer sender_num, integer num, string str, key id)
{
float rotTime = num * 6;
llSetLocalRot(llEuler2Rot(-(<0, 0, rotTime * DEG_TO_RAD>)));
}
}
-----------------------------------------------------------------------
SW-m(分針用)
default
{
state_entry()
{
}
link_message(integer sender_num, integer num, string str, key id)
{
float rotTime = (num / 60) * 6;
llSetLocalRot(llEuler2Rot(-(<0, 0, rotTime * DEG_TO_RAD>)));
}
}
------------------------------------------------------------------------
SW-h(時間針用)
default
{
state_entry()
{
}
link_message(integer sender_num, integer num, string str, key id)
{
float rotTime = (num / 3600) * 6;
llSetLocalRot(llEuler2Rot(-(<0, 0, rotTime * DEG_TO_RAD>)));
}
}
---------------------------------------------------------------------------
以上
メインのスクリプト(親プリムに入れるスクリプト)は、スクリプト内部に説明を書きました。
(読みにくいけど・・・)
大まかな説明
メインのスクリプトで、「llGetTime() = スクリプトの実行時間」を使って、時間を計測してます。
そこから、秒数以下を切り飛ばして、
1秒毎に全子プリム(針プリムです)に、送信してます。
各針プリムは、受信した秒数を自分の表示する単位(時間、分、秒)に変換して、角度に直してます。
注意1
メインのスクリプト内部で、タイマーイベントを0.01秒毎に実行するように指定してますが、
これは、計測中にフローティングテキストで、秒を表示してるんですけど、
それが、ガガガ~って変わってるように見えるように、細かい時間を指定してますけど、
フローティングテクストは必要ないとか、
すこしでも負荷を軽くしたい場合は、もっと大きな時間でいいと思います。
とは、言っても、1秒以上ではダメですし~
0.5ぐらいでいいんじゃないかと思いますけど・・・・
そこは、実験で・・・・お願いします><
注意2
タイマーイベント内で、すこしややこしい事してます。
そもそも、タイマーイベントを0.01秒毎に呼び出すってのが、諸悪の根源かもしれないんですけど、
0.01秒毎に全子プリムに秒を送信にすると、想像ですけど、すっごく負荷がかかるんじゃないか?と思って、
0.01秒前と今と比べて、秒が変わってる時だけ、
全子プリムに秒数を送信するようにしてます。
もし、計測タイムと針の位置の一致はきにしない、
針は飾り程度で、動いてれば、まぁ~いいよ~
(フローティングテキストいらない)
なら、
タイマーイベントは1秒毎に実行して、
タイマーイベント内部も、毎回、全子プリムに秒数を送信でいいですね^^
あと、
start_A() とか stop_A() とか、タッチイベント内に直接書いてもいいんですけど、
拡張性を考えて・・・・
いや^^ほんとは、
ダイアログから、周回毎の計測するタイプ(現在の仕様)とインターバルを加算しないタイプ(試合時間みたいな?)を
切り替えようかな~とも思ったんですけど^^
まぁ^^今回は未実装ってことで^^
えっと、
DCCXXIII本店(Themis)に置いてます

本店の屋根の上です、看板のすぐ後ろです^^
隠してるわけではないんですけど^^
商品ではないので、店舗外に置かせてもらいました^^
中身は、ストップウォッチ本体、スクリプト(メイン、時間針、分針、秒針)、文字盤テクスチャが入ってます。
全部、フルパーミッションですので、煮るなる焼くなりご自由にお使いくださいませ^^
ちょっとだけ宣伝^^



新作ではないんですけど~
ストップウォッチ機能付きのポケットウォッチも販売しております^^
デモもありますので、よろしかったらお試しくださいませm(__)m
記事途中できえちゃったから、書くのに2時間もかかったんですけど~
また、分かりにくい記事になっしまいました><
きっと、いじくってもらえれば、理解していただける・・・・・と思います(本店屋根の上のストップウォッチ)
あ、大きな声では言えないけど、0$です^^
ないしょですよ^^
では、今日はこの辺で^^
長文のお付き合いありがとうございました^^
おやすみなさいませm(__)m
泣きそうな、なつです><
こんばんは^^
さてさて、
この前の記事に書いた、アナログストップウォッチのスクリプトですけど、
できたので、公開させて頂きます。
アナログストップウォッチ スクリプト の検索キーワード(私のブログでは、一番多いキーワード)で、
ここにこられた方に、大正解ではないにしろ、
すこしでも、ヒントになればと思います^^
まずは、ストップウォッチの画像です↓

文字盤とか、マジになって書いちゃってますけど、
商品では、ございませんのでm(__)m
機能説明
自動車レースとかの、何周もする周回毎のタイム計測用です。
よーいドンで、時計本体タッチします(計測開始です)
1周目計測ライン通過時に、再度、時計本体タッチします(1周目のタイムがチャットに「1周目xx時間xx分xx秒.xx」のように表示されます)
2周目以降、時計本体タッチで、同じことを繰り返します。
最終周回時(ゴールですね)のみ、黄色いボタンをタッチします。(最終周回タイム&トータルタイムを表示し、リセットします)
赤いボタンはリセットボタンです、計測中断に使用します。
一応、動く形にはなってますけど、
ちゃんとしたケースもなければ、レンズもありません。
これに、パーツを付け足すとか、分解して作り直すとか、ご自由にどうぞ^^
スクリプト(ざ~読んでもらってOKです、スクリプトは配布中です)
STOPWATCH(main)
integer onoff = FALSE; //計測中か?そうでないか?判定用
integer sec = 0; //針作動用の秒数カウンタ
float zan = 0.0; //前回までのタイム
integer cou = 0; //ラップ数カウント
stop_A()
{
cou = cou + 1; //ラップ数を毎回1加算
float Ntime= llGetTime() - zan;//スタートしてから現在までの稼動時間から前回のタイムを引く(現在のラップタイムを算出してNtimeに格納)
integer N = (integer)Ntime;//不動少数点数型(float)Ntimeを整数型(integer)に変換して N に格納(これで秒数だけ取り出せる^^)
integer H = N / 3600; //秒数Nを3600で割って、商(時間)を求め,Hに格納・・・(1時間に満たない場合は0)
integer M = (N - H * 3600) / 60;//全秒数Nから、時間分の秒(H*3600)を引いて、60で割った商(分)をMに格納
integer S = N % 60; //全秒数Nを60で割ったあまりをSに格納(秒)
float SS = (Ntime - N) * 1000; //少数以下をもとめる・・・不動少数点数型(float)Ntimeから整数部Nを引いて1000をかける
integer SSS = (integer)SS; //SSにまだ少数以下が含まれるので、整数型に変換して切捨て、SSSに格納
llSay(0,(string)cou +"ラップ "+ (string)H + "時間 " + (string)M + "分 " + (string)S + "秒" + " ." + (string)SSS);
//H,M,S,SSSを文字列型に変換し単位をつけて、チャット出力
zan = llGetTime();//現在のまでの時間を一時格納(次回のラップタイムの計算用)
}
start_A()
{
sec = 0; //針作動用の秒カウンターを0リセット
llResetTime(); //スクリプト稼動時間カウンタを0リセット
llSay(0,"START "); //スタートをチャットで宣言
onoff=TRUE; //タイマー判定を動いてる状態に
llSetTimerEvent(0.01); //タイマーイベントを0.01秒毎で開始
}
reset()
{
sec = 0; //針作動用の秒カウンターを0リセット
llResetTime(); //スクリプト稼動時間のリセット
onoff=FALSE; //計測状態の解除
llSetTimerEvent(0);//タイマーイベントを止める
llMessageLinked(LINK_ALL_CHILDREN, 0,"","");//全子プリムに対して、0を送信(針が12時にそろう
zan = 0.0;//変数をリセット
cou = 0; //変数をリセット
llSetText("TOUCH START", <1,1,1>, 1.5);
llSay(0,"RESET");
}
default
{
touch_start( integer total_number )
{
string pname = llGetLinkName(llDetectedLinkNumber(0));//タッチされたプリムの名前を格納
if(pname == "RESET"){//もしタッチされたプリムの名前がRESETだったら~(計測中断用)
reset();//resetを呼び出す
}
else if(pname == "S&S"){//もしタッチされたプリムの名前がS&Sだったら~(計測終了=最終ラップ用)
float Ntime= llGetTime();
stop_A();
integer N = (integer)Ntime;//不動少数点数型(float)Ntimeを整数型(integer)に変換して N に格納(これで秒数だけ取り出せる^^)
integer H = N / 3600; //秒数Nを3600で割って、商(時間)を求め,Hに格納・・・(1時間に満たない場合は0)
integer M = (N - H * 3600) / 60;//全秒数Nから、時間分の秒(H*3600)を引いて、60で割った商(分)をMに格納
integer S = N % 60; //全秒数Nを60で割ったあまりをSに格納(秒)
float SS = (Ntime - N) * 1000; //少数以下をもとめる・・・不動少数点数型(float)Ntimeから整数部Nを引いて1000をかける
integer SSS = (integer)SS; //SSにまだ少数以下が含まれるので、整数型に変換して切捨て、SSSに格納
llSay(0,"トータルタイム " + (string)H + "時間 " + (string)M + "分 " + (string)S + "秒" + " ." + (string)SSS);
reset();
}
else{
if(onoff==TRUE){ //タッチされた時に、計測中だった場合の処理-------------------------------
stop_A();
}
else{//タイマーが動いてなかった場合の処理 +++++++++++++++++++++++++++++++++++++++++++++++++++
start_A();
}
}
}
timer() //タイマーイベント
{
integer Nsec = (integer)llGetTime();//現在のスクリプト実行時間の秒数(整数値のみ)をNsecに格納
llSetText((string)llGetTime(), <1,0.2,0.2>, 1.5);
if (sec != Nsec){ //cseとNsecを判定、同じでなければ、次の行を実行(sec=初期値は0)
llMessageLinked(LINK_ALL_CHILDREN, Nsec,"",""); //前の秒数と違う場合のみ、全子プリムに秒数を送信
}
sec = Nsec; //secに現在の秒数を格納
}
}
-----------------------------------------------------------------------
SW-s(秒針用)
default
{
state_entry()
{
}
link_message(integer sender_num, integer num, string str, key id)
{
float rotTime = num * 6;
llSetLocalRot(llEuler2Rot(-(<0, 0, rotTime * DEG_TO_RAD>)));
}
}
-----------------------------------------------------------------------
SW-m(分針用)
default
{
state_entry()
{
}
link_message(integer sender_num, integer num, string str, key id)
{
float rotTime = (num / 60) * 6;
llSetLocalRot(llEuler2Rot(-(<0, 0, rotTime * DEG_TO_RAD>)));
}
}
------------------------------------------------------------------------
SW-h(時間針用)
default
{
state_entry()
{
}
link_message(integer sender_num, integer num, string str, key id)
{
float rotTime = (num / 3600) * 6;
llSetLocalRot(llEuler2Rot(-(<0, 0, rotTime * DEG_TO_RAD>)));
}
}
---------------------------------------------------------------------------
以上
メインのスクリプト(親プリムに入れるスクリプト)は、スクリプト内部に説明を書きました。
(読みにくいけど・・・)
大まかな説明
メインのスクリプトで、「llGetTime() = スクリプトの実行時間」を使って、時間を計測してます。
そこから、秒数以下を切り飛ばして、
1秒毎に全子プリム(針プリムです)に、送信してます。
各針プリムは、受信した秒数を自分の表示する単位(時間、分、秒)に変換して、角度に直してます。
注意1
メインのスクリプト内部で、タイマーイベントを0.01秒毎に実行するように指定してますが、
これは、計測中にフローティングテキストで、秒を表示してるんですけど、
それが、ガガガ~って変わってるように見えるように、細かい時間を指定してますけど、
フローティングテクストは必要ないとか、
すこしでも負荷を軽くしたい場合は、もっと大きな時間でいいと思います。
とは、言っても、1秒以上ではダメですし~
0.5ぐらいでいいんじゃないかと思いますけど・・・・
そこは、実験で・・・・お願いします><
注意2
タイマーイベント内で、すこしややこしい事してます。
そもそも、タイマーイベントを0.01秒毎に呼び出すってのが、諸悪の根源かもしれないんですけど、
0.01秒毎に全子プリムに秒を送信にすると、想像ですけど、すっごく負荷がかかるんじゃないか?と思って、
0.01秒前と今と比べて、秒が変わってる時だけ、
全子プリムに秒数を送信するようにしてます。
もし、計測タイムと針の位置の一致はきにしない、
針は飾り程度で、動いてれば、まぁ~いいよ~
(フローティングテキストいらない)
なら、
タイマーイベントは1秒毎に実行して、
タイマーイベント内部も、毎回、全子プリムに秒数を送信でいいですね^^
あと、
start_A() とか stop_A() とか、タッチイベント内に直接書いてもいいんですけど、
拡張性を考えて・・・・
いや^^ほんとは、
ダイアログから、周回毎の計測するタイプ(現在の仕様)とインターバルを加算しないタイプ(試合時間みたいな?)を
切り替えようかな~とも思ったんですけど^^
まぁ^^今回は未実装ってことで^^
えっと、
DCCXXIII本店(Themis)に置いてます

本店の屋根の上です、看板のすぐ後ろです^^
隠してるわけではないんですけど^^
商品ではないので、店舗外に置かせてもらいました^^
中身は、ストップウォッチ本体、スクリプト(メイン、時間針、分針、秒針)、文字盤テクスチャが入ってます。
全部、フルパーミッションですので、煮るなる焼くなりご自由にお使いくださいませ^^
ちょっとだけ宣伝^^



新作ではないんですけど~
ストップウォッチ機能付きのポケットウォッチも販売しております^^
デモもありますので、よろしかったらお試しくださいませm(__)m
記事途中できえちゃったから、書くのに2時間もかかったんですけど~
また、分かりにくい記事になっしまいました><
きっと、いじくってもらえれば、理解していただける・・・・・と思います(本店屋根の上のストップウォッチ)
あ、大きな声では言えないけど、0$です^^
ないしょですよ^^
では、今日はこの辺で^^
長文のお付き合いありがとうございました^^
おやすみなさいませm(__)m
Posted by natu(DCCXXIII) at 04:13│Comments(0)
│商品開発秘話(スクリプト、プリムなど)