我是一名计算机科学学生,我需要为我的建筑课构建一个项目。我尝试在 asm 中构建一个简单的拖放程序。整个想法是在屏幕上的某处绘制一个正方形,然后使用鼠标将其拖动到其他位置,就像在常规桌面上一样。
我尝试过使用缓冲区,但没有效果。我太初学者了,无法让它发挥作用。所以我尝试了一些函数来重画正方形。这是我使用 Copilot 得到的最好结果:
.model small
.stack 100h
.data
x dw 100 ; Initial x position of square
y dw 100 ; Initial y position of square
size_square dw 50 ; Size of the square
isDragging db 0 ; Flag to check if the square is being dragged
prev_x dw 100 ; Previous x position of square
prev_y dw 100 ; Previous y position of square
.code
start:
; Initialize graphics mode
mov ax, 13h
int 10h
; Initialize mouse
mov ax, 0
int 33h
mov ax, 1
int 33h
; Hide mouse cursor
mov ax, 2
int 33h
; Draw initial square
call draw_square
main_loop:
; Show mouse cursor
mov ax, 1
int 33h
; Get mouse status
mov ax, 3
int 33h
; Check if left button is pressed
test bx, 1
jz no_drag
; Start dragging
mov isDragging, 1
mov prev_x, cx
mov prev_y, dx
dragging:
; Hide mouse cursor while dragging
mov ax, 2
int 33h
; Get mouse status
mov ax, 3
int 33h
; Check if button is still pressed
test bx, 1
jz stop_drag
; Clear previous square position
call clear_square
; Update square position
mov x, cx
mov y, dx
; Draw square at new position
call draw_square
; Store current position as previous position
mov prev_x, x
mov prev_y, y
jmp dragging
no_drag:
; If not dragging, wait for next mouse event
jmp main_loop
stop_drag:
; Stop dragging
mov isDragging, 0
; Show mouse cursor
mov ax, 1
int 33h
jmp main_loop
draw_square:
; Draw the square
push si
push di
push cx
push bx
push dx
mov cx, 0
draw_loop1:
mov dx, 0
draw_loop2:
mov ax, y
add ax, cx
mov si, ax
mov ax, x
add ax, dx
mov di, ax
mov al, 15
mov ah, 0Ch
int 10h
inc dx
cmp dx, size_square
jl draw_loop2
inc cx
cmp cx, size_square
jl draw_loop1
pop dx
pop bx
pop cx
pop di
pop si
ret
clear_square:
; Clear the previous square position
push si
push di
push cx
push bx
push dx
mov cx, 0
clear_loop1:
mov dx, 0
clear_loop2:
mov ax, prev_y
add ax, cx
mov si, ax
mov ax, prev_x
add ax, dx
mov di, ax
mov al, 0
mov ah, 0Ch
int 10h
inc dx
cmp dx, size_square
jl clear_loop2
inc cx
cmp cx, size_square
jl clear_loop1
pop dx
pop bx
pop cx
pop di
pop si
ret
exit_program:
; Restore text mode
mov ax, 3
int 10h
ret
end start
请帮助我了解出了什么问题;(
请帮助我了解出了什么问题;(
这个程序中很多地方都是错误的! AI 甚至无法使用 BIOS.WritePixel 在 (x,y) 处绘制实心正方形。 (屏幕左上角可能会显示一个实心白色方块)。为什么需要不同的代码来擦除正方形我无法理解。相同的过程,其他参数集。
push bx
pop bx
BX 没有初始化为任何内容,那么为什么要浪费字节来保留 BX。
mov ax, y
add ax, cx
mov si, ax
BIOS.WritePixel 期望其 Y 坐标位于 DX 寄存器中,因此非常不是 SI。
mov ax, x
add ax, dx
mov di, ax
BIOS.WritePixel 期望其 X 坐标位于 CX 寄存器中,因此非常不是 DI。我的版本:
mov cx, x
mov dx, y
mov al, 15 ; To 'clear' the square, you pass AL=0
call PaintSquare
...
; IN (al,cx,dx)
PaintSquare:
push bx ; AL is Color=[0,255]
push si ; CX is X=[0,319]
push di ; DX is Y=[0,199]
mov bh, 0 ; DisplayPage
mov di, size_square ; Height
.OuterLoop:
mov si, size_square ; Width
.InnerLoop:
mov ah, 0Ch ; BIOS.WritePixel
int 10h
inc cx ; X++
dec si
jnz .InnerLoop
sub cx, size_square
inc dx ; Y++
dec di
jnz .OuterLoop
sub dx, size_square
pop di
pop si
pop bx
ret
prev_x dw 100 ; Previous x position of square
prev_y dw 100 ; Previous y position of square
AI 正在加载 prev_x 和 prev_y 以及记录鼠标点击的坐标。这与需要擦除方块的位置无关!
此外,在开始任何拖动之前,您仍然需要检查鼠标是否确实位于当前方块的顶部。
exit_program:
; Restore text mode
mov ax, 3
int 10h
ret
虽然 AI 包含了这个漂亮的“exit_program”部分,但该代码是无法访问的,如果跳转,它的 ret
只能返回到 DOS,因为这是一个 .COM 可执行文件。遗憾的是,
.model small
表示这将是一个 .EXE 可执行文件,另外未设置 DS 段寄存器,因此寻址基于内存的变量将完全失败。这样的例子还在继续......
我的建议是你现在忘记使用鼠标,在我的PaintSquare程序的帮助下,你可以尝试使用基于箭头键移动方块的程序版本在键盘上。为了实现无闪烁图形,您可以使用双缓冲区,如您在评论之一中描述的。祝你好运。