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


HSPTV!掲示板


未解決 解決 停止 削除要請

2016
0115
SqOcHSPで一番正確なタイマー25未解決


SqOc

リンク

2016/1/15(Fri) 22:26:23|NO.74128

音ゲー(リズムゲーム)を作っています。
そこで、仕組みなどはほとんどできたのですが、どうしてもノーツが落ちてくるのに誤差が出てしまいます。
現在はtimeGetTimeを使っています。
毎回誤差なども算出しているのですが、どうもうまくいきません。
どなたかアドバイスをください!!
お願いします!



この記事に返信する


リンク

2016/1/15(Fri) 23:06:37|NO.74129

一般的な音ゲーの範囲で利用する際に、PCの処理落ちなどの要因が無ければ
HSP標準のタイマーで許容できない誤差が出る事態にはならんと思います。
タイマー以外の組み方に問題があるのではないでしょうか?

これだけの情報では、申し訳ないですが自分はこのぐらいしか答えられません。



pumpkin

リンク

2016/1/15(Fri) 23:14:51|NO.74130

既に知っていたら申し訳ないんですが、waitよりawaitの方が精度は高いんだとか。
精度というか、ちょっとした仕様の違いというか。

http://hsp.tv/play/pforum.php?mode=all&num=71725
以下このURLのmotchyさんの文を引用させていただきます
repeat
/* 何らかの処理 : 所要時間 5ms */ await 20 loop
このループは 20ms 間隔で回ります。(理想的に)

一方、
repeat
/* 何らかの処理 : 所要時間 5ms */ wait 2 loop
このループは 25ms の周期で回ります。(理想的に)



暇人

リンク

2016/1/16(Sat) 00:05:21|NO.74131

タイマー精度じゃ無く処理の問題なんじゃないの?


処理に関係なく精密な時間を
http://hsp.tv/play/pforum.php?mode=all&num=71280

読んでる?



zero

リンク

2016/1/16(Sat) 00:20:08|NO.74132

wait p1は内部で実質的にawait p1*10に変換されるので、
実時間に対する誤差という意味ではwaitとawaitは
そんなに変わらないという認識でいましたが違いましたかね。



Mituki

リンク

2016/1/16(Sat) 01:34:42|NO.74134

pumpkinさんの
>>waitよりawaitの方が精度は高いんだとか。
>>精度というか、ちょっとした仕様の違いというか。

waitはCPU(?)をあまり使わずに動きます。
そのかわり、誤差が出ます。つまり、精度が低いということです。
awaitはCPU(?)をwaitより多く使って、動かしています。
なので、精度が高いということです。

pumpkinさんとおなじように間違ってたらスミマセン・・・



Mituki

リンク

2016/1/16(Sat) 01:38:58|NO.74135

補足 (No.74134)
wait(ウエイト)で値を入れると・・・
1=0.01秒
10=0.1秒
100=1秒
(【*1】>正確とは限りません。)
という感じになります。
そして、await(アクティブウエイト)では
1=0.001秒
10=0.01秒
100=0.1秒
1000=1秒
(*1)
というようになります。あまり役に立てなくてごめんなさい(><)



暇人

リンク

2016/1/16(Sat) 01:51:15|NO.74136

後実数で計算する必要がある所を整数にしてしまってる可能性もある



スペース

リンク

2016/1/16(Sat) 03:06:57|NO.74137

Mitukiさんの解説は誤解を招きかねない気が。
awaitとwaitの違いは単位もありますが、単位が違う=精度の違いではありませんよね?
根本的に違うのは処理の仕方で、
awaitは処理にかかった時間も含めて指定した時間分待機します。

例えば処理に10msかかって、await 20、wait 2にしたとしましょう。
awaitの場合は(20-10)msぶん待機するのに対して、waitは(10+20)msぶん待機します。
(内部の時間の計測方法に関しては一切知りません)

で、timegettimeで誤差がでるなら最早それは他の部分に問題がある可能性が。
試しに最高FPSがどれくらいかを計測してみてはどうでしょうか?



暇人

リンク

2016/1/16(Sat) 03:55:12|NO.74138

bpmが正しいかは分からないけど・・・

#uselib "winmm.dll" #cfunc timeGetTime "timeGetTime" #include "hspogg.as" dmmini dmmload dir_exe+"\\sample\\demo\\oot06.ogg",0,0 time_total=0.0 bpm=138.0 //一分間の四分音符の数 Beat =60000.0/bpm //四分音符の時間 Beat16=Beat/4 timspd=400.0/(Beat*4) //一小節分の時間で400ドット進む速度 dat=1,0,1,0,0,1,1,0,0,1,1 Beatcnt_bak=-1 nt_list="" font "MS ゴシック",32,1+16 hitmes="" wait 50 dmmplay 0 timeA=double(timeGetTime())+10 //開始時の微調整 repeat redraw 0 color boxf if (hitmes ! "") { color 255,255 pos 200,300 if gcbt<5 {mes hitmes}else{mes hitmes+" "+gcbt} mes dif hitcnt++ if hitcnt>20 {hitmes = ""} } time_total=double(timeGetTime())-timeA Beatcnt=int(time_total/Beat) //開始からの四分音符数 if Beatcnt_bak ! Beatcnt {//前回と違う Beatcnt_bak=Beatcnt nt_list+str(Beat*Beatcnt)+"\n" } color 0,100,0 gradf 0,400,640,2 notesel nt_list ne_index=0 getkey sp,32//スペース if sp_bak ! sp {sp_on=sp}else{sp_on=0} sp_bak=sp time_total=double(timeGetTime())-timeA repeat notemax noteget nt_str,ne_index ntposy=timspd*(time_total-nt_str) gradf 100,ntposy,64,4,1,$55555555 | $aaaaaaaa*((time_total-Beat*Beatcnt)<100),$55555555 if sp_on { if abs(ntposy-400)<64 { if abs(ntposy-400)<10 { dif=ntposy-400 hitmes= "GREAT!" gcbt++ ntposy=500 //消す }else{ dif=ntposy-400 gcbt=0 hitmes= "GOOD" ntposy=500 //消す } }else{gcbt=0} hitcnt=0 sp_on=0 } if ntposy>450 {notedel ne_index :continue} ne_index++ loop redraw 1 await 10 loop



Velgail

リンク

2016/1/16(Sat) 05:17:47|NO.74139

というか、wait系で同期を取ってはいけない。

こういう時は、「gettimeでPCの時刻を取って参照する」方が正確。
awaitはリフレッシュレートの為に使って、gettimeを重ねた値(サンプル下記)を使って実現しよう。


#define sysclock (gettime(4)*3600000+gettime(5)*60000+gettime(6)*1000+gettime(7))
サンプルのsysclockの値の差を取って積算する場合、「誤差は発生しないはず」。
ちなみに、このサンプルは手抜きで「日をまたぐと事故」しますので、くれぐれも注意を。
やってることは、時間軸をms単位で1次元に落とすということ。



Velgail

リンク

2016/1/16(Sat) 06:33:41|NO.74140

……TimeGetTime使って誤差が発生してるのであれば、処理系がおかしいとしか。
軽く描画系のループを擬似コードで書いてみると
begin Loop
 同期()//ノートの位置と現在時刻を合わせる
 入力()//入力を取得し、音ゲー処理をする
 描画()//画面描画をし、表示する。
 待機()//リフレッシュレートに合わせて待つ
end Loop
といった形になるはず。ここで、
入力と描画にかかる時間をtimegettimeを使って差分取得してlogmesで表示してみよう。
60fpsを目指すなら、16以下、可能であれば10以下である必要があるが果たしてどうだろうか?

仮に時間がかかりすぎるなら以下の点に注意してみると良いかも。
この中で、待機関数以外のブロックでは「wait/awaitを一切使わない」で書いてあるか?
全てのブロックで「非定数回ループ」を使っていないか?(周回数が確定していないループがないか)
さらには、無駄なエフェクト・処理に凝っていないか?(それは最後に追加するべき)

以上です。参考になるソースコードが欲しければ、aekh69@ahk.jpまで送ってくださいな。(パブリック公開すると色々とマズいので



smh1024

リンク

2016/1/16(Sat) 16:17:31|NO.74148

プチコンであれば,垂直同期ができる VSYNC命令があります。これを使うと1/60秒単位のフレームを
保てます。しかし,HSPのwait,awaitって不安定ではないでしょうか?
wait 1で,毎回,PCにかかる負担によってスピードが違うために,例えば四角形の物体を
移動させるのにすごく速かったり,遅かったりします。



スペース

リンク

2016/1/16(Sat) 16:43:52|NO.74149

スレ主は現在TimeGetimeを使ってると言っているし、wait、awaitは関係ないんじゃないかなと思う。
(人の事言えないけど。)

>Velgailさん
>参考になるソースコードが欲しければ、aekh69@ahk.jpまで送ってくださいな。(パブリック公開すると色々とマズいので

ここで公開してもパブリックドメインにはなりませんよ。
著作権は投稿した本人にあります。
それが原因で投稿されたプログラムを安易に自分のソフトに組み込めなかったり・・・



スペース

リンク

2016/1/16(Sat) 19:31:00|NO.74150

あれ、今思ったけどパブリック公開ってのは「一般公開」って意味かな?
だとしたらパブリックドメインの所は読み飛ばしてください。



Velgail

リンク

2016/1/16(Sat) 20:22:52|NO.74151

そう、一般公開不可なんですよ。(AndroidのCytusから譜面データぶっこ抜いた奴が混ざってるので)

ソース自体はCC0でいいんですけど、動かすための奴が…… というわけで。



窓月らら

リンク

2016/1/17(Sun) 09:00:37|NO.74160

音ゲーの場合、まずBGMが正確に再生されてるかを検証するのが先ですね。
mciはおすすめしません。



SqOc

リンク

2016/1/18(Mon) 23:38:20|NO.74184

みなさんありがとうございます。

アドバイスを見させていただいたところ、おそらく、NO.74136の暇人さんの実数を整数に
してしまっている可能性が高いのですが、その場合は扱っている変数に

timekekka*1.0

のように1.0をかければいいのでしょうか?

初歩的なことをすいません



Moz

リンク

2016/1/18(Mon) 23:44:18|NO.74185

左側の型にそろえられてしまうので、
1.0*timekekka か 0.0+timekekka とするか double(timekekka) で実数型にできます。



SqOc

リンク

2016/1/18(Mon) 23:51:49|NO.74186

仕組みまでありがとうございます!

その3つの中で、どれがいいとかはないのでしょうか?



Velgail

リンク

2016/1/19(Tue) 02:38:23|NO.74188

噂によると、0.0+が最速とか。
が、意図が不明瞭になりがちなので、明確にdouble()と型変換関数を使うべきとは言っておくよ。



スペース

リンク

2016/1/19(Tue) 10:09:45|NO.74189

そもそも一番最初に値を代入する段階から、実数型で代入した方がいい。
double()で囲むだけでいいから一番簡単。



AssDick

リンク

2016/1/19(Tue) 20:30:05|NO.74194

Mituki さんは何が言いたいんですか?



Velgail

リンク

2016/1/20(Wed) 06:24:51|NO.74203

>そもそも一番最初に値を代入する段階から、実数型で代入した方がいい。
これには同意しません。
若干でも誤差の出る可能性を下げるのであれば、ミリ秒単位の整数値で時間を管理した方が、
最終的に実数値計算に回す時の誤差が下がるからです。

実数値が必要な時の処理は、double変換をしてしっかりと出力すると良いでしょう。
あ〜っと、間違っても「ノートとノートの間の時間を計算」してノートを描画したりしないように。
必ず「曲の先頭とノートの間の時間を計算」するように。誤差が積み重なるので。

誤差が発生する具体例

i=0.0 repeat mes cnt mes i i+=0.1 if(i>=1.0):break loop
期待される最後の2行は"9\n0.9"だが、実際には"10\n1.0"が出力されてしまう。



スペース

リンク

2016/1/20(Wed) 16:52:41|NO.74207

>>Velgailさん
もしかしたら想定している計算、処理方法が違うのかもしれない。
自分はこんな感じの処理方法を想定して「最初から実数型で代入した方がいい」と言ったのですが、どうでしょう?

#include "winmm.as" #include "d3m.hsp" Screen 0,500,500 //カーソルを下に移動させるとFPSを下げる 移動速度=250.5//1秒あたりの移動px timegettime:開始時間=stat repeat timegettime:最新時間=stat if X座標>=500:開始時間=stat//500pxに到達したら0pxから始まるように。 X座標=double(最新時間-開始時間)*(移動速度/1000.0) Color 255,255,255:boxf:Color 0,0,0:pos X座標,50:mes "●"//背景初期化後、●を描画。 title "X座標"+X座標+","+d3getfps()+"FPS" await double(mousey)/2.0// loop



MillkeyStars

リンク

2016/2/5(Fri) 03:13:33|NO.74453

無理に考えようとしないで、単純にね。
音楽の位置情報(再生時間)とノーツの位置情報は、確定してるんだよね。
1.その場合に音楽の現在位置が 1000だとする。
2.音楽の再生位置が 2000の時に、ノーツが判定ラインに来るようにするにはどうする?

答え、判定ライン位置 - 1000 にすれば、現在のノーツの位置は確定するよね。

このページを一番上に戻してから、→のスクロールバーを見ながら一定間隔で↓にスクロールしてみよう。
必ず同じ回数・時間で一番下まで来ると思うから。それを逆にたどれば現在の位置がわかるということですよ。



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