描画された画像が移動中たまに(動画を見ながら実行すると多く)カクカクするのですが、どうしたらこのカクカクをなくすことができるでしょうか?
多分ここだろうなと言うところを載せます。
//グローバル変数
static HDC g_hdcOff,g_hdcImg[MAX_IMAGE];
static HBRUSHg_hbrBg = NULL;// 背景用ブラシ
static HBITMAPg_hbmImg[IMG_MAX]= {NULL};// 画像のビットマップ
//================================================================================
// オフスクリーンへ画像表示
// idx : 画像データの添え字
// x,y : 表示位置x,y
// sx,sy : 画像切り出し位置x,y
// w,h : 画像切り出し幅、高さ
// src : 転送モード指定。通常はSRCCOPY,SRCPAINT,SRCANDなど
//================================================================================
void DrawImg(int idx,int x,int y,int sx,int sy,int w,int h,DWORD src)
{
BitBlt(g_hdcOff,x,y,w,h,g_hdcImg[idx],sx,sy,src);
}
//================================================================================
// オフスクリーンへ画像表示。マスク表示→画像表示
// idx : 画像データの添え字
// x,y : 表示位置x,y
// sx,sy : 画像切り出し位置x,y
// w,h : 画像切り出し幅、高さ
// mx,my : マスク切り出し位置x,y
//================================================================================
void DrawImgMask(int idx,int x,int y,int sx,int sy,int w,int h,int mx,int my)
{
BitBlt(g_hdcOff,x,y,w,h,g_hdcImg[idx],mx,my,SRCPAINT);
BitBlt(g_hdcOff,x,y,w,h,g_hdcImg[idx],sx,sy,SRCAND);
}
void Draw()
{
// 画面消去
HBRUSH oldbr = (HBRUSH)SelectObject(g_hdcOff, g_hbrBg);
Rectangle(g_hdcOff, -1, -1, CLIENT_WIDTH+1, CLIENT_HEIGHT+1);
SelectObject(g_hdcOff, oldbr);
//----------------------------------------------------------
// ↓ここから描画処理
// キー状態の更新
KeyUpdate();
// プレイヤー移動
if (KeyIsHold(KC_LEFT))
{
g_Player.x -= PL_VELX;
if (g_Player.x < PL_LIMITL) g_Player.x = PL_LIMITL;
}
if (KeyIsHold(KC_RIGHT))
{
g_Player.x += PL_VELX;
if (g_Player.x > PL_LIMITR-g_ImgData[g_Player.type].w)
g_Player.x = PL_LIMITR-g_ImgData[g_Player.type].w;
}
// プレイヤーの表示
DrawChr(g_Player.type, g_Player.x, g_Player.y);
// ↑ここまで描画処理
//----------------------------------------------------------
// 再描画
InvalidateRect(g_hWnd,0,FALSE);
UpdateWindow(g_hWnd);
}
// キャラクタ描画関数
// type : キャラタイプ(eChrType)
// x : 表示位置X
// y : 表示位置Y
void DrawChr(int type,int x,int y)
{
DrawImgMask(g_ImgData[type].idx, x,y,
g_ImgData[type].sx, g_ImgData[type].sy,
g_ImgData[type].w, g_ImgData[type].h,
g_ImgData[type].mx, g_ImgData[type].my);
}
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow )
{
・・・
・・・
・・・
// メッセージループ
while(true)
{
if (PeekMessage(&msg, NULL, 0,0,PM_REMOVE))
{
if (msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
static DWORD before_time;
DWORD now_time;
DWORD ideal_time=0;
static int frame=0;
TCHAR buff[100];
DWORD team=0;
static long surplus_time=0;
now_time=timeGetTime();
if(!before_time)
before_time=timeGetTime();
surplus_time=(long)(now_time-before_time);
ideal_time=(DWORD)(frame*1000)/60;
wsprintf(buff,TEXT("%d %d %d\n"),ideal_time,surplus_time,(long)ideal_time-surplus_time);
OutputDebugString(buff);
if((long)ideal_time-surplus_time>0)
Sleep((long)ideal_time-surplus_time);
team=timeGetTime();
team-=before_time;
if(team>=1000)
{
before_time=timeGetTime();
frame=0;
}
frame++;
}
Sleep(1);
}
・・・
・・・
・・・
return (int)msg.wParam;
}
環境はVC++2005、C言語とWINAPIっだけです。
説明が足りないのなら補足します。
No.4ベストアンサー
- 回答日時:
そういえば、透過とかできないからマスクしてなんてこともしてたなぁとか
すこしずつ思い出しつつ
んで、昔作ったソース探したのですが見つからないものですね(笑
今じゃもう、ビルド環境すらないのでどうにもならない今日この頃なのですけど
やっていることはあっている感じですねぇ
でも全画面転送にWM_PAINTは経由していなかった気がする
なんとなく、GetDC()で取ってきて直接書き込んでいたと思います。
ためしに UpdateWindow() を呼び出さない形にしてみてはいかがでしょう?
UpdateWindow() はWindow作成時の一度しか明示的な呼び出しは不要だったはずです
あとWM_SIZEとかリサイズ周りの時?
Zバッファというは、スプライトの描画を後ろから書いていくことで
重なったときに全面のスプライトを表示するという意味です。
WIN32APIでも、マスク画像を準備してあげることで透過スプライトを出力できるのでてっきりやっているものだと。。
返信ありがとうございます。
なんとか出きるようになりました。
TransparentBlt()関数使っていたりしてたらいつの間にか出来てました。
お騒がせしました!点数は配分するので!
No.3
- 回答日時:
ダブルバッファリングの基本は、書き直しと一括転送です。
気になったのは
>オフスクリーンはorで切り取って、
>次にandで切り取ったのを背景に貼り付けるような作りになっています。
>そしてPAINTで表画面に貼り付ける感じになっております。
の部分ですね。
プライマリの画面から一瞬でもスプライトが消えていたりしませんか?
消えちゃうとカクカクとした感じになったりします。
あとは、単純に描画回数が多すぎて処理落ちしているケースもありますけど。。
コーディングしていたのはずっと昔なので関数とか用語は忘れちゃいましたけど、
ダブルバッファリングの流れを簡単にかくとこんな感じです。
1. 初期化用の背景バッファ作成
2. バックバッファ(オフスクリーン)とプライマリバッファ(普通のDC)作成
3. オフスクリーンを背景バッファで塗りつぶし
4. オフスクリーンにすべてのスプライト書き直し
5. プライマリバッファに全画面転送
6. 「3.」へもどる
昔はVGAが遅かったのとスプライトが少なかったため、
オフスクリーンの部分的に消し描きなんてのもしていましたが
今のご時世ならスプライトも多いでしょうから一度クリアして書き直した方が早いです。
(Zバッファが効くので都合もよい)
この回答への補足
返信ありがとうございます。
>1. 初期化用の背景バッファ作成は、
// 背景表示ブラシ作成(背景色の設定)
g_hbrBg = CreateSolidBrush(RGB(255,255,255));
>2. バックバッファ(オフスクリーン)とプライマリバッファ(普通のDC)作成は、
// オフスクリーンの作成
hdc = GetDC(hWnd);
g_hdcOff = CreateCompatibleDC(hdc);
hbmp = CreateCompatibleBitmap(hdc,CLIENT_WIDTH,CLIENT_HEIGHT);
ReleaseDC(hWnd, hdc);
SelectObject(g_hdcOff,hbmp);
DeleteObject(hbmp);
>3. オフスクリーンを背景バッファで塗りつぶしは、
// 画面消去
HBRUSH oldbr = (HBRUSH)SelectObject(g_hdcOff, g_hbrBg);
Rectangle(g_hdcOff, -1, -1, CLIENT_WIDTH+1, CLIENT_HEIGHT+1);
SelectObject(g_hdcOff, oldbr);
で
>4. オフスクリーンにすべてのスプライト書き直し
void DrawImgMask(int idx,int x,int y,int sx,int sy,int w,int h,int mx,int my)
{
BitBlt(g_hdcOff,x,y,w,h,g_hdcImg[idx],mx,my,SRCPAINT);
BitBlt(g_hdcOff,x,y,w,h,g_hdcImg[idx],sx,sy,SRCAND);
}
、>5. プライマリバッファに全画面転送は、
case WM_PAINT:
hdc = BeginPaint(hWnd,&ps);
// オフスクリーンからウィンドウに転送
BitBlt(hdc,0,0,CLIENT_WIDTH,CLIENT_HEIGHT,g_hdcOff,0,0,SRCCOPY);
EndPaint(hWnd,&ps);
return 0;
ですよね?これでもカクカクが取れません。なにか間違っているのでしょうか?
>今のご時世ならスプライトも多いでしょうから一度クリアして書き直した方が早いです。
(Zバッファが効くので都合もよい)
は多分DirectXですよね。WIN32APIにもあるのでしょうか?
回答お待ちして居ります。
>プライマリの画面から一瞬でもスプライトが消えていたりしませんか?
>消えちゃうとカクカクとした感じになったりします。
>あとは、単純に描画回数が多すぎて処理落ちしているケースもありますけど。。
画面からは消えていません。カクカクしたままです。
No.2
- 回答日時:
g_hdcOffはどのように得ていますか?
g_hdcOff=CreateCompatibleDC(NULL);
のように、バックバッファ用にデバイスコンテキストを作成しているのであれば、良いと思うのですが、コールバック関数の引数のウインドウハンドルから得ていると、直接windowに表示してしまっていることになります。その場合、画面がちらつきます。
この回答への補足
g_hdcOff = CreateCompatibleDC(hdc);
の所をhdcをNULLに変えてやりましたが、カクカクしたままです。
コールバック関数のWM_CREATEは次のようになっております。
case WM_CREATE:
// オフスクリーンの作成
hdc = GetDC(hWnd);
g_hdcOff = CreateCompatibleDC(hdc);
hbmp = CreateCompatibleBitmap(hdc,CLIENT_WIDTH,CLIENT_HEIGHT);
ReleaseDC(hWnd, hdc);
SelectObject(g_hdcOff,hbmp);
DeleteObject(hbmp);
SetTimer(hWnd,NULL,1000,NULL);
return 0;
これは、
>コールバック関数の引数のウインドウハンドルから得ていると、直接windowに表示してしまっていることになります。その場合、画面がちらつきます
これは、hdc = GetDC(hWnd);
こういうことを指しているのでしょうか?
回答お待ちしております。
No.1
- 回答日時:
コードはほとんどみていません。
一昔前の2Dゲームとかだと、「ダブルバッファリング」という手法を
利用していました。
これは、表示しようとする画面を裏で作成しておいて
いっぺんに表示するという方法です。
こうすることで、ちらつきや目に残る残像を減らすことができます。
オフスクリーンという単語が入っているので
使っているようにも見えたのですけど
なんか、オフスクリーンを直接表にしていたりしませんかね?
本当なら、オフスクリーンの出力がメッセージループの
アイドル処理部分とかにあるはずなんだけど見あたらないですね。
あと余談ですが
キャラの座標移動と描画はイベントを分けた方がいいと思いますよ。
if(team>=1000)
{
before_time=timeGetTime();
frame=0;
}
frame++;
<ーーここ
のところにDraw();が入ります。入れるのを忘れました。
それでもカクカクが消えません
>オフスクリーンという単語が入っているので
>使っているようにも見えたのですけど
>なんか、オフスクリーンを直接表にしていたりしませんかね?
void DrawImgMask(int idx,int x,int y,int sx,int sy,int w,int h,int mx,int my)
{
BitBlt(g_hdcOff,x,y,w,h,g_hdcImg[idx],mx,my,SRCPAINT);
BitBlt(g_hdcOff,x,y,w,h,g_hdcImg[idx],sx,sy,SRCAND);
}
オフスクリーンはorで切り取って、
次にandで切り取ったのを背景に貼り付けるような作りになっています。
そしてPAINTで表画面に貼り付ける感じになっております。
なにか間違っているのでしょうか?
直すことはできないのでしょうか?
回答お待ちしております。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# バイナリファイルをコピーするのにかかる時間を測りたいのですが実行するとFatel error:gli 2 2022/11/03 01:10
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- Visual Basic(VBA) エクセルマクロでアニメを作る方法を教えてください。 1 2023/02/07 14:27
- CGI perlで書いたcgiでsqliteの使い方を教えてください 2 2023/05/08 21:29
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- Java javaでのプログラム(配列)について質問です. 2 2022/10/14 22:27
- Ruby パイソンプログラミング 2 2022/12/03 18:44
- JavaScript アップロードファイルの種類によって処理を分岐させたいのですが書き方が分からずアドバイスお願いします 4 2023/06/17 19:12
- C言語・C++・C# カードシャッフルのブログラムを使ってc言語でブラックジャックをしたい 2 2022/04/12 15:13
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
分数の足し算をさせるプログラ...
-
C言語で%を使わない余りの出し方
-
再起呼び出しの回数をカウント...
-
C言語のプログラムについて(...
-
3のつく数と3の倍数を表示 C言語
-
迷路を脱出する経路探索プログ...
-
intとlongは同じ?
-
円周にアンチエイリアスをかける
-
【C#】SQL文の中に変数を埋め込...
-
迷路の解を見つけるアルゴリズム
-
2の補数を計算するプログラム
-
直線補間について
-
条件が多い場合
-
DXライブラリによるパズルゲー...
-
ヒストグラム均等化処理プログラム
-
異なるn個の整数からr個の整数...
-
最大の四角形を求めるプログラム
-
C#で疑似カラー
-
乱数生成について
-
rand()の乱数は何故良くないの?
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
おすすめ情報