难以用汇编语言完成贪吃蛇游戏

Difficulty completing the snake game with assembly language

我能够用汇编语言创建一个游戏并使用星星,它像蛇游戏一样在撞墙时结束,但我想添加另一件事,当星星撞到时游戏结束本身。我有一个解决问题的部分,我希望你能帮忙。

gotoxy macro x,y
     mov dl,x
     mov dh,y
     mov bh,0
     mov ah,2
     int 10h
endm 

printchar macro n
     mov dl,n
     mov ah,2
     int 21h
endm 

printstring macro n
     lea dx,n
     mov ah,9
     int 21h
endm

.model small
.stack 64
.data
    x db 40
    y db 12
    deltax db 0
    deltay db -1 
    msg1 DB "GAME OVER !!!$"
.code
main:            
     mov ax,@data
     mov ds,ax
     gotoxy x,y     
     printchar '*'

     mov ah,7
     int 21h
l1:  
     gotoxy x,y
     mov al,x
     add al,deltax
     mov x,al       
     mov al,y
     add al,deltay
     mov y,al       
     
     gotoxy x,y     
     printchar '*'

     mov ah,0bh     
     int 21h
     cmp al,0     
     je l2          
     mov ah,0
     int 16h        
     cmp al,'w'     
     je L_W
     cmp al,'s'
     je L_S
     cmp al,'a' 
     je L_A
     cmp al,'d'     
     je l_D 
     jmp l2
L_W:                
     mov deltax,0
     mov deltay,-1
     jmp L2
L_S:
     mov deltax,0
     mov deltay,1
     jmp L2
L_A:
     mov deltax,-1
     mov deltay,0
     jmp L2
L_D:
     mov deltax,1
     mov deltay,0
     
L2:     
     cmp y,0      
     je LEND
     cmp y,23
     je LEND
     cmp x,0
     je LEND
     cmp x,79
     je LEND
     jmp l1

LEND:    
     gotoxy 35,12      
     printstring msg1
     mov ah,7
     int 21h
     
     mov ah,4ch
     int 21h
end main

printchar macro n
  mov dl,n
  mov ah,2
  int 21h
endm

您的 printchar 宏使用 DOS.PrintChar 函数 02h。对于贪吃蛇游戏而言,此 DOS 函数还发出回车 return / 换行没有用,有时可能有害。您应该改用 BIOS.WriteCharacter 函数 0Ah。

printchar macro n
  mov cx, 1
  mov bh, 0
  mov al, n
  mov ah, 0Ah  ; BIOS.WriteCharacter
  int 10h
endm

与星星相撞

要检测碰撞,只需使用 BIOS.ReadCharacterAndAttribute 函数 08h 从视频内存中读取数据即可。您可以在转到下一个位置 (gotoxy) 和显示另一颗星 (printchar) 之间执行此操作。

gotoxy x,y

mov bh, 0
mov ah, 08h   ; BIOS.ReadCharacterAndAttribute
int 10h       ; -> AX
cmp ax, 0720h ; Is this position unoccupied? (0720h means a WhiteOnBlack space character)
jne LEND      ; No

printchar '*'

闯入边境

如果要绘制矩形 (0,0) - (79,23),则不必验证超出标签 L2 处的坐标,因为上述碰撞检测也会处理的。

接下来是绘制白色矩形的快速解决方案:

mov dx, 174Fh  ; (79,23)
xor cx, cx     ; (0,0)
mov bh, 77h    ; WhiteOnWhite
mov ax, 0600h  ; BIOS.ClearWindow
int 10h
mov dx, 164Eh  ; (78,22)
mov cx, 0101h  ; (1,1)
mov bh, 07h    ; WhiteOnBlack
mov ax, 0600h  ; BIOS.ClearWindow
int 10h

最后一个提示

在从用户那里检索密钥时保持一致。您的程序混合了 DOS 功能 07h 和键盘 BIOS 功能 00h。我建议你一直使用Keyboard BIOS功能。


[编辑]
您完成的代码,其中包含更正和更多改进。
请注意,我已经增加了堆栈的大小。 64 字节有点小,很容易让您在使用某些 BIOS and/or DOS 系统调用时遇到麻烦。

gotoxy macro x, y
  mov dl, x
  mov dh, y
  mov bh, 0
  mov ah, 02h     ; BIOS.SetCursor
  int 10h
endm 
    
printchar macro n
  mov cx, 1
  mov bh, 0
  mov al, n
  mov ah, 0Ah     ; BIOS.WriteCharacter
  int 10h
endm
    
printstring macro n
  lea dx, n
  mov ah, 09h     ; DOS.PrintString
  int 21h
endm
    
.model small
.stack 512
.data
  x     db 40
  y     db 12
  delta dw 0FF00h ; deltax = 0  deltay = -1 
  msg1  db "GAME OVER !!!$"
.code
main:            
  mov ax, @data
  mov ds, ax

  mov dx, 174Fh   ; (79,23)
  xor cx, cx      ; (0,0)
  mov bh, 77h     ; WhiteOnWhite
  mov ax, 0600h   ; BIOS.ClearWindow
  int 10h
  mov dx, 164Eh   ; (78,22)
  mov cx, 0101h   ; (1,1)
  mov bh, 07h     ; WhiteOnBlack
  mov ax, 0600h   ; BIOS.ClearWindow
  int 10h

  gotoxy x, y
  printchar '*'
    
  mov ah, 00h     ; BIOS.GetKey
  int 16h         ; -> AX

Again:  
  mov ax, delta
  add x, al
  add y, ah
  gotoxy x, y

  mov bh, 0
  mov ah, 08h     ; BIOS.ReadCharacterAndAttribute
  int 10h         ; -> AX
  cmp ax, 0720h   ; Is this position unoccupied?
  jne Done        ; No

  printchar '*'
    
  mov ah, 01h     ; BIOS.TestKey
  int 16h         ; -> AX ZF
  jz  Again       ; No key available
  mov ah, 00h     ; BIOS.GetKey
  int 16h         ; -> AX
  mov bx, 0FF00h  ; deltax = 0  deltay = -1
  cmp al, 'w'     ; Up
  je  SetDelta
  mov bx, 0100h   ; deltax = 0  deltay = 1
  cmp al, 's'     ; Down
  je  SetDelta
  mov bx, 00FFh   ; deltax = -1  deltay = 0
  cmp al, 'a'     ; Left
  je  SetDelta
  mov bx, 0001h   ; deltax = 1  deltay = 0
  cmp al, 'd'     ; Right
  jne Again
SetDelta:
  mov delta, bx
  jmp Again
    
Done:    
  gotoxy 35, 12
  printstring msg1
  mov ah, 00h     ; BIOS.GetKey
  int 16h         ; -> AX
  mov ax ,4C00h   ; DOS.Terminate
  int 21h
end main