プロが教える店舗&オフィスのセキュリティ対策術

最近デバイスコンテキストを何とか理解してきたので、実験的に『上から物体が振ってくるのを避ける』というゲームを作ってみようと思い作り始めました。

『←』が押されれば、棒人間を左に、『→』が押されれば、棒人間を右に移動させる処理と、ランダムで●が上から落ちてくるという処理をタイマーを使ってやってみました。(スレッドとかはまだ勉強していないので)
一応完成はしたのですが、棒人間を動かすと、どうしても●がちらつきます。
この場合は、どういう風に処理をすればいいのでしょうか?
プログラムはこう書きました。

グローバル変数
Dim hBmp01 As HWND
Dim hBmp02 As HWND
Dim hBmp03 As HWND
Dim hBmp04 As HWND
Dim hMemDC As HDC
Dim BmpInfo As Long
Dim hBomDC As HWND
Dim Bomxy As RECT

Dim x As Long
Dim y As Long
Dim bx As Long
Dim by As Long
Dim n As Long

'----------------------------------------------------
省略
'-----------------------------------------------------

Sub MainWnd_Destroy()
DeleteObject(hBmp01)
DeleteObject(hBmp02)
DeleteObject(hBmp03)
DeleteObject(hBmp04)
YokeGame_DestroyObjects()
PostQuitMessage(0)
End Sub

Sub MainWnd_Create(ByRef CreateStruct As CREATESTRUCT)
SetWindowText(hMainWnd,"画像描写テスト ~爆弾的なものを避けるゲーム~")
hBmp01 = LoadImage(0,".\画像\人\普通.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE)
hBmp02 = LoadImage(0,".\画像\人\右.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE)
hBmp03 = LoadImage(0,".\画像\人\左.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE)
hBmp04 = LoadImage(0,".\画像\爆弾\ボム.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE)
GetWindowRect(hBmp04,Bomxy)

If hBmp01=0 or hBmp02=0 or hBmp03=0 or hBmp04=0 Then
MessageBox(hMainWnd,Ex"画像の読み込みに失敗しました\r\n強制終了します。","Error",MB_OK or MB_ICONHAND)
DeleteObject(hBmp01)
DeleteObject(hBmp02)
DeleteObject(hBmp03)
DeleteObject(hBmp04)
SendMessage(hMainWnd,WM_CLOSE,0,0)
End If

x=290
y=275
BmpInfo=1
bx = 320
by = 0

SetTimer(hMainWnd,0,300,0)

End Sub

Sub Kettei()
Dim ok As Long
by=0
Do
Randomize
bx = Fix(Rnd()*100)
If bx>0 and 630>bx Then
ok=TRUE
End If
Loop Until ok=TRUE
End Sub

Sub MainWnd_Paint(hDC As HDC)
hMemDC = CreateCompatibleDC(hDC)
hBomDC = CreateCompatibleDC(hDC)
If BmpInfo = 1 Then
SelectObject(hMemDC,hBmp01)
Else If BmpInfo = 2 Then
SelectObject(hMemDC,hBmp02)
Else If BmpInfo = 3 Then
SelectObject(hMemDC,hBmp03)
End If
BitBlt(hDC,x,y,40,50,hMemDC,0,0,SRCCOPY)

Sleep(30)

SelectObject(hMemDC,hBmp01)
BitBlt(hDC,x,y,40,50,hMemDC,0,0,SRCCOPY)

Sleep(30)

SelectObject(hBomDC,hBmp04)
BitBlt(hDC,bx,by,9,9,hBomDC,0,0,SRCCOPY)

DeleteDC(hMemDC)
DeleteDC(hBomDC)
BmpInfo = 1
End Sub

Sub MainWnd_KeyDown(KeyCode As Long, flags As Long)
If KeyCode = 37 Then
If x<=0 Then
x=0
Exit Sub
End If
x = x - 10
BmpInfo=3
End If

If KeyCode = 39 Then
If x>=600 Then
x = 600
Exit Sub
End If
x = x + 10
BmpInfo=2
End If

InvalidateRect(hMainWnd,ByVal 0,TRUE)

End Sub

Sub MainWnd_Timer(TimerID As DWord)
If TimerID = 0 Then
by = by + 10
InvalidateRect(hMainWnd,Byval 0,TRUE)

If by >=360 Then
Kettei()
End If
End If
End Sub

っと、このようになりました。(一応動きます)
strictには、チェックを入れていません。
バージョンは、4.23.00を使っています。

それと、InvalidateRect関数なのですが、
InvalidateRect(hMainWnd,Byval 0,TRUE)
の、二つ目のパラメータ(?)部分に、全体を再描写させるときに何故『Byval 0』と表記するのでしょうか?
ヘルプには、NULL を指定すると、クライアント領域全体が更新領域に設定されますと書かれていますが、NULLを指定すると無効な識別となります。

すみませんが、分かる方がいらっしゃいましたら、ご教授をお願いします。

A 回答 (1件)

 こんにちは。



 チラつくのは、BitBltの後にSleepを過剰に呼び出してしまっているからでしょう。
 キー入力の方向に対応した人間をBitBltした後、爆弾をBitBltしてから、Sleepをかければ良いでしょう。
 また、デバイスコンテキストは、可能な限り直に開放した方が良いです。
 後、細かい事に言及すると、MainWnd_KeyUpイベントを処理してその中で、←か→のボタンが離されたら、BmpInfo=1として人間を普通の向きにしてあげると良いと思います。
 「ByVal 0」に関しては、本来その部分にはRECT*と言うポインタが入ります。NULLを指定すると全体を再描画出来ます。

 「NULLについて」
 http://www.valley.ne.jp/~ryouga/machine/tips/c00 …

 まぁ、要は「0」の事です。
 「ByVal 0」と書く理由に関しては(しかし、0である事位は容易に想像出来る)、当方もActiveBasicの事をもっと勉強してみないと名言は出来ません。
 で、肝心なチラつき対策の方ですが、実際にActiveBasic5で試して見ました。以下参考程度に。

'再描画イベント(チラつき修正)
Sub MainWnd_Paint(hDC As HDC)
hMemDC = CreateCompatibleDC(hDC)
hBomDC = CreateCompatibleDC(hDC)

'キーに対応した方向の人間の絵を選択
If BmpInfo = 1 Then
SelectObject(hMemDC,hBmp01)
Else If BmpInfo = 2 Then
SelectObject(hMemDC,hBmp02)
Else If BmpInfo = 3 Then
SelectObject(hMemDC,hBmp03)
End If

'人間を描く
BitBlt(hDC,x,y,40,50,hMemDC,0,0,SRCCOPY)

'ボムの絵を選択
SelectObject(hBomDC,hBmp04)
'ボムの絵を描く
BitBlt(hDC,bx,by,9,9,hBomDC,0,0,SRCCOPY)

'先にデバイスコンテキストを開放した方がよい
DeleteDC(hMemDC)
DeleteDC(hBomDC)

'ココで休む
Sleep(30)
End Sub

'キーが離された時(追加)
Sub MainWnd_KeyUp(KeyCode As Long, flags As Long)
'←又は→が離された
If KeyCode = 37 or KeyCode = 39 Then
'普通の向きにしてから再描画する
BmpInfo=1
InvalidateRect(hMainWnd,ByVal 0,TRUE)
End If

End Sub
    • good
    • 0
この回答へのお礼

なるほど・・・
DCは早めに開放しなければいけなかったのですか・・・
勉強になりました!
スリープの数ですね?早速試してみます。
ありがとうございました

お礼日時:2008/12/31 16:51

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!