HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2012
0404
にゃんちゃんHSPで音ゲーを作るために11解決


にゃんちゃん

リンク

2012/4/4(Wed) 14:09:34|NO.45785

HSPで音ゲーを作ろうと思い、テンポを設定して1拍をカウントするモジュールを作ったのですが、awaitではどうしても時間に誤差がでてしまいます。
こういう現象を回避し、設定したテンポで確実にカウントができる方法はありませんでしょうか。
以下は、現在の私の実装方法です。
まず、テンポ値を命令の引数として受け取り、
tempo_wait=60000/tempo//tempo:受け取った数値
これで待ち時間を検出し、別の命令でこの待ち時間をそのままawaitに使っています。
また、カウントする命令の引数として1(1拍)以外を指定した場合は、その数値が乗算されて待ち時間となります。
なにか良い方法がございましたら、ご教授ください。



この記事に返信する


hexa.hemi

リンク

2012/4/4(Wed) 14:28:39|NO.45787

await命令を精度の良いものに置き換えるという方法があります。

#module // 時間を正確に測るためのAPI #uselib "winmm.dll" #cfunc timeGetTime "timeGetTime" #func timeBeginPeriod "timeBeginPeriod" int #func timeEndPeriod "timeEndPeriod" int #deffunc __init_await timeBeginPeriod 1// 1ms単位ではかれるようにする t = timeGetTime() return #undef await// 既存のawait命令を消す(いままでのawait命令を使用する場合はawait@hspで呼び出せます) #deffunc await int wc repeat wait 0 if timeGetTime() - t >= wc : break loop t = timeGetTime() return #deffunc __end_await onexit timeEndPeriod 1 return #global __init_await
上のスクリプトを音ゲーのスクリプトの先頭に貼り付けてください。
おそらく精度がよくなると思います。



にゃんちゃん

リンク

2012/4/4(Wed) 20:08:34|NO.45799

アドバイスありがとうございます。
GetTickCountは試してたのですが、これは試していませんでした。
結果がでたら、また報告します。
他にもアドバイスがありましたらお願いいたします。



にゃんちゃん

リンク

2012/4/4(Wed) 20:14:00|NO.45801

連投すみません。
試してみたところ、確かにawait命令の制度はあがっていました。
しかし、やはりテンポはミリ秒では表現しきれないようです。
midiとかのように完璧にタイミングをとる方法ってHSPでは出来ないのかなぁ…
パソコンの時間の扱いがミリ秒だから、これ以上は無理かもしれませんね。



hexa.hemi

リンク

2012/4/4(Wed) 21:15:21|NO.45809

改良版

#module // 時間を正確に測るためのAPI #uselib "kernel32.dll" #func QueryPerformanceFrequency "QueryPerformanceFrequency" var #func QueryPerformanceCounter "QueryPerformanceCounter" var #deffunc __init_await dim fr, 2 dim tm, 2 QueryPerformanceFrequency fr if stat = 0 : return 1 QueryPerformanceCounter tm return 0 #undef await// 既存のawait命令を消す(いままでのawait命令を使用する場合はawait@hspで呼び出せます) #deffunc await int wc wt = wc * fr / 1000 repeat wait 0 QueryPerformanceCounter tm2 if tm2 - tm >= wt : QueryPerformanceCounter tm : break loop return #global __init_await if stat : dialog "エラー", 1 : end
ただし、環境によってはできないことがあります。



hexa.hemi

リンク

2012/4/4(Wed) 21:33:48|NO.45810

ちょっと間違ってました。

#module // 時間を正確に測るためのAPI #uselib "kernel32.dll" #func QueryPerformanceFrequency "QueryPerformanceFrequency" var #func QueryPerformanceCounter "QueryPerformanceCounter" var #deffunc __init_await ddim fr, 1 ddim tm, 1 ddim tm2, 1 ddim wt, 1 QueryPerformanceFrequency fr if stat = 0 : return 1 QueryPerformanceCounter tm return 0 #undef await// 既存のawait命令を消す(いままでのawait命令を使用する場合はawait@hspで呼び出せます) #deffunc await double wc wt = double(strf("%I64u", fr)) * wc / 1000 repeat wait 0 QueryPerformanceCounter tm2 if double(strf("%I64u", tm2)) - double(strf("%I64u", tm)) >= wt : QueryPerformanceCounter tm : break loop return #global __init_await if stat : dialog "エラー", 1 : end
これ以上は私の力では無理です。



check

リンク

2012/4/5(Thu) 01:57:39|NO.45820

どんな環境であれ(例えば、Wiiなどのコンシューマー機であれ)
超高解像度のタイマーを内部で持つなんてことはありえない。
(もしかしたら音ゲーム向けのゲームセンターにおいてあるようなヤツには搭載されているかもしれないが)

1ループごとに、指定されたテンポとの誤差をカウントしておいて、
ある程度たまったら(ゲームとして画面に表示できるだけの誤差がたまったら)
意図的にずらすというのが一般的な方法じゃないだろうか。

上記のやり方だったら、処理の遅いHSPでも負荷のかかることをさせなければ十分
ゲームとして機能するのではないかと。
超高速な曲でもBPMが240を超えることは滅多にないだろうから、
240/240で1小節あたり1秒で処理できれば良いことになる。



hexa.hemi

リンク

2012/4/5(Thu) 07:09:02|NO.45830

check氏> なるほど、ずれた際に同じ分逆方向へずらすのですか。

await命令のほうで実装したのでcheck氏とやり方がずれますが、
一応ずれた分戻す機能の付いたawait命令のスクリプトを張っておきます。

なんちゃん氏> await 0 で基準を設定します。音ゲーのループの前に設置しておいてください。

#module // 時間を正確に測るためのAPI #uselib "kernel32.dll" #func QueryPerformanceFrequency "QueryPerformanceFrequency" var #func QueryPerformanceCounter "QueryPerformanceCounter" var #deffunc __init_await ddim fr, 1 ddim tm, 1 ddim tm2, 1 ddim wt, 1 ddim xtm, 1 ddim xfr, 1 QueryPerformanceFrequency fr if stat = 0 : return 1 xfr = double(strf("%I64u", fr)) QueryPerformanceCounter tm xtm = double(strf("%I64u", tm)) return 0 #undef await// 既存のawait命令を消す(いままでのawait命令を使用する場合はawait@hspで呼び出せます) #deffunc await double wc wait 0 if wc <= 0.0 {// await 0やawait -1で現在の時刻(?)を基準に設定 QueryPerformanceCounter tm xtm = double(strf("%I64u", tm)) return } wt = xfr * wc / 1000 xtm += wt repeat QueryPerformanceCounter tm2 if double(strf("%I64u", tm2)) - xtm >= wt : break loop return #global __init_await if stat : dialog "エラー", 1 : end await 0// 基準設定。これを音ゲーのループの前に置く。



てれてれ

リンク

2012/4/5(Thu) 08:16:30|NO.45834

mciを使って曲の再生を行えば、再生されてから何ms経過したかが取得できますので、
それを基に座標を割り出すことで、例えフリーズしたとしてもズレないような仕様に出来ます。



にゃんちゃん

リンク

2012/4/5(Thu) 08:23:32|NO.45835

返信を書いているあいだにてれてれさんの書き込みがあったので、まだ試していません。
再生後の時間を取得するMCIコマンド、調べておきます。
だんだんと誤差が少なくなってきました。
あとはずれるタイミングを見て主導で修正しなければならないと思います。
とりあえずHSPの限界に来ちゃったみたいなので、これで解決とさせていただきます。
にしても、太鼓の達人とかリズム天国とか、どういう仕掛けになってるんだろう…
ありがとうございました。



spider

リンク

2012/4/5(Thu) 08:42:41|NO.45837

もう終わっているようですが、
一応書きます。
音ゲーで使うMCIのコマンド一覧

mci "open ファイル名 alias music" ;ファイルオープン"alias music"でファイル名を"music"に置き換え mci "status music length" ;全体の長さをms単位で取得(statに代入) mci "play music" ;音楽再生 mci "stop music" ;一時停止 mci "status music position" ;再生位置をms単位で取得 mci "play music from 再生位置" ;指定した再生位置から再生(ms単位)



にゃんちゃん

リンク

2012/4/5(Thu) 09:03:55|NO.45838

おお、ありがとうございます!助かります。



ONION software Copyright 1997-2023(c) All rights reserved.