汇编学习记录

来源:互联网 发布:php curl 选项 编辑:程序博客网 时间:2024/06/05 16:05
    前段时间感觉迷茫,便开始看一直想了解的汇编,看了些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
原创粉丝点击