魔板 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日
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)