重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
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,100
add eax,140
;ecx=j*100+100,绘制的y坐标,100为起始坐标
imul ecx,j,100
add ecx,100
;edx=i*4+j,表示第[i][j]个方块
imul edx,i,4
add edx,j
;gameMat[i][j]的值转为字符数组存到Data中,dword:*4
invoke num2byte,dword ptr gameMat[edx*4]
;如果为0
;eax=i*100+140,绘制的x坐标,140为起始坐标
imul eax,i,100
add eax,140
;ecx=j*100+100,绘制的y坐标,100为起始坐标
imul ecx,j,100
add 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
.else
invoke 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,4
add 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,NULL
MOV hGame[64],eax
invoke CreateWindowEx,NULL,offset edit,offset szText2,\
WS_CHILD or WS_VISIBLE OR WS_DISABLED,100,75,400,15,\
hWnd,17,hInstance,NULL
mov hGame[68],eax
invoke CreateWindowEx,NULL,offset edit,offset szText5,\
WS_CHILD or WS_VISIBLE OR WS_DISABLED,100,90,400,15,\
hWnd,18,hInstance,NULL
mov hGame[72],eax
invoke CreateWindowEx,NULL,offset edit,offset szText3,\
WS_CHILD or WS_VISIBLE OR WS_DISABLED,100,105,400,15,\
hWnd,19,hInstance,NULL
mov hGame[76],eax
invoke CreateWindowEx,NULL,offset edit,offset szText4,\
WS_CHILD or WS_VISIBLE OR WS_DISABLED,100,120,400,15,\
hWnd,20,hInstance,NULL
mov hGame[80],eax
2.1.3 绘制位图
加载位图主要通过调用gdi32库所支持的API,其主要流程为:
具体实现代码如下:
;加载位图
;首先获取窗口DC
invoke GetDC, hWnd
mov @hDc,eax
;创建兼容窗口DC的缓存dc
invoke CreateCompatibleDC,@hDc
mov hdcIDB_BITMAP1,eax
invoke CreateCompatibleDC,@hDc
mov hdcIDB_BITMAP2,eax
;创建位图缓存
invoke CreateCompatibleBitmap, @hDc,150,80
mov hbmIDB_BITMAP1,eax
invoke CreateCompatibleBitmap, @hDc,90,60
mov hbmIDB_BITMAP2,eax
;将hbm与hdc绑定
invoke SelectObject,hdcIDB_BITMAP1,hbmIDB_BITMAP1
;载入位图到位图句柄中
invoke LoadBitmap,hInstance,BITMAP1
mov @hBm,eax
;创建以位图为图案的画刷
invoke CreatePatternBrush,@hBm
push eax
;以画刷填充缓存DC
invoke SelectObject,hdcIDB_BITMAP1,eax
;按照PATCOPY的方式
invoke PatBlt,hdcIDB_BITMAP1,0,0,150,80,PATCOPY
pop eax
;删除画刷
invoke DeleteObject,eax
;在主窗口DC上绘制位图dc
invoke 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,NULL
MOV hGame[64],eax
invoke CreateWindowEx,NULL,offset edit,offset szText2,\
WS_CHILD or WS_VISIBLE OR WS_DISABLED,100,75,400,15,\
hWnd,17,hInstance,NULL
mov hGame[68],eax
invoke CreateWindowEx,NULL,offset edit,offset szText5,\
WS_CHILD or WS_VISIBLE OR WS_DISABLED,100,90,400,15,\
hWnd,18,hInstance,NULL
mov hGame[72],eax
invoke CreateWindowEx,NULL,offset edit,offset szText3,\
WS_CHILD or WS_VISIBLE OR WS_DISABLED,100,105,400,15,\
hWnd,19,hInstance,NULL
mov hGame[76],eax
invoke CreateWindowEx,NULL,offset edit,offset szText4,\
WS_CHILD or WS_VISIBLE OR WS_DISABLED,100,120,400,15,\
hWnd,20,hInstance,NULL
mov hGame[80],eax
;绘制分数框
invoke num2byte,score
invoke CreateWindowEx,NULL,offset edit,offset Data,\
WS_CHILD or WS_VISIBLE OR WS_DISABLED,420,38,80,15,\
hWnd,21,hInstance,NULL
mov hGame[84],eax
xor eax,eax
ret
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
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧