您的位置:首页 > 其它

汇编学习记录

2009-01-13 22:43 204 查看
前段时间感觉迷茫,便开始看一直想了解的汇编,看了些8086汇编基本的规则,感觉很难学,试着写了个简单的贪吃蛇游戏,就是在显存区域显示,没有考虑任何优化,只是想让游戏动起来(用的工具是网上下载的MASMPlus 个人免费版).
现在又开始觉得迷茫了,因为感觉学的东西现在根本用不着,也感觉很难深入,于是我打算放弃继续学习汇编了,尽管现在还没入门。记下来,也算曾经试图学过。

;#Mode=DOS
data segment

SPACE EQU 0720h
BODY EQU 3501h
WALL EQU 070ah
;meg1 db "game over.....$"
meg2 db "press ENTER to continue.....$"
meg3 db "press ESC to exit.....$"

head_direction dw ? ;虫头方向,初始化为向左
all_dir dw 07c0h dup(0) ;记录虫身所有节点方向,从低位虫尾开始
headLoc dw ? ;记录all_dir中虫头偏移量
data ends
stack segment
db 128 dup(0) ;定义堆栈,128b的大小是随便设置的
stack ends

code segment
assume cs:code,ss:stack,ds:data
startGame:
mov ax,data
mov ds,ax
mov ax,stack
mov ss,ax
mov ds:[head_direction],0002h ;虫头方向,初始化为向左
mov ds:[headLoc],0002h ;虫头相对虫尾线性偏移量

mov ax,0b800h ;b800h为显存入口
mov es,ax ;设置es为指向现存区域的段,界面显示通过es:di和es:si操作
mov di,00a4h ;虫头初始化位置
mov si,00a2h ;虫尾初始化位置

mov cx,07D0h

push di
mov di,0000h
clearScr: ;清屏
mov es:[di],SPACE
inc di
inc di
loop clearScr

lea di,offset all_dir
mov ds:[di],0002h ;初始化所有节点方向
inc di
inc di
mov ds:[di],0002h
pop di

mov es:[si],BODY ;虫初始化
mov es:[di],BODY

initScreen: ;背景初始化
mov cx,0050h
push di
push si
mov ax,WALL
mov di,0000h
mov si,0f00h
init_row:
mov es:[di],ax
mov es:[si],ax
inc di
inc di
inc si
inc si
loop init_row

mov cx,0019h
mov di,0000h
mov si,009eh
init_col:
mov es:[di],ax
mov es:[si],ax
add di,00a0h
add si,00a0h
loop init_col

pop si
pop di
call createFood

s_move: ;move accroding to its direction
add di,ds:[head_direction] ;通过当前坐标+方向得到虫头移动后的坐标
mov dl,es:[di] ;取得虫头将要移动位置的信息,判断是否能继续运动
cmp dl,0ah ;设置碰到墙壁游戏结束
jz gameOver

cmp dl,01h ;碰到自己游戏结束
jz gameOver

mov es:[di],BODY ;虫头移动到新位置
cmp dl,20h ;判断新的位置是否为空格
jnz changeDir ;非空格grow,tail不变

jmp changeAllDir ;是空格,改变所有虫体方向

changeDir: ;非空格,虫头偏移量加02,all_dir增加一个节点保存虫头方向,其余不变
push di
lea di,offset all_dir
add ds:[headLoc],02h
mov ax,ds:[head_direction]
mov bx,ds:[headLoc]
mov ds:[di+bx],ax
pop di

call createFood ;随即产生食物
call delay ;移动间隔
jmp s_move

changeAllDir: ;如果是空格,更新虫体所有部分的方向
mov es:[si],SPACE ;虫尾移动到新的位置,之前的虫尾变为空
add si,ds:[all_dir] ;虫尾新位置

mov cx,ds:[headLoc] ;要将所有方向移位,计数
xor bx,bx
push di
lea di,offset all_dir ;指向尾部方向偏移量
again:
mov dx,ds:[di+bx+2h] ;
mov ds:[di+bx],dx ;换方向,前面节点的方向变为相连后面节点的方向
dec cx ;
inc bx
inc bx
loop again
pop di

push di
mov dx,ds:[headLoc]
mov ax,ds:[head_direction]
lea di,offset all_dir
add di,dx
mov ds:[di],ax
pop di
call delay
jmp s_move

key_move:
cmp dl,1bh ;如果是esc,则结束游戏
je exitgame

cmp dl," " ;如果是空格,则暂停游戏
je pausegame
goon:
cmp dl,'d'
jz move_right ;按'd'右移
cmp dl,'a'
jz move_left ;左移
cmp dl,'w'
jz move_up ;上移
cmp dl,'s'
jz move_down ;下移

jmp s_move ;否则,按照原方向移动

move_right:
cmp ds:[head_direction],-0002h ;如果想转180度,维持原来的状态
jz s_move
mov ds:[head_direction],0002h ;设置运动方向为向右
push di
lea di,offset headLoc
mov dx,ds:[di]
lea di,offset all_dir
add di,dx
mov ds:[di],0002h
pop di
jmp s_move

move_left:
cmp ds:[head_direction],0002h ;如果想转180度,维持原来的状态
jz s_move
mov ds:[head_direction],-0002h ;设置运动方向

push di ;当头部方向改变时,第二个节点的方向和头部方向相同了
lea di,offset headLoc
mov dx,ds:[di]
lea di,offset all_dir
add di,dx
mov ds:[di],-0002h
pop di
jmp s_move

move_up:
cmp ds:[head_direction],00a0h ;如果想转180度,维持原来的状态
jz s_move
mov ds:[head_direction],-00a0h ;设置运动方向

push di
lea di,offset headLoc
mov dx,ds:[di]
lea di,offset all_dir
add di,dx
mov ds:[di],-00a0h
pop di
jmp s_move

move_down:
cmp ds:[head_direction],-00a0h ;如果想转180度,维持原来的状态
jz s_move
mov ds:[head_direction],00a0h ;设置运动方向

push di
lea di,offset headLoc
mov dx,ds:[di]
lea di,offset all_dir
add di,dx
mov ds:[di],00a0h
pop di
jmp s_move

pausegame: ;暂停处理
mov ah,06h
mov dl,0ffh
int 21h
cmp al," " ;按空格恢复游戏
jne pausegame
jmp goon ;继续游戏

gameOver: ;退出游戏
mov ah,4ch
int 21h
exitgame: ;结束游戏
mov ah,4ch
int 21h

;延时程序
delay proc
mov cx,00ffh
delay1:
push cx
mov cx,03ffh
delay2:
mov ax,0600h ;相应键盘,手动控制移动
mov dl,0ffh
int 21h
mov dl,al
cmp dl,00h ;如果有键盘输入,进行响应
jnz key_move
loop delay2
pop cx
loop delay1
ret
delay endp

;生成随机数的方法,通过(random_seed*X+Y)%Z,这里只是粗略计算
;产生的随机数存放在ax中,因此调用之前如果ax有用要先压栈
Rand proc
mov ah,2ch ;取系统时间
int 21h
mov ax,dx ;表分秒存在dl中,秒在dh中
;mov ax,es:[di]
mov cx, 4 ; X = cx
mul cx ; ax = ax * X
add ax, 10 ; ax = ax + Y
mov cx, 0efeh ; cx = 上限
sub cx, 00a2h ; cx = 上限 - 下限
xor dx, dx ; dx = 0
div cx ; eax = eax mod Z (余数在edx里面)
add dx, 00a2h ; 修正产生的随机数的范围
mov ax, dx ; eax = Rand_Number
ret
Rand endp

createFood proc uses di
createFoodAgain:
call Rand
mov di,ax
cmp BYTE ptr es:[di],20h ;不是空格换个地方产生food
jne createFoodAgain ;不能用jne createFood,不然有可能产生循环调用,堆栈溢出
mov es:[di],0741h ;food用字母'A'表示
ret
createFood endp
code ends
end startGame
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: