2017-06-13 6 views
0

Je crée un jeu simple en utilisant l'API Win32. Quand je clique sur la fenêtre, une boule apparaît et commence à rouler ressembler à un jeu de bidaWin32 boucle de jeu

Mon problème est quand j'appelle "InvalidateRect", mon jeu très lag. Je ne sais pas que je fais quelque chose de mal !!!

Et mon HPEN ne fonctionne pas comme ce que j'attends

S'il vous plaît aider !!! Merci et désolé pour mon mauvais anglais

.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

Essayez un débogage. Vous ne vérifiez pas les valeurs de retour. Peut-être que certains de ces appels échouent. Où le programme passe-t-il son temps? Et l'utilisation d'asm rend votre vie très difficile pour absolument aucun avantage du tout. –

Répondre

0

Ce n'est pas une bonne idée d'utiliser le temps du système pour des problèmes de vitesse. Utilisez votre procédure moveEllipse à la place et augmentez vectorX et vectorY pour plus de vitesse. InvalidateRec devrait être appelé s'il y a une vraie mise à jour nécessaire. Vous pouvez atteindre cela en utilisant une minuterie au lieu de changer et de vérifier l'heure du système: 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

Un débordement de pile est en train de se produire, vous avez probablement l'intention d'appeler "PeekMessage" à la place de "GetMessage" L'ID de temporisateur est également choisi de manière inappropriée. Il est de type "UINT_PTR". peut passer une adresse mémoire unique – IInspectable

+0

@IInspectable: Je voulais dire 'GetMessage' et enlevé le mauvais push Désolé 'UINT_PTR' signifie [*" Un entier non signé, dont la longueur dépend de la taille du mot du processeur "*] (https://msdn.microsoft.com/library/cc248915.aspx) Il n'a pas besoin d'être unique et doit être une valeur directe, pas une adresse mémoire – rkhb

+0

Il doit être unique pour une minuterie. s d'une entité distincte est le moyen le plus simple de garantir l'unicité. C'est pourquoi l'ID est un "UINT_PTR" (par rapport à un "UINT", ce qui serait ** suffisant ** pour contenir un identifiant unique pour les minuteurs simultanés pris en charge maximum). Voir [Comment appeler SetTimer avec un ID de temporisateur qui est garanti pour ne pas entrer en conflit avec un autre ID de temporisateur?] (Https://blogs.msdn.microsoft.com/oldnewthing/20150924-00/?p=91521). – IInspectable

0

Vous gérez un seul message entre l'exécution de votre GAME_LOOP. Cela ne présage rien de bon. Au lieu de cela, vidangez toute la file d'attente de messages entre les mises à jour d'écran. La solution est simple: Ajouter

jmp MESSAGE_LOOP 

juste après

call DispatchMessage 
+0

Merci, mais il est encore en retard :( –

+0

@ hinhVănKiệt: Eh bien, un appel à 'SetSystemTime' pour implémenter la synchronisation locale, process-private, n'est pas idéal non plus.Il y a probablement beaucoup plus de problèmes avec le code, mais ma réponse – IInspectable