【问题标题】:Difficulty completing the snake game with assembly language用汇编语言完成贪吃蛇游戏的难度
【发布时间】:2021-01-08 08:40:49
【问题描述】:

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

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

【问题讨论】:

  • 您可以使用自己的数组跟踪游戏状态,或者在写入角色之前读取视频内存以查看该点是否已绘制。 (例如 xchg 而不是 mov store,使用直接 VGA 文本访问而不是 DOS 或 BIOS 字符输出函数)
  • 我想在我编写的相同代码中进行一些更改,以将我想要的项目添加到输出中
  • 是的,很明显。但是您需要一个全新的数据结构,或者对 I/O 进行更改,但仍然保留(并构建)在哪里绘制什么的逻辑。实际上可能有一个 BIOS 功能来查询当前屏幕位置的字符;如果是这样,您可以使用它。
  • 你能帮我更多吗?
  • 我认为这是家庭作业,所以我绝对不会为您编写它(尽管可能没有人会这样做;功能缺失太大)。如果您对如何做某事有具体问题,请提出问题,但 Stack Overflow 不是辅导服务,而且 cmets 不适合来回辅导课程。 Beginner's snake game using PyGame(在 Python 中)是您可以用来跟踪蛇状态的数据结构的一个示例,但请参阅答案以了解更简单的方法。

标签: assembly dos x86-16 emu8086


【解决方案1】:
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, 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。我建议你一直使用键盘 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, 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

【讨论】:

  • @AkbarNasiri 第一个 sn-p 是一个简单的替换,第二个 sn-p 是我告诉它去的插入,第三个 sn-p 紧跟在 mov ax,@data mov ds,ax 之后.
  • @AkbarNasiri 请注意,我已在此论坛上回答了您的 3 个问题。您还没有点击任何接受按钮。如果答案对您有帮助,您应该这样做,因为它会激励我继续回答...请参阅 here 为什么这对我们俩都很重要。
  • @AkbarNasiri 我已经用您的程序的改进版本更新了答案。我希望它是第一手的。
  • @AkbarNasiri 当然,您已经在使用数组了!视频内存实际上是您的程序当前写入(BIOS 函数 0Ah)和读取(BIOS 函数 08h)的二维数组(也称为矩阵)。一些程序员更喜欢将屏幕矩阵镜像到读取速度更快的常规 RAM 中。
  • @AkbarNasiri 另一种形式的数组是记录蛇所有段的 X、Y 坐标,因此可以在尾部删除一个段,同时在尾部添加一个新段。头。请参阅 Peter Cordes 的 this answer
猜你喜欢
  • 1970-01-01
  • 2019-06-15
  • 1970-01-01
  • 1970-01-01
  • 2016-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多