Win32 游戏循环
Win32 game loop
我正在使用 Win32 API 创建简单的游戏。当我点击 window 时,出现一个球并开始滚动,看起来像 bida 游戏
我的问题是当我调用 "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
您正在 运行 您的 GAME_LOOP
之间处理一条消息。这可不是什么好兆头。相反,在屏幕更新之间清空整个消息队列。解决方法很简单:Add
jmp MESSAGE_LOOP
紧接着
call DispatchMessage
使用系统时间来解决速度问题不是一个好主意。请改用您的程序 moveEllipse
并增加 vectorX
和 vectorY
以获得更快的速度。如果需要真正的更新,应该调用 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
我正在使用 Win32 API 创建简单的游戏。当我点击 window 时,出现一个球并开始滚动,看起来像 bida 游戏
我的问题是当我调用 "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
您正在 运行 您的 GAME_LOOP
之间处理一条消息。这可不是什么好兆头。相反,在屏幕更新之间清空整个消息队列。解决方法很简单:Add
jmp MESSAGE_LOOP
紧接着
call DispatchMessage
使用系统时间来解决速度问题不是一个好主意。请改用您的程序 moveEllipse
并增加 vectorX
和 vectorY
以获得更快的速度。如果需要真正的更新,应该调用 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