问题描述
我最近开始学习组装 (TASM),目前正在学习如何正确改变不同形状的位置。
.model small
.stack 100h
.data
; codes returned int 16h ah = 00h
; the arrows we control
kbArrowUp equ 4800h
kbArrowDown equ 5000h
kbArrowLeft equ 4B00h
kbArrowRight equ 4D00h
kbEsc equ 011Bh
; color codes of symbols and points in graphic mode
Red equ 4
Gray equ 7
Blue equ 1
White equ 15
Mode0D_W equ 320 ; screen width in pixels for video mode 0Dh
Mode0D_H equ 200 ; screen height in pixels for video mode 0Dh
Mode0D_C equ 16 ; number of colors for video mode 0Dh
Mode0D_A equ 0A000h ; starting address of video memory for video mode 0Dh
VideoPage db ? ;video page number
Xstart dw 100 ; coordinates of the beginning of the square
Ystart dw 70
sqColor dw 1 ; color of the rendered rectangle
sqWidth dw 40 ; rectangle width
sqHeight dw 40 ; height of the rectangle
XstartS dw 150 ;coordinates of the beginning of the square
YstartS dw 70
sqColorS dw 1 ;color of the rendered rectangle
sqWidthS dw 15 ;rectangle width
sqHeightS dw 80 ;height of the rectangle
; macro to simplify calling procedures with parameters
invoke macro CallProc,Params
IRP P,<Params>
mov ax,P
push ax
endm
call CallProc
endm
.code
main proc
mov ax,@data
mov ds,ax
; setting graphics video mode
mov ax,000Dh
int 10h
mov ah,0Fh ; clarification of video mode parameters
int 10h
mov [VideoPage],bh
invoke Bar,<[sqHeight],[sqWidth],[Ystart],[Xstart],[sqColor] >
@@GetCmd:
; waiting for any key
mov ah,00h
int 16h
;обработка команды
@@TestCmd1:
cmp ax,kbArrowUp
jne @@TestCmd2
mov dx,[Ystart]
cmp dx,0
je @@GetCmd
dec dx
mov cx,[Xstart]
jmp @@Redraw
@@TestCmd2:
cmp ax,kbArrowDown
jne @@TestCmd3
mov dx,[Ystart]
add dx,[sqWidth]
cmp dx,Mode0D_H
jae @@GetCmd
mov dx,[Ystart]
inc dx
mov cx,[Xstart]
jmp @@Redraw
@@TestCmd3:
cmp ax,kbArrowLeft
jne @@TestCmd4
mov cx,[Xstart]
cmp cx,0
je @@GetCmd
dec cx
mov dx,[Ystart]
jmp @@Redraw
@@TestCmd4:
cmp ax,kbArrowRight
jne @@TestCmd5
mov cx,[Xstart]
add cx,[sqWidth]
cmp cx,Mode0D_W
jae @@GetCmd
mov cx,[Xstart]
inc cx
mov dx,[Ystart]
jmp @@Redraw
@@TestCmd5:
cmp ax,kbEsc
jne @@TestCmd1S
jae @@GetCmds
invoke Bar,<[sqHeightS],[sqWidthS],[YstartS],[XstartS],[sqColorS] >
@@GetCmds:
;ожидание нажатия любой клавиши
mov ah,00h
int 16h
;обработка команды
@@TestCmd1S:
cmp ax,kbArrowUp
jne @@TestCmd2S
mov dx,[YstartS]
cmp dx,0
jae @@GetCmds
dec dx
mov cx,[XstartS]
jmp @@Redraw
@@TestCmd2S:
cmp ax,kbArrowDown
jne @@TestCmd3S
mov dx,[YstartS]
add dx,[sqWidthS]
cmp dx,Mode0D_H
jae @@GetCmds
mov dx,[YstartS]
inc dx
mov cx,[XstartS]
jmp @@Redraw
@@TestCmd3S:
cmp ax,kbArrowLeft
jne @@TestCmd4S
mov cx,[XstartS]
cmp cx,0
je @@GetCmds
dec cx
mov dx,[YstartS]
jmp @@Redraw
@@TestCmd4S:
cmp ax,kbArrowRight
jne @@TestCmd5S
mov cx,[XstartS]
add cx,[sqWidthS]
cmp cx,Mode0D_W
jae @@GetCmds
mov cx,[XstartS]
inc cx
mov dx,[YstartS]
jmp @@Redraw
@@TestCmd5S:
cmp ax,kbEsc
jne @@GetCmds
jmp @@StopCmdLoop
@@Redraw:
invoke Bar,0>
mov ax,[sqColor]
inc ax ;Color++
cmp ax,Mode0D_C ;if (Color>MaxColor)
sbb bx,bx ; Color=1
and ax,bx
cmp ax,1
adc ax,0
mov [sqColor],ax
mov [Xstart],cx
mov [Ystart],dx
invoke Bar,dx,cx,[sqColor]>
jmp @@GetCmd
@@RedrawS:
invoke BarS,[sqColorS]
inc ax ;Color++
cmp ax,0
mov [sqColorS],ax
mov [XstartS],cx
mov [YstartS],dx
invoke BarS,[sqColor]>
jmp @@GetCmds
@@StopCmdLoop:
;переключение в текстовый режим
mov ax,0003h
int 10h
;завершение программы
mov ax,4C00h
int 21h
main endp
;рисование полосы (залитого прямоугольника)
;на входе:
; color - цвет заливки
; x_pos,y_pos - координаты левого верхнего угла
; x_size,y_size - размеры прямоугольника
;на выходе:
; -
Bar proc color: word,x_pos:word,y_pos: word,x_size: word,y_size: word
push bp ;формирование кадра параметров
mov bp,sp
push ax ;сохранение регистров
push bx
push cx
push dx
push si
push di
mov ah,0Ch ; настройка параметров для вызова функции 0Ch
mov al,byte ptr color ;цвет точек
mov bh,0 ;номер видеостраницы
mov dx,y_pos ;строка
mov cx,x_pos ;колонка
mov di,y_size
@@Vertical:
mov cx,x_pos ;колонка
mov si,x_size ;вывести x_size точек в горизонтальной линии
@@Horizontal:
int 10h ;вывести точку
inc cx ;прирастить координату x
dec si
jnz @@Horizontal
inc dx ;переход к следующей горизонтальной линии с
dec di
jnz @@Vertical
pop di ;восстановление рагистров
pop si
pop dx
pop cx
pop bx
pop ax
pop bp
ret 10 ;удаление параметров из стека
Bar endp
BarS proc colorS: word,x_posS:word,y_posS: word,x_sizeS: word,y_sizeS: word
push bp ;формирование кадра параметров
mov bp,byte ptr colorS ;цвет точек
mov bh,y_posS ;строка
mov cx,x_posS ;колонка
mov di,y_sizeS
@@VerticalS:
mov cx,x_posS ;колонка
mov si,x_sizeS ;вывести x_size точек в горизонтальной линии
@@HorizontalS:
int 10h ;вывести точку
inc cx ;прирастить координату x
dec si
jnz @@Horizontal
inc dx ;переход к следующей горизонтальной линии с
dec di
jnz @@Vertical
pop di ;восстановление рагистров
pop si
pop dx
pop cx
pop bx
pop ax
pop bp
ret 10 ;удаление параметров из стека
BarS endp
end main
有一件事我不明白:
当我更改矩形的坐标(XstartS 和 YstartS)时,矩形的位置不会改变。
我希望矩形居中并位于正方形下方,如下所示:
你能给我解释一下:
解决方法
您的程序永远不会绘制第二个形状!
您在屏幕上看到的是第一个形状的不规则重绘,这是由于我在下面列出的一些错误造成的:
@@TestCmd2:
cmp ax,kbArrowDown
jne @@TestCmd3
mov dx,[Ystart]
add dx,[sqWidth]
这里需要添加高度 [sqHeight]
而不是宽度 [sqWidth]
。
因为对于第一个形状 width 等于 height,它毕竟是一个正方形,您不会在屏幕上看到此错误。 但是,您对宽度与高度不同的第二个形状犯了同样的错误,并且一旦最终绘制第二个形状您就会看到。
@@TestCmd5:
cmp ax,kbEsc (*)
jne @@TestCmd1S (*)
jae @@GetCmdS (*)
invoke Bar,<[sqHeightS],[sqWidthS],[YstartS],[XstartS],[sqColorS] >
@@GetCmdS:
mov ah,00h
int 16h
@@TestCmd1S:
此处从未绘制第二条!如果键不是 ESC,则跳转到 TestCmd1S,如果键是 ESC,则跳转到 GetCmdS。 invoke Bar ...
无法执行。
我已按照您的程序流程进行操作,事实证明您根本不需要在这里测试 ESC。您可以简单地删除我标记为 (*) 的 3 条指令
@@TestCmd1S:
cmp ax,kbArrowUp
jne @@TestCmd2S
mov dx,[YstartS]
cmp dx,0
jae @@GetCmdS
这里的条件跳转 jae
就像一个无条件跳转,因为上述条件对于所使用的数字始终为真!您需要此处的 je
说明。
您的程序包含 8 个 jmp @@Redraw
指令,而不是单个 jmp @@RedrawS
!
顶部需要 4 个 jmp @@Redraw
指令,底部需要 4 个 jmp @@RedrawS
指令。
invoke BarS,dx,cx,[sqColor]>
第二个形状的颜色为 [sqColorS]
。
我相信一旦上述错误得到纠正,程序就会按预期工作(移动矩形)。
[迟到]
您的程序中不需要 2 个相同的过程 Bar 和 BarS!
代替
invoke Bar,<[sqHeight],[sqWidth],[sqColor]>
invoke BarS,[sqColorS]>
您可以放心使用
invoke Bar,[sqColor]>
invoke Bar,[sqColorS]>