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相关推荐

  1. 寄存器理解 及 X86汇编入门

    本文整理自多材料源,感谢原址分享,请查看末尾Url I, 汇编语言分类: 汇编语言和CPU息息相关,但是不能把汇编语言完全等同于CPU的机器指令.不同架构的CPU指令并不相同,如x86,powerpc ...

  2. 在VS2015中编写x86汇编

     参考教程: 作者:上下求索 VS2015,C嵌套汇编 & C,汇编相互调用 http://ylqhust.github.io/blog/2016/04/17/vs-clanguage-asm ...

  3. 【Android 逆向】x86 汇编 ( align | db | dw | dd | nop | 伪指令 )

    文章目录 一.align 字节对齐指令 二.db / dw / dd 指令 三.nop 指令 总结 一.align 字节对齐指令 align 字节对齐 ; 默认情况下是 161616 字节对齐 ; 该 ...

  4. x86汇编指令集大全

    一.数据传输指令 1. 通用数据传送指令 MOV 传送字或字节. MOVSX 先符号扩展,再传送. MOVZX 先零扩展,再传送. PUSH 把字压入堆栈. POP 把字弹出堆栈. PUSHA 把AX ...

  5. 汇编中各寄存器的作用(16位CPU14个,32位CPU16个)和 x86汇编指令集大全(带注释)

    From:https://www.cnblogs.com/zimmerk/articles/2520011.html From:https://blog.csdn.net/bjbz_cxy/artic ...

  6. 【汇编优化】之X86汇编优化

    入门序  本文主要讲解x86汇编的内容,涉及的东西比较多,篇幅比较有限,但部分详尽的内容给出了具体的参考网址:本文主要讲了x86_32.windows64以及Linux64下纯汇编的编写. 英文版:h ...

  7. html+css+javascript实现小游戏2048(详解,附源代码)

    html+css+javascript实现小游戏2048(详解,附源代码) 1.上下左右的移动原理相同,这里只详细说明向上移动的方法 2.这里的上下左右由wasd四个键控制 3-小方块空的意思就是没数 ...

  8. Android 带你玩转实现游戏2048 其实2048只是个普通的控件

    转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/40020137,本文出自: [张鸿洋的博客] 1.概述 博主本想踏入游戏开放行业 ...

  9. Android 带你玩转实现游戏2048 其实2048只是个普通的控件(转)

    1.概述 博主本想踏入游戏开放行业,无奈水太深,不会游泳:于是乎,只能继续开发应用,但是原生Android也能开发游戏么,2048.像素鸟.别踩什么来着:今天给大家带来一篇2048的开发篇,别怕不分上 ...

  10. X86汇编常见的寄存器

    X86汇编常见的寄存器 4个数据寄存器(EAX.EBX.ECX和EDX) 2个变址和指针寄存器(ESI和EDI) 2个指针寄存器(ESP和EBP) 6个段寄存器(ES.CS.SS.DS.FS和GS) ...

最新文章

  1. Ka的回溯编程练习 Part1|整划什么的。。
  2. sqlalchemy.exc.InternalError: (pymysql.err.InternalError) Packet sequence number wrong - got 40 expe
  3. c js html页面进度条,js实现进度条的方法
  4. 【转载】如果你身边有程序员的朋友,请善待他们
  5. C++强制类型转换操作符 dynamic_cast
  6. Java 比较两个日期的方法
  7. oracle 中的几天后,几年后
  8. mysql 以 db 结尾_MySQL的高级部分
  9. Android 百度推送使用总结
  10. Python接口自动化之接口依赖
  11. 心情舒畅,升级到u10.04了
  12. Android apk系列1-------APK签名
  13. 隐式反馈的去噪,模型取得巨大提升!
  14. Android LeakCanary的使用和原理
  15. TR069 (CWMP协议即CPE广域网管理协议)
  16. python爬取ppt课件_Python 爬虫 好大学在线PPT
  17. typora中插入化学反应式
  18. MapAbc使用体验
  19. 下载Synechococcus elongatus UTEX 2973(accession no.为GCA_000817325.1 )的基因组注释文件,统计其中染色体序列(CP006471.1)前10
  20. 一般硬盘读取速度和写入速度是多少

热门文章

  1. 已经有些跑偏的“学术会议文化”!
  2. axios和ajax怎么读,axios, ajax和fetch的比较
  3. PHP内核剖析之FPM
  4. java socket 连接异常_JAVA Socket连接服务器时可能抛出的异常
  5. C# Winform右下角弹窗方式
  6. Qt::WA_DeleteOnClose
  7. 程序员如何提高影响力
  8. 操作系统的程序内存结构 —— data和bss为什么需要分开,各自的作用
  9. 数字图像处理——大家来找茬(Python)
  10. Alpha 完结撒花 —— 事后诸葛亮