x86汇编游戏——2048
2.1游戏界面绘制
游戏界面绘制窗口程序主要有_WinMain和_ProcWinMain两个函数来构成。
_WinMain是生成窗口的主函数,主要流程为:
(1)得到应用程序句柄
(2)注册窗口类
(3)建立窗口
(4)显示窗口
(5)刷新窗口客户区
(6)维护消息获取和处理的循环
通过GetMessage获取消息
TranslateMessage翻译消息
DispatchMessage分派消息给回调函数处理
通过User32来调用回调函数
_ProcWinMain是用来处理消息的,是窗口的回调函数,也叫窗口过程。消息如WM_PAINT,WM_CHAR等。
2.1.1 界面构成
界面主要由4个部分3个模块构成.
4个部分分别是
(1)游戏主体部分的方块
(2)游戏说明部分
(3)显示得分部分
(4)游戏名称部分
3个模块分别是
(1)静态控件'Static'绘制游戏模块
(2)文本框'edit'绘制得分和游戏说明
(3)位图装饰界面
2.1.2 绘制静态控件
需要绘制4X4的方块,采用一个2重循环,通过i,j控制绘制的位置和绘制的控件ID
L6:;eax=i*100+140,绘制的x坐标,140为起始坐标imul eax,i,100add eax,140;ecx=j*100+100,绘制的y坐标,100为起始坐标imul ecx,j,100add ecx,100;edx=i*4+j,表示第[i][j]个方块imul edx,i,4add edx,j;gameMat[i][j]的值转为字符数组存到Data中,dword:*4invoke num2byte,dword ptr gameMat[edx*4];如果为0;eax=i*100+140,绘制的x坐标,140为起始坐标imul eax,i,100add eax,140;ecx=j*100+100,绘制的y坐标,100为起始坐标imul ecx,j,100add ecx,100.IF Data[0] =='0';创建静态控件,居中有边框invoke CreateWindowEx,NULL,offset static,offset EmptyText,\WS_CHILD or WS_VISIBLE or SS_CENTER or WS_BORDER or SS_CENTERIMAGE,ecx,eax,100,100,\ hWnd,edx,hInstance,NULL ;句柄为edx.elseinvoke CreateWindowEx,NULL,offset static,offset Data,\WS_CHILD or WS_VISIBLE or SS_CENTER or WS_BORDER or SS_CENTERIMAGE,ecx,eax,100,100,\ hWnd,edx,hInstance,NULL ;句柄为edx.endif;edx=i*4+j,表示第[i][j]个方块imul edx,i,4add edx,j;存储窗口句柄,句柄返回值在eax中mov hGame[edx*4],eax
2.1.2 绘制文本框
绘制文本框同绘制方块一样,通过调用CreateWindowEx函数,指定对应的值即可,由于文本框可以在界面上进行编辑,所以绘制时指定为禁用状态。
L7:;绘制游戏说明部分;创建文本框,但设为Disabeled防止玩家更改invoke CreateWindowEx,NULL,offset edit,offset szText1,\WS_CHILD or WS_VISIBLE OR WS_DISABLED,100,60,120,15,\hWnd,16,hInstance,NULLMOV hGame[64],eaxinvoke CreateWindowEx,NULL,offset edit,offset szText2,\WS_CHILD or WS_VISIBLE OR WS_DISABLED,100,75,400,15,\hWnd,17,hInstance,NULLmov hGame[68],eaxinvoke CreateWindowEx,NULL,offset edit,offset szText5,\WS_CHILD or WS_VISIBLE OR WS_DISABLED,100,90,400,15,\hWnd,18,hInstance,NULLmov hGame[72],eaxinvoke CreateWindowEx,NULL,offset edit,offset szText3,\WS_CHILD or WS_VISIBLE OR WS_DISABLED,100,105,400,15,\hWnd,19,hInstance,NULLmov hGame[76],eaxinvoke CreateWindowEx,NULL,offset edit,offset szText4,\WS_CHILD or WS_VISIBLE OR WS_DISABLED,100,120,400,15,\hWnd,20,hInstance,NULLmov hGame[80],eax
2.1.3 绘制位图
加载位图主要通过调用gdi32库所支持的API,其主要流程为:
具体实现代码如下:
;加载位图;首先获取窗口DCinvoke GetDC, hWndmov @hDc,eax;创建兼容窗口DC的缓存dcinvoke CreateCompatibleDC,@hDcmov hdcIDB_BITMAP1,eaxinvoke CreateCompatibleDC,@hDcmov hdcIDB_BITMAP2,eax;创建位图缓存invoke CreateCompatibleBitmap, @hDc,150,80mov hbmIDB_BITMAP1,eaxinvoke CreateCompatibleBitmap, @hDc,90,60mov hbmIDB_BITMAP2,eax;将hbm与hdc绑定invoke SelectObject,hdcIDB_BITMAP1,hbmIDB_BITMAP1;载入位图到位图句柄中invoke LoadBitmap,hInstance,BITMAP1mov @hBm,eax;创建以位图为图案的画刷invoke CreatePatternBrush,@hBmpush eax;以画刷填充缓存DCinvoke SelectObject,hdcIDB_BITMAP1,eax;按照PATCOPY的方式invoke PatBlt,hdcIDB_BITMAP1,0,0,150,80,PATCOPYpop eax;删除画刷invoke DeleteObject,eax;在主窗口DC上绘制位图dcinvoke BitBlt,@hDc,90,0,150,80,hdcIDB_BITMAP1,0,0,SRCCOPY
2.1.4 显示数字和分数
我们通过使用一个数组gameMat来保存游戏的局面,由于存储的是数字,所以需要通过不断除以10,按位转换为数字字符串来显示,之后调用SetWindowText函数显示文字。
L7:;绘制游戏说明部分;创建文本框,但设为Disabeled防止玩家更改invoke CreateWindowEx,NULL,offset edit,offset szText1,\WS_CHILD or WS_VISIBLE OR WS_DISABLED,100,60,120,15,\hWnd,16,hInstance,NULLMOV hGame[64],eaxinvoke CreateWindowEx,NULL,offset edit,offset szText2,\WS_CHILD or WS_VISIBLE OR WS_DISABLED,100,75,400,15,\hWnd,17,hInstance,NULLmov hGame[68],eaxinvoke CreateWindowEx,NULL,offset edit,offset szText5,\WS_CHILD or WS_VISIBLE OR WS_DISABLED,100,90,400,15,\hWnd,18,hInstance,NULLmov hGame[72],eaxinvoke CreateWindowEx,NULL,offset edit,offset szText3,\WS_CHILD or WS_VISIBLE OR WS_DISABLED,100,105,400,15,\hWnd,19,hInstance,NULLmov hGame[76],eaxinvoke CreateWindowEx,NULL,offset edit,offset szText4,\WS_CHILD or WS_VISIBLE OR WS_DISABLED,100,120,400,15,\hWnd,20,hInstance,NULLmov hGame[80],eax;绘制分数框invoke num2byte,scoreinvoke CreateWindowEx,NULL,offset edit,offset Data,\WS_CHILD or WS_VISIBLE OR WS_DISABLED,420,38,80,15,\ hWnd,21,hInstance,NULLmov hGame[84],eaxxor eax,eaxret
2.1.5 显示游戏胜利和失败消息
通过维护gameIsEnd,gameIsWin和gameContinue三个变量。
游戏失败时,gameIsEnd置1,弹出游戏失败提示消息,点击OK重新开始游戏。
游戏胜利时,gameIsWin置1,弹出游戏胜利提示消息,玩家可选择继续游戏或结束游戏。
若游戏继续,gameContinue置1,则之后不再对游戏是否胜利进行判断。
2.2生成新模块
2.3方块移动及合并
方块的移动分为四个方向,所以首先设想为该模块编写四个函数,分别实现上下左右的移动的实现。通过沟通,我们将输入字符WASD分别代表向上、向左、向下、向右移动。
2.3.1移动方向以及起点
上图的四个函数的实现过程,直观上讲有如下效果:
通过对16个方块按行或按列进行划分,然后我们对每个方向的行或列进行遍历,之后通过遍历过程中某方块和他周围方块的关系进行比较,如此实现整个遍历过程。例如我们对向右的移动进行分析,我们就会把所有方块按行分组,对每一行的每一个方块进行遍历。
完成分治后,我们还要对遍历起点进行分析。在实现过程中,我采用了Loop的方式进行循环,所以我们的循环起点始终为4,之后不断递减形成循环。此时我们对不同方向的移动起点进行分析,可知我们的起点如图所示:
2.3.2合并实现
确定了循环起点后,我们还要对具体的方块移动方向进行确定。此处我们仍对D方向(向右移动)进行分析。在游戏过程中,我们发现,每个方块都会和其左边的方块进行比较,若某方块的左边出现相同数字或者该相同数字和数字0一同出现,则会进行合并。如此,我们就确定了每个循环中行或列的遍历方向是与移动方向相反的,如此才能更快更好的实现该功能。在确定了循环内遍历方向后,我们自然会向确定移动方向一样,对每个行或列的所有方块抽象为一个状态,并对每个状态进行遍历判断。事实上,在开发过程中我发现整个过程可以抽象为一个递归的判断过程,这样实现就更加简单。其具体实现思想如下:
我们不再对每个方向上的四个方块分别抽象,而是对其状态进行抽象:
1)是否为0
如果我们遍历到该数字为0的话,我们直接跳过,因为我们不需要对0进行任何操作;
2)左右是否为0
如果是在移动过程,在其移动方向上若存在0(存在0就说明有空方块,有位置支持移动),我们就对该方块进行移动,即0和非零数字的交换,然后继续进行判断,若到达边界或没有空方块则无法进行移动,我们对其进行合并功能的判断。
3)忽略0后是否有相同数字
我们知道在合并过程中,我们会对移动过程的反方向进行判断,当然判断过程中,我们仍需要对是否有0(即是否有空方方块)进行判断,若有则直接跳过,继续遍历;若遇到相同数字,直接合并,并将遍历到的数字置为0,若没有或者遍历越界,则对循环中的下一个方块进行如上方式的判断,如此就能完成每一行或列的移动和合并。
3.完整代码X86-2048: x86汇编语言编写的2048游戏 (gitee.com)https://gitee.com/chris-william/x86-2048
x86汇编游戏——2048相关推荐
- 寄存器理解 及 X86汇编入门
本文整理自多材料源,感谢原址分享,请查看末尾Url I, 汇编语言分类: 汇编语言和CPU息息相关,但是不能把汇编语言完全等同于CPU的机器指令.不同架构的CPU指令并不相同,如x86,powerpc ...
- 在VS2015中编写x86汇编
参考教程: 作者:上下求索 VS2015,C嵌套汇编 & C,汇编相互调用 http://ylqhust.github.io/blog/2016/04/17/vs-clanguage-asm ...
- 【Android 逆向】x86 汇编 ( align | db | dw | dd | nop | 伪指令 )
文章目录 一.align 字节对齐指令 二.db / dw / dd 指令 三.nop 指令 总结 一.align 字节对齐指令 align 字节对齐 ; 默认情况下是 161616 字节对齐 ; 该 ...
- x86汇编指令集大全
一.数据传输指令 1. 通用数据传送指令 MOV 传送字或字节. MOVSX 先符号扩展,再传送. MOVZX 先零扩展,再传送. PUSH 把字压入堆栈. POP 把字弹出堆栈. PUSHA 把AX ...
- 汇编中各寄存器的作用(16位CPU14个,32位CPU16个)和 x86汇编指令集大全(带注释)
From:https://www.cnblogs.com/zimmerk/articles/2520011.html From:https://blog.csdn.net/bjbz_cxy/artic ...
- 【汇编优化】之X86汇编优化
入门序 本文主要讲解x86汇编的内容,涉及的东西比较多,篇幅比较有限,但部分详尽的内容给出了具体的参考网址:本文主要讲了x86_32.windows64以及Linux64下纯汇编的编写. 英文版:h ...
- html+css+javascript实现小游戏2048(详解,附源代码)
html+css+javascript实现小游戏2048(详解,附源代码) 1.上下左右的移动原理相同,这里只详细说明向上移动的方法 2.这里的上下左右由wasd四个键控制 3-小方块空的意思就是没数 ...
- Android 带你玩转实现游戏2048 其实2048只是个普通的控件
转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/40020137,本文出自: [张鸿洋的博客] 1.概述 博主本想踏入游戏开放行业 ...
- Android 带你玩转实现游戏2048 其实2048只是个普通的控件(转)
1.概述 博主本想踏入游戏开放行业,无奈水太深,不会游泳:于是乎,只能继续开发应用,但是原生Android也能开发游戏么,2048.像素鸟.别踩什么来着:今天给大家带来一篇2048的开发篇,别怕不分上 ...
- X86汇编常见的寄存器
X86汇编常见的寄存器 4个数据寄存器(EAX.EBX.ECX和EDX) 2个变址和指针寄存器(ESI和EDI) 2个指针寄存器(ESP和EBP) 6个段寄存器(ES.CS.SS.DS.FS和GS) ...
最新文章
- Ka的回溯编程练习 Part1|整划什么的。。
- sqlalchemy.exc.InternalError: (pymysql.err.InternalError) Packet sequence number wrong - got 40 expe
- c js html页面进度条,js实现进度条的方法
- 【转载】如果你身边有程序员的朋友,请善待他们
- C++强制类型转换操作符 dynamic_cast
- Java 比较两个日期的方法
- oracle 中的几天后,几年后
- mysql 以 db 结尾_MySQL的高级部分
- Android 百度推送使用总结
- Python接口自动化之接口依赖
- 心情舒畅,升级到u10.04了
- Android apk系列1-------APK签名
- 隐式反馈的去噪,模型取得巨大提升!
- Android LeakCanary的使用和原理
- TR069 (CWMP协议即CPE广域网管理协议)
- python爬取ppt课件_Python 爬虫 好大学在线PPT
- typora中插入化学反应式
- MapAbc使用体验
- 下载Synechococcus elongatus UTEX 2973(accession no.为GCA_000817325.1 )的基因组注释文件,统计其中染色体序列(CP006471.1)前10
- 一般硬盘读取速度和写入速度是多少