2017-06-13 165 views
0

我使用Win32 API创建简单的游戏。当我点击窗口时,出现一个球并开始滚动看起来像比达游戏Win32游戏循环

我的问题是当我打电话“InvalidateRect”,我的游戏很滞后。我不知道我在做任何错误的事情!

而我的hPen没有像我期望的那样工作

请帮忙!!! 谢谢你,对不起我的英语不好

.386 ; use 80386 instruction 
.model flat,stdcall ; uses flat memory addressing model 
option casemap:none 

include C:\masm32\include\windows.inc ; windows.inc have structures and constants 
include C:\masm32\include\user32.inc 
includelib C:\masm32\lib\user32.lib ; CreateWindowEx, RegisterClassEx,... 
include C:\masm32\include\kernel32.inc 
includelib C:\masm32\lib\kernel32.lib ; ExitProcess 
include C:\masm32\include\masm32.inc 
includelib C:\masm32\lib\masm32.lib 
include C:\masm32\include\gdi32.inc 
includelib C:\masm32\lib\gdi32.lib 

.CONST 
DRAWING equ 1 
WAITING equ 0 
PEN_COLOR equ 00000000h ; black 
PEN_SIZE equ 2 
BALL_SIZE equ 35 
BALL_SPEED equ 20 

.DATA 
ClassName db 'SimpleWinClass',0 
AppName db 'Ball',0 

state db WAITING 

vectorX dd 6 
vectorY dd -7 

WIN_WIDTH dd 700 
WIN_HEIGHT dd 500 

.DATA? 
; HINSTANCE & LPSTR typedef DWORD in windows.inc 
; reserve the space for future use 
hInstance HINSTANCE ? 

tlpoint POINT <> 
brpoint POINT <> 

; use for create window 
wc WNDCLASSEX <?> 
msg MSG <?> ; handle message 
hwnd HWND ? ; handle window procedure 

hdc HDC ? 
ps PAINTSTRUCT <?> 

time SYSTEMTIME <?> 

hPen HPEN ? 

.CODE 
start: 
    ; call GetModuleHandle(null) 
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms683199(v=vs.85).aspx 
    push NULL 
    call GetModuleHandle ; module handle same as instance handle in Win32 
    mov hInstance, eax ; return an instance to handle in eax 

    ; call WinMain(hInstance, hPrevInstance, CmdLine, CmdShow) 
    ; our main function 
    push SW_SHOW 
    push NULL 
    push NULL 
    push hInstance 
    call WinMain 

    ; call ExitProcess 
    push eax 
    call ExitProcess 

    ; Define WinMain 
    WinMain proc hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:DWORD 
     ; Structure in msdn, define in windows.inc 
     ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms633577(v=vs.85).aspx 

     ; Load default icon 
     push IDI_APPLICATION 
     push NULL 
     call LoadIcon 
     mov wc.hIcon, eax 
     mov wc.hIconSm, eax 

     ; Load default cursor 
     push IDC_ARROW 
     push NULL 
     call LoadCursor 
     mov wc.hCursor, eax 

     mov wc.cbSize, SIZEOF WNDCLASSEX ; size of this structure 
     mov wc.style, CS_HREDRAW or CS_VREDRAW ; style of windows https://msdn.microsoft.com/en-us/library/windows/desktop/ff729176(v=vs.85).aspx 
     mov wc.lpfnWndProc, OFFSET WndProc ; andress of window procedure 
     mov wc.cbClsExtra, NULL 
     mov wc.cbWndExtra, NULL 
     push hInstance 
     pop wc.hInstance 
     mov wc.hbrBackground, COLOR_WINDOW+1 ; background color, require to add 1 
     mov wc.lpszMenuName, NULL 
     mov wc.lpszClassName, OFFSET ClassName 

     ; we register our own class, named in ClassName 
     push offset wc 
     call RegisterClassEx 

     ; after register ClassName, we use it to create windows compond 
     ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms632680(v=vs.85).aspx 
     push NULL 
     push hInstance 
     push NULL 
     push NULL 
     push WIN_HEIGHT 
     push WIN_WIDTH 
     push CW_USEDEFAULT 
     push CW_USEDEFAULT 
     push WS_OVERLAPPEDWINDOW 
     push offset AppName 
     push offset ClassName 
     push WS_EX_CLIENTEDGE 
     call CreateWindowEx 

     mov hwnd, eax ; return windows handle 

     ; display window 
     ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms633548(v=vs.85).aspx 
     push CmdShow 
     push hwnd 
     call ShowWindow 

     ; update window 
     ; https://msdn.microsoft.com/en-us/library/windows/desktop/dd145167(v=vs.85).aspx 
     push hwnd 
     call UpdateWindow 

     ; Message Loop 
     MESSAGE_LOOP: 
      ; get message 
      ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms644936(v=vs.85).aspx 
      push PM_REMOVE 
      push 0 
      push 0 
      push NULL 
      push offset msg 
      call PeekMessage 

      ; return in eax 
      ; if the function retrieves a message other than WM_QUIT, the return value is nonzero. 
      ; if the function retrieves the WM_QUIT message, the return value is zero. 
      cmp eax, 0 
      je GAME_LOOP 

      cmp msg.message, WM_QUIT 
      je END_LOOP 

      ; translate virtual-key messages into character messages - ASCII in WM_CHAR 
      ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms644955(v=vs.85).aspx 
      push offset msg 
      call TranslateMessage 

      ; sends the message data to the window procedure responsible for the specific window the message is for. 
      ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms644934(v=vs.85).aspx 
      push offset msg 
      call DispatchMessage 

     GAME_LOOP: 
      ; check that is DRAWING or not? 
      cmp [state], DRAWING 
      jne MESSAGE_LOOP 

      push offset time 
      call GetSystemTime 

      cmp dword ptr[time.wMilliseconds], BALL_SPEED 
      jl MESSAGE_LOOP 

      push TRUE 
      push NULL 
      push hwnd 
      call InvalidateRect 

      jmp MESSAGE_LOOP 

     END_LOOP: 
      mov eax, msg.wParam 
     ret 
    WinMain endp 

    ; Handle message with switch(notification) 
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms633573(v=vs.85).aspx 
    WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM 
     cmp uMsg, WM_PAINT 
     je ON_WM_PAINT 

     cmp uMsg, WM_CREATE 
     je ON_WM_CREATE 

     cmp uMsg, WM_LBUTTONDOWN 
     je ON_WM_LBUTTONDOWN 

     cmp uMsg, WM_DESTROY 
     je ON_WM_DESTROY 

     cmp uMsg, WM_QUIT 
     je ON_WM_DESTROY 

     cmp uMsg, WM_CLOSE 
     je ON_WM_DESTROY 

     jmp ON_DEFAULT 

     ; user close program 
     ON_WM_DESTROY: 
      push NULL 
      call PostQuitMessage 
      jmp EXIT 

     ON_WM_CREATE: 
      ; create a pen with specific color and size 
      ; https://msdn.microsoft.com/en-us/library/windows/desktop/dd183509(v=vs.85).aspx 
      push PEN_COLOR 
      push PEN_SIZE 
      push PS_SOLID 
      call CreatePen 
      mov hPen, eax 

      jmp EXIT 

     ON_WM_LBUTTONDOWN: 
      cmp [state], DRAWING 
      je EXIT 

      push lParam 
      call updateXY 

      ; when clicked, set state to DRAWING 
      mov [state], DRAWING 

      mov dword ptr[time.wMilliseconds], BALL_SPEED 
      push offset time 
      call SetSystemTime 

      jmp EXIT 

     ON_WM_PAINT: 
      mov dword ptr[time.wMilliseconds], 0 
      push offset time 
      call SetSystemTime 

      push offset ps 
      push hWnd 
      call BeginPaint 
      mov hdc, eax 

      ; apply pen to hdc 
      push hPen 
      push hdc 
      call SelectObject 

      call createEllipse 

      push offset ps 
      push hWnd 
      call EndPaint 

      jmp EXIT 

     ON_DEFAULT: 
      ; handle any message that program don't handle 
      ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms633572(v=vs.85).aspx 
      push lParam 
      push wParam 
      push uMsg ; message 
      push hWnd ; windows 
      call DefWindowProc 

      jmp EXIT 

     EXIT: 
      ret 
    WndProc endp 

    createEllipse proc 
     push brpoint.y 
     push brpoint.x 
     push tlpoint.y 
     push tlpoint.x 
     push hdc 
     call Ellipse 

     call moveEllipse 

     mov eax, WIN_WIDTH 
     cmp brpoint.x, eax 
     jg MEET_RIGHT_LEFT 

     mov eax, WIN_HEIGHT 
     cmp brpoint.y, eax 
     jg MEET_BOTTOM_TOP 

     cmp tlpoint.x, 0 
     jl MEET_RIGHT_LEFT 

     cmp tlpoint.y, 0 
     jl MEET_BOTTOM_TOP 

     jmp MEET_NONE 

     MEET_RIGHT_LEFT: 
      neg vectorX 
      jmp MEET_NONE 

     MEET_BOTTOM_TOP: 
      neg vectorY 
      jmp MEET_NONE 

     MEET_NONE: 

     ret 
    createEllipse endp 

    moveEllipse proc 
     mov eax, dword ptr[vectorX] 
     mov ecx, dword ptr[vectorY] 

     add tlpoint.x, eax 
     add tlpoint.y, ecx 
     add brpoint.x, eax 
     add brpoint.y, ecx 

     ret 
    moveEllipse endp 

    updateXY proc lParam:LPARAM 
     mov eax, lParam 

     ; get low word that contain x 
     xor ebx, ebx 
     mov bx, ax 

     mov tlpoint.x, ebx 
     mov brpoint.x, ebx 
     add brpoint.x, BALL_SIZE 

     ; get high word that contain y 
     mov eax, lParam 
     shr eax, 16 

     mov tlpoint.y, eax 
     mov brpoint.y, eax 
     add brpoint.y, BALL_SIZE 

     ret 
    updateXY endp 

end start 
+2

尝试一些调试。你不检查返回值。也许其中一些通话失败。该计划在哪里花费时间?使用asm会让你的生活变得非常困难,绝对没有任何好处。 –

回答

0

不使用该系统时对速度问题是一个好主意。改为使用您的程序moveEllipse,并增加vectorXvectorY以获得更快的速度。如果需要更新,应该调用InvalidateRec。您可以通过使用计时器来达到此目的,而不是更改并检查系统时间:SetTimer

.386 ; use 80386 instruction 
.model flat,stdcall ; uses flat memory addressing model 
option casemap:none 

include C:\masm32\include\windows.inc ; windows.inc have structures and constants 
include C:\masm32\include\user32.inc 
includelib C:\masm32\lib\user32.lib ; CreateWindowEx, RegisterClassEx,... 
include C:\masm32\include\kernel32.inc 
includelib C:\masm32\lib\kernel32.lib ; ExitProcess 
include C:\masm32\include\masm32.inc 
includelib C:\masm32\lib\masm32.lib 
include C:\masm32\include\gdi32.inc 
includelib C:\masm32\lib\gdi32.lib 

.CONST 
DRAWING equ 1 
WAITING equ 0 
PEN_COLOR equ 00000000h ; black 
PEN_SIZE equ 2 
BALL_SIZE equ 35 
BALL_SPEED equ 20 

.DATA 
ClassName db 'SimpleWinClass',0 
AppName db 'Ball',0 

state db WAITING 

vectorX dd 19 
vectorY dd -19 

WIN_WIDTH dd 700 
WIN_HEIGHT dd 500 

.DATA? 
; HINSTANCE & LPSTR typedef DWORD in windows.inc 
; reserve the space for future use 
hInstance HINSTANCE ? 

tlpoint POINT <> 
brpoint POINT <> 

; use for create window 
wc WNDCLASSEX <?> 
msg MSG <?> ; handle message 
hwnd HWND ? ; handle window procedure 

hdc HDC ? 
ps PAINTSTRUCT <?> 

time SYSTEMTIME <?> 

hPen HPEN ? 

.CODE 
start: 
    ; call GetModuleHandle(null) 
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms683199(v=vs.85).aspx 
    push NULL 
    call GetModuleHandle ; module handle same as instance handle in Win32 
    mov hInstance, eax ; return an instance to handle in eax 

    ; call WinMain(hInstance, hPrevInstance, CmdLine, CmdShow) 
    ; our main function 
    push SW_SHOW 
    push NULL 
    push NULL 
    push hInstance 
    call WinMain 

    ; call ExitProcess 
    push eax 
    call ExitProcess 

    ; Define WinMain 
    WinMain proc hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:DWORD 
     ; Structure in msdn, define in windows.inc 
     ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms633577(v=vs.85).aspx 

     ; Load default icon 
     push IDI_APPLICATION 
     push NULL 
     call LoadIcon 
     mov wc.hIcon, eax 
     mov wc.hIconSm, eax 

     ; Load default cursor 
     push IDC_ARROW 
     push NULL 
     call LoadCursor 
     mov wc.hCursor, eax 

     mov wc.cbSize, SIZEOF WNDCLASSEX ; size of this structure 
     mov wc.style, CS_HREDRAW or CS_VREDRAW ; style of windows https://msdn.microsoft.com/en-us/library/windows/desktop/ff729176(v=vs.85).aspx 
     mov wc.lpfnWndProc, OFFSET WndProc ; andress of window procedure 
     mov wc.cbClsExtra, NULL 
     mov wc.cbWndExtra, NULL 
     push hInstance 
     pop wc.hInstance 
     mov wc.hbrBackground, COLOR_WINDOW+1 ; background color, require to add 1 
     mov wc.lpszMenuName, NULL 
     mov wc.lpszClassName, OFFSET ClassName 

     ; we register our own class, named in ClassName 
     push offset wc 
     call RegisterClassEx 

     ; after register ClassName, we use it to create windows compond 
     ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms632680(v=vs.85).aspx 
     push NULL 
     push hInstance 
     push NULL 
     push NULL 
     push WIN_HEIGHT 
     push WIN_WIDTH 
     push CW_USEDEFAULT 
     push CW_USEDEFAULT 
     push WS_OVERLAPPEDWINDOW 
     push offset AppName 
     push offset ClassName 
     push WS_EX_CLIENTEDGE 
     call CreateWindowEx 

     mov hwnd, eax ; return windows handle 

     ; display window 
     ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms633548(v=vs.85).aspx 
     push CmdShow 
     push hwnd 
     call ShowWindow 

     ; update window 
     ; https://msdn.microsoft.com/en-us/library/windows/desktop/dd145167(v=vs.85).aspx 
     push hwnd 
     call UpdateWindow 

     ; Message Loop 
     MESSAGE_LOOP: 
      ; get message 
      ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms644936(v=vs.85).aspx 
      push 0 
      push 0 
      push NULL 
      push offset msg 
      call GetMessage 

      ; return in eax 
      ; if the function retrieves a message other than WM_QUIT, the return value is nonzero. 
      ; if the function retrieves the WM_QUIT message, the return value is zero. 
      test eax, eax 
      jle END_LOOP 

      ; translate virtual-key messages into character messages - ASCII in WM_CHAR 
      ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms644955(v=vs.85).aspx 
      push offset msg 
      call TranslateMessage 

      ; sends the message data to the window procedure responsible for the specific window the message is for. 
      ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms644934(v=vs.85).aspx 
      push offset msg 
      call DispatchMessage 

      jmp MESSAGE_LOOP 

     END_LOOP: 
      mov eax, msg.wParam 
     ret 
    WinMain endp 

    TimerProc PROC thwnd:HWND, uMsg:UINT, idEvent:UINT, dwTime:DWORD 
      push TRUE 
      push NULL 
      push thwnd 
      call InvalidateRect 
      ret 
    TimerProc ENDP 

    ; Handle message with switch(notification) 
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms633573(v=vs.85).aspx 
    WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM 
     cmp uMsg, WM_PAINT 
     je ON_WM_PAINT 

     cmp uMsg, WM_CREATE 
     je ON_WM_CREATE 

     cmp uMsg, WM_LBUTTONDOWN 
     je ON_WM_LBUTTONDOWN 

     cmp uMsg, WM_DESTROY 
     je ON_WM_DESTROY 

     cmp uMsg, WM_QUIT 
     je ON_WM_DESTROY 

     cmp uMsg, WM_CLOSE 
     je ON_WM_DESTROY 

     jmp ON_DEFAULT 

     ; user close program 
     ON_WM_DESTROY: 
      push NULL 
      call PostQuitMessage 
      jmp EXIT 

     ON_WM_CREATE: 
      ; create a pen with specific color and size 
      ; https://msdn.microsoft.com/en-us/library/windows/desktop/dd183509(v=vs.85).aspx 
      push PEN_COLOR 
      push PEN_SIZE 
      push PS_SOLID 
      call CreatePen 
      mov hPen, eax 

      jmp EXIT 

     ON_WM_LBUTTONDOWN: 
      cmp [state], DRAWING 
      je EXIT 

      push lParam 
      call updateXY 

      ; when clicked, set state to DRAWING 
      mov [state], DRAWING 

      push OFFSET TimerProc 
      push 20 
      push 1 
      push hwnd 
      call SetTimer 

;   mov dword ptr[time.wMilliseconds], BALL_SPEED 
;   push offset time 
;   call SetSystemTime 

      jmp EXIT 

     ON_WM_PAINT: 
      mov dword ptr[time.wMilliseconds], 0 

      push offset ps 
      push hWnd 
      call BeginPaint 
      mov hdc, eax 

      ; apply pen to hdc 
      push hPen 
      push hdc 
      call SelectObject 

      call createEllipse 

      push offset ps 
      push hWnd 
      call EndPaint 

      jmp EXIT 

     ON_DEFAULT: 
      ; handle any message that program don't handle 
      ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms633572(v=vs.85).aspx 
      push lParam 
      push wParam 
      push uMsg ; message 
      push hWnd ; windows 
      call DefWindowProc 

      jmp EXIT 

     EXIT: 
      ret 
    WndProc endp 

    createEllipse proc 
     push brpoint.y 
     push brpoint.x 
     push tlpoint.y 
     push tlpoint.x 
     push hdc 
     call Ellipse 

     call moveEllipse 

     mov eax, WIN_WIDTH 
     cmp brpoint.x, eax 
     jg MEET_RIGHT_LEFT 

     mov eax, WIN_HEIGHT 
     cmp brpoint.y, eax 
     jg MEET_BOTTOM_TOP 

     cmp tlpoint.x, 0 
     jl MEET_RIGHT_LEFT 

     cmp tlpoint.y, 0 
     jl MEET_BOTTOM_TOP 

     jmp MEET_NONE 

     MEET_RIGHT_LEFT: 
      neg vectorX 
      jmp MEET_NONE 

     MEET_BOTTOM_TOP: 
      neg vectorY 
      jmp MEET_NONE 

     MEET_NONE: 

     ret 
    createEllipse endp 

    moveEllipse proc 
     mov eax, dword ptr[vectorX] 
     mov ecx, dword ptr[vectorY] 

     add tlpoint.x, eax 
     add tlpoint.y, ecx 
     add brpoint.x, eax 
     add brpoint.y, ecx 

     ret 
    moveEllipse endp 

    updateXY proc lParam:LPARAM 
     mov eax, lParam 

     ; get low word that contain x 
     xor ebx, ebx 
     mov bx, ax 

     mov tlpoint.x, ebx 
     mov brpoint.x, ebx 
     add brpoint.x, BALL_SIZE 

     ; get high word that contain y 
     mov eax, lParam 
     shr eax, 16 

     mov tlpoint.y, eax 
     mov brpoint.y, eax 
     add brpoint.y, BALL_SIZE 

     ret 
    updateXY endp 

end start 
+0

这是一个堆栈溢出等待发生。你大概意思'叫PeekMessage'到位GetMessage'的'计时器ID也被不恰当地选择,它是类型'UINT_PTR'让你可以通过一个唯一的存储地址 – IInspectable

+0

@IInspectable:。我的意思'GetMessage'和除去错推对不起'UINT_PTR'手段[*“的无符号整数,其长度依赖于处理器字大小” *](HTTPS:/ /msdn.microsoft.com/library/cc248915.aspx)。它不需要是唯一的,而必须是直接值,而不是内存地址。 – rkhb

+0

对于定时器它需要是唯一的,而内存地址不同实体的独特性是保证唯一性的最简单方法。这就是为什么这个ID是一个'UINT_PTR'(而不是'UINT',这对于最大支持的并发定时器来说足以容纳唯一的ID)。请参阅[如何使用保证不与其他计时器ID冲突的计时器ID来调用SetTimer?](https://blogs.msdn.microsoft.com/oldnewthing/20150924-00/?p=91521)。 – IInspectable

0

您处理一个消息在运行您GAME_LOOP之间。这并不是一个好兆头。相反,在屏幕更新之间耗尽整个消息队列。解决方法很简单:将它

jmp MESSAGE_LOOP 

之后

call DispatchMessage 
+0

谢谢,但它仍然滞后:( –

+0

@ĐinhVănKiệt:那么,调用'SetSystemTime'来实现本地,进程专用同步也不是很理想。代码可能有很多错误,但我的答案解决了最明显的问题,相对于延迟。 – IInspectable