用汇编语言完成蛇游戏的难度

问题描述

我能够使用汇编语言和使用星星创建一个游戏,当它撞到墙上时会像蛇游戏一样结束,但我想添加另一件事,当星星撞到自己时游戏结束。我有一个解决问题的部分,我想让你帮忙。

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,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,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,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

picture from run in emu8086

解决方法

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

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

printchar macro n
  mov cx,1
  mov bh,0
  mov al,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。我建议你一直使用键盘 BIOS 功能。


[编辑]
您已完成代码并进行了更正和更多改进。
请注意,我增加了堆栈的大小。 64 字节有点小,很容易让您遇到某些 BIOS 和/或 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,0Ah     ; BIOS.WriteCharacter
  int 10h
endm
    
printstring macro n
  lea dx,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,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