描画のカクカクについて
描画された画像が移動中たまに(動画を見ながら実行すると多く)カクカクするのですが、どうしたらこのカクカクをなくすことができるでしょうか?
多分ここだろうなと言うところを載せます。
//グローバル変数
static HDC g_hdcOff,g_hdcImg[MAX_IMAGE];
static HBRUSH g_hbrBg = NULL; // 背景用ブラシ
static HBITMAP g_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っだけです。
説明が足りないのなら補足します。
お礼
お、ほんとだ MidiOutProcの解説にそういう文章がありますね♪ ありがとうございます! 別の実験で 上記のように使い捨て的な判定するのではなくしておいて 別個に配列にIDを確保しておくようにして、timeSetEventをたくさん連続で呼んだり timeSetEvent→timeKillEvent→timeSetEvent→timeKillEvent といったことも試してみて問題はないようなので (ただ、連続で呼ぶほうはなぜか同じコールバック関数に対して一定の回数以上はできない・・・?というような現象が出ましたが、そんなに何回も呼ぶような設計はそもそもCPUへの影響とかタイミングのとりやすさも含めてあまりやらないで済むほうがいいと思うので) おそらく、むしろ単発で好きな時に走らせて、用がすんだらすぐに止めるようにしつつ、何度でも呼べることを前提にした設計の方が汎用性があっていいかもしれませんね。 (てかそういうことならスレッドのほうが意味的にあってるかもしれませんw) 作戦はいろいろ考えられますが、いずれにせよありがとうございます。