8086汇编初学之实现贪吃蛇游戏

前言

一直没想过要去学习汇编,觉得需要用汇编的场合无非三种:

  1. 与硬件结合很紧密高级语言做不到
  2. 时空效率要求甚高算法层面已不能优化到
  3. 逆向破解等只能用某些途径看其汇编指令

其余情况下,用汇编无异于有炮不用偏用鸟枪。
本来准备等自己需求以上场合时再去学,但因为学校举办的汇编比赛,计算机学院都要参加,也算是一个由头,于是开始了我的第一个汇编程序。

运行效果

代码只有400行,功能很简略,实现了最基本的游戏流程,看运行效果

如何实现

本质上用汇编去写一个贪吃蛇和用其他语言去实现没什么区别,不过是换一种方式表达,当然,是一种更加麻烦的方式。
以前用C++实现过 贪吃蛇俄罗斯方块。所以对于这类小游戏,该怎么切是知道了,剩下的事就是找刀了。

要实现这类简易的小游戏,需要二点:

  1. 定时器
  2. 非阻塞接收按键

有上面两者便可以搞定一切。
但在汇编下,为这两点,耽搁了不少时间。不对,是三点,还有生成随机数(原本很容易的事都变得麻烦了起来)。

定时器

事实上,查了很多资料,但还是不知道怎样去实现定时器,所以这个需求只能变通的解决。
用空循环来控制时间。

非阻塞接受按键

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
getInput:
mov al, 0
mov ah, 1
int 16h;查看键盘缓冲区是否有数据
cmp ah, 1;ah为0表示有,否则没有
je getInputEnd

mov al, 0
mov ah, 0
int 16h;从缓冲区读取数据

;此时值已经在ax里了,做你想做的

getInputEnd:
ret

随机数

1
2
3
4
5
6
7
8
9
10
11
12
13
mov ax, 0h;间隔定时器
out 43h, al;通过端口43h
in al, 40h;
in al, 40h;
in al, 40h;访问3次,保证随机性

;如果对范围并不需要精确,可以直接与运算来获得,
;否则,用div取余
mov bl, 18
div bl

mov al, ah
mov ah, 0;此时ax的值就是0~18的

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
assume cs:code,ds:data,ss:stack

data segment
sfood dw 0
sdct dw 0
sbody dw 400 dup(0)
data ends

stack segment
dw 20 dup(0)
stack ends

code segment

start:
mov ax, data
mov ds, ax

mov ax, stack
mov ss, ax
mov sp, 20

mov ax, 0b800h
mov es, ax

mov si, 4 ;保存数据段偏移量

mov cx, 4;初始蛇长度
mov ax, 0A04h

s:;初始化蛇
mov ds:[si], ax
add si, 2
inc al
loop s

mov ax, 4d00h;向右
mov ds:[2], ax;初始化方向

call clearBg;清屏
call outBg;输出地图边框
call outBody;输出蛇
call creatFood;输出食物

mov cx, 30
Game:
push cx

call updateBody

mov cx, 0Fh
aaaa1:
push cx
mov cx, 0FFFh
bbbb:
push cx
call getInput
pop cx
loop bbbb
pop cx
loop aaaa1

;jmp GameEnd

jmp Game


GameEnd: ;退出
;call outBody
mov ax, 4c00h
int 21h


updateBody:

mov ax, ds:[2]
mov di, si
sub di, 2
cmp ax, 4800h
je shang

mov ax, ds:[2]
cmp ax, 5000h
je xia

mov ax, ds:[2]
cmp ax, 4b00h
je zuo

mov ax, ds:[2]
cmp ax, 4d00h
je you

shang:
mov ax, ds:[di]
sub ah, 1
jmp checkBody

xia:
mov ax, ds:[di]
add ah, 1
jmp checkBody
zuo:
mov ax, ds:[di]
sub al, 1
jmp checkBody

you:
mov ax, ds:[di]
add al, 1
;mov ds:[di], ax
jmp checkBody

checkBody:
push ax

;判断蛇头是否碰到地图边界
cmp ah, 0
je GameEnd
cmp ah, 20
je GameEnd
cmp al, 0
je GameEnd
cmp al, 20
je GameEnd

;判断蛇头是否碰到蛇身
mov cx, si
sub cx, 6
mov di, 4

s0:
mov bx, ds:[di]
cmp bx, ax
je GameEnd

add di, 2
sub cx, 1
loop s0

pop ax

;判断蛇头是否吃到食物
mov bx, ds:[0]
cmp ax, bx
je addBody

jmp updateStart

updateStart:
mov cx, si
sub cx, 6
mov di, 4

push ax

mov dl, ' ';字符
mov dh, 0;颜色
mov bx, ds:[di]
call outStr

s5:
mov dx, ds:[di+2]
mov ds:[di], dx

add di, 2
sub cx, 1
loop s5

mov dl, ' ';字符
mov dh, 71h;颜色
mov bx, ds:[di]
call outStr

pop ax
mov ds:[di], ax

mov dl, ' ';字符
mov dh, 44h;颜色
mov bx, ds:[di]
call outStr


updateEnd:
ret

addBody:
mov dl, ' ';字符
mov dh, 71h;颜色
mov bx, ds:[di]
call outStr

mov ax, ds:[0]
mov ds:[si], ax

mov dl, ' ';字符
mov dh, 44h;颜色
mov bx, ds:[si]
call outStr

add si, 2

call creatFood

jmp updateEnd

getInput:;获取键盘输入

mov al, 0
mov ah, 1
int 16h;接收键盘
cmp ah, 1
je getInputEnd

mov al, 0
mov ah, 0
int 16h;
mov cx, ax;键盘值在ax
;判断输入
cmp cx, 4800h
je gshang

cmp cx, 5000h
je gxia

cmp cx, 4b00h
je gzuo

cmp cx, 4d00h
je gyou

jmp getInputEnd

gshang:
mov ax, ds:[2]
cmp ax, 5000h
je getInputEnd
jmp fx

gxia:
mov ax, ds:[2]
cmp ax, 4800h
je getInputEnd
jmp fx

gzuo:
mov ax, ds:[2]
cmp ax, 4d00h
je getInputEnd
jmp fx

gyou:
mov ax, ds:[2]
cmp ax, 4b00h
je getInputEnd
jmp fx

fx:;更改方向标志

mov ds:[2], cx

getInputEnd:
ret;结束



outBody:
mov cx, si
sub cx, 6
mov di, 4
s1:
mov ax, ds:[di]

mov dl, ' ';字符
mov dh, 71h;颜色

mov bl, al;列
mov bh, ah;行
call outStr

add di, 2
sub cx, 1
loop s1
mov dl, ' '
mov dh, 44h
mov ax, ds:[di]
mov bl, al
mov bh, ah
call outStr
ret

outBg:
mov dl, ' ';字符
mov dh, 71h;颜色

mov bl, 0;列
mov bh, 0;行

mov cx, 20
row:
push cx

push bx
call outStr;上边界
pop bx

push bx
add bh, 20
call outStr;下边界
pop bx

inc bl;列加1

pop cx

loop row

mov bl, 0;
mov bh, 0;
mov cx, 21
col:
push cx

push bx
call outStr;左边界
pop bx

push bx
add bl, 20
call outStr;右边界
pop bx

inc bh;行加1

pop cx

loop col
ret

outStr: ;在指定位置输出字符

mov al, 80
mul bh;行乘以80
mov bh, 0

add bl, bl;

add ax, bx;加上列即为偏移量

push si
mov si, ax
add si, si

mov es:[si], dl
mov es:[si+1], dh

mov es:[si+2], dl
mov es:[si+3], dh

pop si
ret

creatFood:;生成食物

call getFoodPosition

mov dl, ' '
mov dh, 071h
mov bx, ds:[0]

call outStr

ret


getFoodPosition:;获取食物位置
f1:
call getRand
mov ds:[0], al
call getRand
mov ds:[1], al

mov cx, si
sub cx, 4
mov di, 4
s11:
mov ax, ds:[di]

cmp ax, ds:[0]
je f1

add di, 2
sub cx, 1
loop s11

ret

getRand:;获取随机数 范围1~19

mov ax, 0h;间隔定时器
out 43h, al;通过端口43h
in al, 40h;
in al, 40h;
in al, 40h;访问3次,保证随机性

mov bl, 18
div bl

mov al, ah
mov ah, 0

inc al

ret

clearBg: ;清屏
mov ax, 3h
int 10h
ret


code ends

end start
如果本文对你有用,可以请作者喝杯茶~
0%