カクカクしないで処理を一定にするには

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
けん

カクカクしないで処理を一定にするには

#1

投稿記事 by けん » 16年前

どのような環境でも移動スピードを一定にしたいのですが
こちらのゲームプログラミングの宝館のサンプルで記載されている処理で

void wait_fanc(){
int term;
static int t=0;
term = GetNowCount()-t;
if(16-term>0)
Sleep(16-term);
t=GetNowCount();
return;
}

を追加すると、リフレッシュレートが高いほどカクカクしてしまいます。

四聖龍神録をプレイするとかなり滑らかに動いていますが

処理的にはどのようにしているのでしょうか?

初心者ですみません。

どうぞご教授ください。

御津凪

Re:カクカクしないで処理を一定にするには

#2

投稿記事 by 御津凪 » 16年前

> こちらのゲームプログラミングの宝館

http://dixq.net/g/のことですか?

Sleep 関数は 100% 指定した通りの待ちをしません。
(PCにもよりますがだいたい 20ms ほどの誤差が出ます)
そのため、この方法ではカクカクすることがあります。

ここのサイトの龍神録プログラミングの館のソースを見てみたほうがいいかと思います。

けん

Re:カクカクしないで処理を一定にするには

#3

投稿記事 by けん » 16年前

返信ありがとうございます。

龍神録プログラミングの館のソースでも試してみたところ
※wait_fps()?

やはり微妙にカクカクしました。

リフレッシュレート60では非常に滑らかですが
75に変更して試すと少しぶれがあります。

ウエイトをかけてFPSを保つ方法では限界があるのでしょうか?


> > こちらのゲームプログラミングの宝館
>
> http://dixq.net/g/のことですか?
>
> Sleep 関数は 100% 指定した通りの待ちをしません。
> (PCにもよりますがだいたい 20ms ほどの誤差が出ます)
> そのため、この方法ではカクカクすることがあります。
>
> ここのサイトの龍神録プログラミングの館のソースを見てみたほうがいいかと思います。

御津凪

Re:カクカクしないで処理を一定にするには

#4

投稿記事 by 御津凪 » 16年前

実は龍神録プログラミングの館のソースを見ていませんでしたが、
同じ処理内容でしたでしょうか?

wait_fanc 関数内に書かれている 16 とは、60Hz での1フレームの経過時間です。
正確には端数が出ます(1000.0 / 60.0 = 16.666666666666)がここでは省かれています。
75Hz で正しく処理するには、
(1000.0 / 75.0 = 13.333333333333)で、 16 を 13 に変更すれば、
リフレッシュレートが 75Hz の時に滑らかになると思います。

けん

Re:カクカクしないで処理を一定にするには

#5

投稿記事 by けん » 16年前

処理は微妙に違いましたが、基本的に16ms未満だった場合処理を待つような設計でした。

下記関数になります。

void fps_wait(){
int term,i,gnt;
static int t=0;
if(fps_count==0){//60フレームの1回目なら
if(t==0)//完全に最初ならまたない
term=0;
else//前回記録した時間を元に計算
term=count0t+1000-GetNowCount();
}
else //待つべき時間=現在あるべき時刻-現在の時刻
term = (int)(count0t+fps_count*(1000.0/FLAME))-GetNowCount();
if(term>0)//待つべき時間だけ待つ
Sleep(term);
gnt=GetNowCount();
if(fps_count==0)//60フレームに1度基準を作る
count0t=gnt;
f[fps_count]=gnt-t;//1周した時間を記録
t=gnt;
//平均計算
if(fps_count==FLAME-1){
ave=0;
for(i=0;i<FLAME;i++)
ave+=f;
ave/=FLAME;
}
fps_count = (++fps_count)%FLAME ;
}

75フレームのときおっしゃるとうりソースを書き換えれば滑らかに動きますが
事前にリフレッシュレートがわかっていないければ出来ないかと思います。

各環境で自動的にあわせて行きたいのですが現在のリフレッシュレートを算出する関数はdxlibに実装されていますでしょうか?

よろしくお願いします。


> 実は龍神録プログラミングの館のソースを見ていませんでしたが、
> 同じ処理内容でしたでしょうか?
>
> wait_fanc 関数内に書かれている 16 とは、60Hz での1フレームの経過時間です。
> 正確には端数が出ます(1000.0 / 60.0 = 16.666666666666)がここでは省かれています。
> 75Hz で正しく処理するには、
> (1000.0 / 75.0 = 13.333333333333)で、 16 を 13 に変更すれば、
> リフレッシュレートが 75Hz の時に滑らかになると思います。

けん

Re:カクカクしないで処理を一定にするには

#6

投稿記事 by けん » 16年前

上で書いたことで間違えました。

リフレッシュレートを現在の環境にあわせていくだけでは実際の速度が変わってきてしまうので
意味のないことでした。

やはり60フレーム固定の状態で75フレームの状態でプレイするとぶれますね・・・。

少し頭がこんがらがってきました。

toyo

Re:カクカクしないで処理を一定にするには

#7

投稿記事 by toyo » 16年前

>現在のリフレッシュレートを算出する関数はdxlibに実装されていますでしょうか?
GetVSyncTime( )という関数で1フレームのミリ秒が得られます
60Hzの場合は16か17が返ります。

御津凪

Re:カクカクしないで処理を一定にするには

#8

投稿記事 by 御津凪 » 16年前

現在の状態だと、

描画間隔(60)=動作スピード(60)

なので、リフレッシュレートなどにより描画間隔が変われば動作スピードも変わります。

リフレッシュレートが 60 以外で、

描画間隔(75)≠動作スピード(60)

とするには、描画間隔で待たずに
移動処理の方に対して 60 フレーム間隔で処理すると良いでしょう。

ソースとしては、下記のような感じです。
#define FPS_FRAME 16 // 1フレームあたりの待ち時間

void mainloop( void ){
    int t   = GetNowCount();
    int tmp = 0;
    while(1){
        tmp += GetNowCount() - t;
        while(tmp >= FPS_FRAME){
            move(); // 移動処理
            tmp -= FPS_FRAME;
        }
        draw(); // 描画処理
    }
}
ソースを見れば分かるようにそのまま使うと終了できなくなるので注意。
ちなみに VSync まで待たないようになると、ものすごい描画処理のループをするので注意。

けん

Re:カクカクしないで処理を一定にするには

#9

投稿記事 by けん » 16年前

御津凪様、
返信ありがとうございます。

この処理ですが
VSyncをまたずに移動処理だけ60FPSで処理するということでしょうか?

そして描画処理についてはマシンパワーが許す限り実行すると。

龍神録さんのソースではそのような処置がしてないのですが

たとえばウインドウモードで75FPSで実行すると
少しぶれてますよね?

私の環境だけでしょうか・・・。

御津凪

Re:カクカクしないで処理を一定にするには

#10

投稿記事 by 御津凪 » 16年前

上のコードは VSync(垂直同期) を待っても待たなくても移動処理は 60FPS 間隔で動作します。
描画処理の方は VSync を待つならリフレッシュレートに応じた間隔で、
そうでなければマシンパワーの許す限り呼び出されます。

(ちなみに VSync を待つかどうかの処理は上のコードにはありませんよ。)

もし処理に時間がかかり、移動処理に遅れが出ると、遅れた分を取り戻すために
移動処理関数を複数回呼び出す仕組みになっています。

これは、フレームスキップという方法で、龍神録の方では使われていません。

理由は、フレームスキップによってスキップされた時の状態が描画されないため、
描画されていない(フレーム時)間がどのような状態になっているかを視認できないので、
シューティング(特に精密操作系ゲーム)には余り向かないためです。
(3フレーム分スキップしたら、その3フレームの状態が描画されないということ)

フレームスキップ法は、リフレッシュレートが違う場合でも必ずゲーム時間は一致しますが、
表示が(周期的に)ぶれたりカクつくことがあります。

こちらの方法も一長一短というわけです。

("フレームスキップ法"で検索してみると FPS 周りについて詳しく分かるかと思います)

けん

Re:カクカクしないで処理を一定にするには

#11

投稿記事 by けん » 16年前

いろいろとご教授ありがとうございます。

ソースを参考にしたいと思います。

最後にひとつお聞きしたいのですが

DXLIBではフルスクリーンモードでは基本的に60FPSに固定されているようなのですが

ウインドウモードを切り捨てれば60FPS固定で開発しても支障はないということでしょうか?

よろしくお願いします。

御津凪

Re:カクカクしないで処理を一定にするには

#12

投稿記事 by 御津凪 » 16年前

> ウインドウモードを切り捨てれば60FPS固定で開発しても支障はないということでしょうか?

それは製作するゲームの仕様設定によります。

製作するゲームでフルスクリーン推薦とするのであればそれでかまわないかと思いますが、
ウインドウモードもきちんと対応しなければならないのであれば、対応するべきです。

閉鎖

“C言語何でも質問掲示板” へ戻る