⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.asm

📁 俄罗斯方块用汇编语言编写 (1)执行的命令: ---------------------------------- ML /c /coff /Cp main.asm Link /subsy
💻 ASM
📖 第 1 页 / 共 2 页
字号:
;作者:仙人指路,QQ 13633292, QQ群 28287492
;******************************************************************************

.386
.model flat, stdcall
option casemap:none

;******************************************************************************

include     windows.inc
include     gdi32.inc
includelib  gdi32.lib
include     user32.inc
includelib  user32.lib
include     kernel32.inc
includelib  kernel32.lib

;通用控件库
include comctl32.inc
includelib comctl32.lib

include     <data.inc> 

;******************************************************************************
        .code
;******************************************************************************

;--------------------------------------
; 把10*20的方块矩阵画到窗口上
;--------------------------------------

_MapToWnd proc

    ret
_MapToWnd endp

;--------------------------------------
; 随机数
;--------------------------------------

_Rand proc uses ebx ecx edx, first, second
    local stime: SYSTEMTIME

    ;取得随机数的种子,当然,可用别的方法代替
    invoke GetLocalTime, addr stime   ;当前本地时间
    movzx eax, stime.wMilliseconds    ;现在时间的毫秒
    ;mov ebx, 3
    ;mul ebx
    movzx ebx, stime.wSecond
    add eax, ebx

    ;invoke GetTickCount ; 程序开始运行时间的毫秒数

    mov ecx, 23         ; X = ecx = 23
    mul ecx             ; eax = eax * X
    add eax, 97          ; eax = eax + Y (Y = 97)
    mov ecx, second     ; ecx = 上限
    sub ecx, first      ; ecx = 上限 - 下限
    inc ecx             ; Z = ecx + 1 (得到了范围)
    xor edx, edx        ; edx = 0
    div ecx             ; eax = eax mod Z (余数在edx里面)
    add edx, first      ; 修正产生的随机数的范围
    mov eax, edx        ; eax = Rand_Number
    ret
_Rand endp


;--------------------------------------
;索引号转换成窗口坐标
;方格左上角的坐标
;Cell是表示小方格的全局变量,
;i-行, j-列
;--------------------------------------

_IndexToCoord proc i, j

    mov eax, 20  
    mul j
    add eax, 2
    mov Cell.left, eax ;求坐标X [x] = 2 + j * 20

    mov eax, 20
    mul i
    add eax, 2
    mov Cell.top, eax ;求坐标Y [y] = 2 + i * 20

    mov eax, 20  
    mul j
    add eax, 21  ;考虑到有间隔线
    mov Cell.right, eax ;求坐标X

    mov eax, 20
    mul i
    add eax, 21
    mov Cell.bottom, eax ;求坐标Y 

    ret
_IndexToCoord endp

Test_IndexToCoord proc
    invoke _IndexToCoord, 19, 9
    ;mov eax, 'K'
    invoke wsprintf, addr DgBuffer, addr DgMsg, Cell.left, Cell.top, Cell.right, Cell.bottom
    invoke MessageBox, NULL, addr DgBuffer, addr DgCaption, MB_OK
    ret
Test_IndexToCoord endp

;--------------------------------------
;游戏矩阵在(i,j)处的符号
;返回al
;--------------------------------------

_GetMapChar proc uses edx, i, j
    mov eax, i
    mov edx, 10
    mul edx
    add eax, j
    mov edx, offset Map
    add edx, eax             ; edx = Map + j * 10 + i
    mov al, byte ptr [edx]
    movzx eax, al
    ret
_GetMapChar endp

;--------------------------------------
;设置游戏矩阵在(i,j)处的符号设置成'Q'
;返回al
;--------------------------------------

_SetMapChar proc uses edx, i, j
    mov eax, i
    mov edx, 10
    mul edx
    add eax, j
    mov edx, offset Map
    add edx, eax             ; edx = Map + j * 10 + i
    mov al, 'Q'
    mov byte ptr [edx], al
    ret
_SetMapChar endp


;--------------------------------------
; WM_PAINT事件
;--------------------------------------

_OnPaint proc
    local ps: PAINTSTRUCT    
    local hdc

    invoke BeginPaint, HMainWnd, addr ps
    mov hdc, eax

    ;求需要重画的区域的长和宽
    mov	eax, ps.rcPaint.right
    sub	eax, ps.rcPaint.left
    mov	ecx, ps.rcPaint.bottom
    sub	ecx, ps.rcPaint.top

    ;把内存设备拷贝到窗口上
    invoke BitBlt, 
           hdc, ps.rcPaint.left, ps.rcPaint.top, eax, ecx, 
           HMemWnd, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY
    invoke EndPaint, HMainWnd, addr ps
    ret 
_OnPaint endp

;--------------------------------------
; 在缓冲区画图
;--------------------------------------

_DrawView proc uses ebx ecx esi
    local i, j

    ;画背景是蓝色
    invoke FillRect, HMemWnd, addr Panel, BlueBrush

    ;画10*20个方格
    mov i, 0
    .while i < 20         ;总共有20行      
        mov j, 0
        .while j < 10     ;10列
            invoke _IndexToCoord, i, j  ;改变Cell的四角坐标
            ;(i,j)处的符号
            invoke _GetMapChar, i, j
            .if al == ' '     ;画空白方块
                invoke FillRect, HMemWnd, addr Cell, BlackBrush
                ;invoke MessageBox, NULL, offset DgMsg, offset DgCaption, MB_OK
            .elseif al == 'Q' ;画墙根                
                invoke StretchBlt, \
                       HMemWnd, Cell.left, Cell.top, CellWidth, CellHeight, \
                       HDCO, 0, 0, 35, 35, \
                       SRCCOPY  
                ;invoke MessageBox, NULL, offset DgMsg, offset DgCaption, MB_OK
            .endif
            inc j            
        .endw 
        inc i        
    .endw 

    ;画正在下落的东西,共4个方块,
    .if IsDrawCooky
        mov i, 0
        mov esi, offset Dots
        .while i < 4 
            mov ebx, [esi]
            add esi, 4
            mov ecx, [esi]
            add esi, 4
            invoke _IndexToCoord, ebx, ecx 
            invoke StretchBlt, \
                   HMemWnd, Cell.left, Cell.top, 20, 20, \
                   HDCX, 0, 0, 35, 35, \
                   SRCCOPY 
            inc i
        .endw
    .endif
    ret
_DrawView endp


Test_WndCreate proc
    invoke wsprintf, addr DgBuffer, addr DgMsg, HMemWnd
    invoke MessageBox, NULL, addr DgBuffer, addr DgCaption, MB_OK
    ret
Test_WndCreate endp

;--------------------------------------
; WM_CREATE消息
;--------------------------------------

_CreateOther proc
    local hbmp1, hbmp2, hbmp3            ;位图句柄
    local hdc

    invoke GetDC, HMainWnd               ;这样得到的窗口设备和BeginPaint得到的设备不一样
    mov hdc, eax                         ;所以不能这样用

    ;画板的矩形大小
    mov Panel.left, 0
    mov Panel.top, 0
    mov Panel.right, PanelWidth
    mov Panel.bottom, PanelHeight

    ;正在下落的方块图片
    invoke LoadBitmap, HInstance, IDB_BITMAP2  
    mov hbmp1, eax
    invoke CreateCompatibleDC, hdc    
    mov HDCX, eax
    invoke SelectObject, HDCX, hbmp1    

    ;已经落到底的方块图片
    invoke LoadBitmap, HInstance, IDB_BITMAP8  
    mov hbmp2, eax
    invoke CreateCompatibleDC, hdc
    mov HDCO, eax
    invoke SelectObject, HDCO, hbmp2

    ;窗口图像的缓冲区
    invoke CreateCompatibleDC, hdc
    mov HMemWnd, eax
    invoke	CreateCompatibleBitmap, hdc, PanelWidth, PanelHeight
    mov	hbmp3, eax
    invoke SelectObject, HMemWnd, hbmp3

    ;画空白小方格的画刷
    invoke GetStockObject, BLACK_BRUSH
    mov BlackBrush, eax

    ;画蓝色背景的画刷
    invoke CreateSolidBrush, 0FF0000H
    mov BlueBrush, eax

    ;释放
    invoke DeleteObject, hbmp1
    invoke DeleteObject, hbmp2
    invoke DeleteObject, hbmp3
    invoke ReleaseDC, HMainWnd, hdc
    
    ;先把图画到内存设备中
    invoke _DrawView

    ;状态栏
    invoke CreateStatusWindow, \
           WS_CHILD or WS_VISIBLE, \  
           0, \
           HMainWnd, \
           ID_STATUSBAR
    mov	HStatus, eax
    mov Score, 0
    invoke wsprintf, addr StatusBuffer, addr StatusMsg, Score
    invoke SendMessage, HStatus, SB_SETTEXT, 0, addr StatusBuffer

    ret
_CreateOther endp

;--------------------------------------
; WM_CLOSE消息
;--------------------------------------
_OnClose proc
    invoke DeleteObject, BlueBrush
    invoke DeleteDC, HMemWnd
    invoke DestroyWindow, HMainWnd
    invoke PostQuitMessage, NULL
_OnClose endp

;--------------------------------------
; 开始新游戏
;--------------------------------------
_NewGame proc
    .if IsTimer
        mov IsTimer, FALSE
        invoke KillTimer, HMainWnd, ID_TIMER1
    .endif 
    mov al, ' '         ;把矩阵清空
    mov edi, offset Map
    mov ecx, 200
    rep stosb
    invoke _DrawView    ;重新画游戏
    invoke InvalidateRect, HMainWnd, NULL, FALSE 
    invoke SetTimer, HMainWnd, ID_TIMER1, INTERVAL, NULL

    mov IsTimer, TRUE
    mov IsDrawCooky, TRUE
    mov Act, XNEW

    ;状态栏
    mov Score, 0
    invoke wsprintf, addr StatusBuffer, addr StatusMsg, Score
    invoke SendMessage, HStatus, SB_SETTEXT, 0, addr StatusBuffer
    ret
_NewGame endp

;--------------------------------------
; 游戏结束,一切静止
;--------------------------------------
_GameOver proc
    .if IsTimer
        mov IsTimer, FALSE
        invoke KillTimer, HMainWnd, ID_TIMER1
    .endif 
    mov IsTimer, FALSE
    mov IsDrawCooky, FALSE
    mov Act, 0
    ret
_GameOver endp



;--------------------------------------
; 产生新的要下落的物件,如果有放置的空间返回True,如果没有空间返回False
;--------------------------------------
_NewCooky proc uses ebx edi
    local x, y       ;游戏矩阵上的位置(行,列)
    local i, j       ;物件4*4方格上的位置
    local pos        ;(i, j)位置的的地址
    local count      ;计数, 达到4个方格就退出
    local CanNew     ;是否有位置产生

    mov CanNew, TRUE
    invoke _Rand, 0, 6           ;得到随机的将要落下的物件

    mov CookyNo, eax               ;把现在是哪一个方块和方块的位置保存起来
    mov Pose, 0
    mov CookyTop, 0              ;把方块左上角的位置保存起来
    mov CookyLeft, 4             

    ;;mov eax, 0
    mov ebx, 64
    mul ebx
    mov esi, eax
    add esi, offset Box          ;esi是存放物件结构的数据的地址
    mov x, 0
    mov i, 0   
    mov count, 1
    mov edi, offset Dots         ;把行列位置放到edi指定的地方去
    .while i < 4
        mov j, 0
        mov y, 4
        .while j < 4
            mov bl, [esi]
            .if bl == 'X'
                ;先判断矩阵上是否有位置
                invoke _GetMapChar, x, y
                .if al == 'Q'
                    mov CanNew, FALSE
                    jmp @F
                .endif
                mov edx, x       ;行
                mov [edi], edx   ;还要这样赋值
                add edi, 4
                mov edx, y       ;列
                mov [edi], edx
                add edi, 4
                inc count
                .if count > 4    ;已经够了4个方格, 怕不小心Dots越界
                    jmp @F
                .endif
            .endif
            inc j
            inc y
            inc esi
        .endw
        inc i
        inc x
    .endw    
@@:
    .if CanNew
        mov IsDrawCooky, TRUE
        invoke _DrawView    ;重新画游戏
        invoke InvalidateRect, HMainWnd, NULL, FALSE
        mov Act, XDOWN
    .else
        invoke _GameOver
        invoke wsprintf, addr StatusBuffer, addr GameOver, Score
        invoke MessageBox, NULL, addr StatusBuffer, addr TipCaption, MB_OK
    .endif
    ret
_NewCooky endp

Test_NewCooky proc uses ecx
    local x1, y1, x2, y2, x3, y3, x4, y4

    mov ecx, offset Dots    
    mov eax, [ecx]
    mov x1, eax
    add ecx, 4
    mov eax, [ecx]
    mov y1, eax
    add ecx, 4
    mov eax, [ecx]
    mov x2, eax
    add ecx, 4
    mov eax, [ecx]
    mov y2, eax
    add ecx, 4
    mov eax, [ecx]
    mov x3, eax
    add ecx, 4
    mov eax, [ecx]
    mov y3, eax
    add ecx, 4
    mov eax, [ecx]
    mov x4, eax
    add ecx, 4
    mov eax, [ecx]
    mov y4, eax

    invoke wsprintf, addr DgBuffer, addr DgMsg, x1, y1, x2, y2, x3, y3, x4, y4
    invoke MessageBox, NULL, addr DgBuffer, addr DgCaption, MB_OK

    invoke _NewCooky    ;产生新物件
    mov IsDrawCooky, TRUE
    invoke _DrawView    ;重新画游戏
    invoke InvalidateRect, HMainWnd, NULL, FALSE 

    ret
Test_NewCooky endp

;--------------------------------------
; 消去行
;--------------------------------------

_RemoveRow proc uses ebx ecx edx esi edi
    local i                        ;循环每一行用
    local j                        ;转移每一个元素用
    local full_num                 ;有多少行被消去了
    local addr_from, addr_to       ;消去一行,自上往下填充,起始地址和目标地址
    local line_flag                ;指向每一行是否已满的标志
    local mov_num                  ;移动个数

    invoke KillTimer, HMainWnd, ID_TIMER1
    mov full_num, 0
    mov i, 0                       ;i表示行号
    mov edx, offset RowFull        ;这个地方为什么非得用寄存器, 内存变量为啥就是不行
    mov addr_from, offset Map
    sub addr_from, 1
    mov addr_to, offset Map
    add addr_to, 9
    mov mov_num, 10
    .while i < 20
        mov bl, byte ptr [edx]        
        .if bl == 'Y'              ;消去一行
            ;invoke MessageBox, NULL, addr DgMsg, addr DgCaption, MB_OK

            ;注意,我本来在这里打算这么用,结果程序执行的莫名其妙,只好用笨方法了 
            ;mov esi, addr_from
            ;mov edi, addr_to
            ;mov ecx, mov_num
            ;std
            ;rep movsb

            mov j, 0
            mov esi, addr_from
            mov edi, addr_to
            mov ebx, mov_num
            .while j < ebx

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -