魔板 1.0 - Win32 汇编程序设计


;
; 概述
;

还记得以前玩过的魔板吗?

那时没有游戏机, 没有电脑, 更没有网络;

那时有着翠绿的山, 有着清澈的河水, 有着宽阔的稻田,
还有着小伙伴们一起度过... 

这是我期末的作业, 26号开始写, 到现在写了 4 天, 主程序有 1000 行
了(Oh my god!!). 这是我第一次用纯汇编写一个完整的程序, 更是我第
一次写游戏程序. 不多废话了, 写得不怎么好, 凑合着看吧  ^^



;
; 编译环境
;
操作系统
    Windows XP SP2

头文件/库文件
    来自 Masm32 v9.0
    
汇编器
    Macro Assembler v6.15
    
脚本资源编译器
    Windows Resource Compiler v6.0
    
链接器
    Microsoft Incremental Linker v6.0
    
nmake.exe
    Microsoft Program Maintenance Utility v6.0


;
; 整个工程的文件说明 ( 假设我们当前处于根目录下 )
;
 
MagicBoard.exe      游戏可执行程序
说明文档.txt        相关说明

Data 数据目录
    Picture_X.bmp   游戏图片, 格式为 300px * 150px
    Restart.wav     重新开始本局游戏时播放的子图重列声
    Step.wav        移动子图时播放的沙沙声

Src 源代码目录
    MagicBoard.asm  主汇编源文件
    MagicBoard.rc   资源文件
    MagicBoard.ico  程序图标
    ToolBar.bmp     工具条按钮位图
    Normal.cur      普通光标
    Finger.cur      手指光标
    MagicBoard.xml  XP 风格通用控件描述文件
    Makefile        Makefile 文件


;
; 源代码导读
;

在我看来, 阅读他人的源代码不是件容易的事( 如果你真想读的话 ). 更
何况这份源代码实在太长了, 下面我将主汇编源程序中的注释与函数名摘
抄出来, 各函数顺序与源程序中保持一致. 在你着手阅读源代码前, 我想, 阅读一下这里的摘要从而对程序的大体框架有个了解是很有必要的. 

MagicBoard.asm <魔板> 汇编源代码摘要:

;*******************************************************************************
; 宏定义
;*******************************************************************************
[code]


;*******************************************************************************
; 数据段
;*******************************************************************************
[code]


;*******************************************************************************
; 代码段
;*******************************************************************************

;-------------------------------------------------------------------------------
; 在 [ min, max ] 区间上生成一个随机数
; RandSeed = ( RandSeed * 23 + 7 ) % ( max - min + 1 )
;-------------------------------------------------------------------------------
RandomNumber proc min:DWORD, max:DWORD

    [code]
    
    ret
RandomNumber endp

;-------------------------------------------------------------------------------
; 以第 CurPicture 张图片开始一局游戏
;-------------------------------------------------------------------------------
StartPicture proc uses ebx edi, isNewPicture:BOOL
    
    ;
    ; 得到本局位图图片的句柄
    ;
    [code]
    
    ;
    ; 随机地将原图打散成 3 行 6 列 共 18 块, 将打散后的编号存到 CurBlocks 数组里
    ;
    ; 随机打散的方法为 :
    ;   0、初始状态 N = 17, M = 0, r = ?
    ;   1、将原图就地划分成 N 个子图, 顺序编号为 0 到 N, 将其看成一线性队列
    ;   2、在 [0,N] 区间上生成一随机数 r, 将子图队列中第 r 号取出
    ;   3、将编号 r 存到 CurBlocks 数组第 M 号单元
    ;   4、N = N -1, M = M + 1, 回到第 1 步
    ;
    [code]
    
    ; 游戏面板最后一个子区置为空, 为子图移动腾出空位
    [code]      
        
    ; 迫使游戏重绘
    [code]
    
    ; 播放子图重列声音
    [code]

    ret
StartPicture endp

;-------------------------------------------------------------------------------
; 绘制一帧游戏
;-------------------------------------------------------------------------------
DrawGame proc uses ebx esi, hdc:HDC 
    ;
    ; 选择笔触 / 画刷到设备环境
    ;
    [code]
    
    ;
    ; 绘制游戏主面板的下凹效果
    ;
    [code]
    
    ; 设置阴影笔触颜色             
    [code]    

    ; 绘制左边 / 上边
    [code]
    
    ; 设置高光笔触颜色
    [code]
    
    ; 绘制右边 / 下边
    [code]
            
    ;
    ; 顺序遍历游戏主面板各子区, 绘制打散的子图及其立体效果( 棱上高光与阴影 )
    ;
    [code]       
        ;
        ; 计算当前区域在目的设备环境(游戏主面板)上的坐标:
        ;   dstRow = 区号 / 6, dstCol = 区号 % 6
        ;   dstX = GameOrgX + dstCol * 50
        ;   dstY = GameOrgY + dstRow * 50
        ;
        [code]
        
        ;
        ; 计算当前区域所放置的子图在后台设备环境(游戏原图)上的坐标
        ; 当该区域放置有子图时, 标记为该子图在原图中的序号
        ; 当该区域未放置子图时, 标记为 -1
        ;
        ;   srcRow = 序号 / 6, srcCol = 序号 % 6
        ;   srcX = 0 + srcCol * 50
        ;   srcY = 0 + srcRow * 50
        ;
        ; 寄存器使用约定:
        ;   eax, ecx, edx 为调用者寄存器, 由调用者保护
        ;   ebx, esi, edi 为被调用者寄存器, 由被调用者保护
        ;
        [code]
        
        ; 如果当前区域放置有子图
        [code]

            ; 将子图从原图拷贝到当前区域
            [code]
            
            ;
            ; 绘制棱上高光与阴影
            ;
            [code]
            
            ; 设置高光笔触颜色          
            [code]  

            ; 绘制左边 / 上边
            [code]
            
            ; 设置阴影笔触颜色
            [code]
            
            ; 绘制右边 / 下边
            [code]
        
        ; 如果当前区域未放置子图
        [code]          
            
            ; 设置窗体背景笔触 / 画刷颜色
            [code]
    
            ; 填充该区域为窗体背景颜色
            [code]      
    
    ;
    ; 绘制原图及边框, 宽高缩放为原图的一半大小
    ;
    [code]
            
    ; 设置边框笔触颜色
    [code]

    ; 绘制边框
    [code]
    
    ;
    ; 绘制已用时间 / 已走步数及文字阴影效果
    ;
    [code]
    
    ; 设置窗体背景笔触 / 画刷颜色
    [code] 
    
    ; 填充该区域为窗体背景颜色, 即覆盖上一帧该区域处残留文字
    [code]
    
    ; 设置字体 / 背景模式
    [code]
    
    ; 绘制已用时间
    [code]
    
    ; 绘制已走步数
    [code]
    
    ret
DrawGame endp

;-------------------------------------------------------------------------------
; 计算鼠标所指子区的区号及该区域内子图可移向的新的子区的区号
;-------------------------------------------------------------------------------
TranMousePos proc uses ebx, posX:DWORD, posY:DWORD, pOldId:DWORD, pNewId:DWORD
        
    ; 初始化原 / 新区号为 -1
    [code]
        
    ; 计算整个游戏面板边界范围
    [code]

    ; 如果不在游戏面板边界范围内直接返回, [ 0, edgeRect.right ), [ 0, edgeRect.bottom )
    [code]
    
    ;
    ; 计算鼠标所指子区的行列号及其区号
    ;
    ;   row = ( posY - edgeRect.top ) / 40
    ;   col = ( posX - edgeRect.left ) / 40 
    ;   区号 = row * 7 + col
    ;
    [code]
    
    ;
    ; 依次判断其左上右下的子区是否为空, 如果为空则表明可移动
    ;
    [code]
    
    ; 左边
    [code]
    
    ; 上边
    [code]
    
    ; 右边
    [code]
    
    ; 下边
    [code]
    
    ; 左 / 上 / 右 / 下子区均非空, 当前子区域内子图不可移动
    [code]

    ret
TranMousePos endp

;-------------------------------------------------------------------------------
; 处理游戏鼠标移动
;-------------------------------------------------------------------------------
DealMouseMove proc posX:DWORD, posY:DWORD
  
    ;
    ; 判断鼠标所指子区内的子图是否可移动
    ; 如果该子区内子图可移动则显示手指光标, 否则显示普通光标
    ;
    [code]
     
    ret
DealMouseMove endp

;-------------------------------------------------------------------------------
; 处理游戏鼠标单击
;-------------------------------------------------------------------------------
DealMouseClick proc uses ebx, posX:DWORD, posY:DWORD   
    ;
    ; 判断鼠标所指子区内的图片块是否可移动
    ; 如果该子区内子图可移动则将子图移动到新的子区
    ;
    [code]
        
        ; 已走步数加 1
        [code]               
        
        ; 迫使游戏重绘
        [code]
        
        ; 播放子图移动声音
        [code]
        
        ;
        ; 判断是否完成
        ;
        [code]
        
        ; 如果前 17 块子图都移到了对应正确的位置, 则补上先前为腾出空位的第
        ; 18 块子图( 编号为 17 ), 同时, 设置完成标志
        [code]      
    
    ret
DealMouseClick endp

;-------------------------------------------------------------------------------
; 处理游戏计时器信号
;-------------------------------------------------------------------------------
DealTimerSignal proc timerId:DWORD  
        
    ; 已用时间加 1
    [code]
    
    ; 迫使游戏重绘
    [code]
    
    ret
DealTimerSignal endp

;-------------------------------------------------------------------------------
; 初始化游戏
;-------------------------------------------------------------------------------
InitGame proc
    
    ; 初始化游戏数据
    [code]    
    
    ; 初始游戏原图设备环境
    [code]
    
    ; 初始化颜色
    [code]

    ; 初始化计时器
    [code]
    
    ; 初始化字体    
    [code] 
    
    ; 初始化鼠标光标
    [code]    

    ret
InitGame endp

;-------------------------------------------------------------------------------
; 结束游戏
;-------------------------------------------------------------------------------
ExitGame proc

    ; 释放游戏资源  
    [code]

    ret
ExitGame endp

;-------------------------------------------------------------------------------
; 关于对话框过程
;-------------------------------------------------------------------------------
AboutDlgProc proc hWnd:HWND, msg:UINT, wParam:WPARAM, lParam:LPARAM

    [code]
    
    ret
AboutDlgProc endp

;-------------------------------------------------------------------------------
; 主窗口过程
;-------------------------------------------------------------------------------
MainWndProc proc hWnd:HWND, msg:UINT, wParam:WPARAM, lParam:LPARAM    
    ;
    ; 窗口创建时进行相关初始化
    ;
    [code]
        
    ;
    ; 菜单命令
    ;
    [code]
           
    ;
    ; 鼠标移动消息, 根据鼠标所处游戏面板子区动态改变鼠标光标
    ;
    [code]
    
    ;
    ; 鼠标单击消息, 根据鼠标所处游戏面板子区移动子图
    ;
    [code]     
    
    ;
    ; 计时器消息, 为游戏计时
    ;
    [code]
            
    ;
    ; 窗口重绘消息, 重绘一帧游戏
    ;
    [code]
                     
    ;
    ; 工具条提示消息
    ;
    [code]
             
    ;
    ; 结束游戏 / 系统默认窗口处理过程
    ;
    [code]

    ret
MainWndProc endp

;-------------------------------------------------------------------------------
; 入口代码
;-------------------------------------------------------------------------------
start:
    ;
    ; 初始化
    ;
    [code] 
    
    ;
    ; 注册窗口类
    ;
    [code]
    
    ;
    ; 在屏幕正中心创建窗口
    ;
        
    ; 根据期望的客户区大小计算所需创建的窗口大小
    ; 用以自动适应各种系统风格, 比如系统设置为 Windows Xp 或 Windows 经典风格等
    [code]
    
    ; 计算屏幕中心位置
    [code]
    
    ; 加载菜单
    [code]
    
    ; 创建窗口
    [code]
    
    ;
    ; 创建工具条 / 加载光标 / 显示更新窗口
    ;
    [code]
        
    ;
    ; 程序消息循环
    ;
    [code]
    
end start

    Have fun! ^^
    刘泽围 2007年12月30日

上传的附件 魔板1.0 Win32汇编完整源代码.zip