Assembly 移动正方形时无法将其保持为完整的正方形

Assembly 移动正方形时无法将其保持为完整的正方形,assembly,x86-16,bios,tasm,Assembly,X86 16,Bios,Tasm,我一直在试着在组装中画一个盒子,然后水平移动它 穿过屏幕。打印正方形本身的代码对我来说很有效,但当我试图让它移动时,效果并不好。如果你明白我的意思,我可以看到它在移动,但不是一个完整的正方形 我的代码:在汇编Tasm中 STA SEGMENT STACK DB 0FFFeH DUP(?) STA ENDS DATA SEGMENT ;----------- ;VARIABLES HERE xpos dw 50h ypos dw 50h color db 9h constat equ 0ffffh

我一直在试着在组装中画一个盒子,然后水平移动它 穿过屏幕。打印正方形本身的代码对我来说很有效,但当我试图让它移动时,效果并不好。如果你明白我的意思,我可以看到它在移动,但不是一个完整的正方形

我的代码:在汇编Tasm中

STA SEGMENT STACK
DB 0FFFeH DUP(?)
STA ENDS
DATA SEGMENT
;-----------
;VARIABLES HERE
xpos dw 50h
ypos dw 50h
color db 9h
constat equ 0ffffh
siNum dw ?
diNum dw ?
numOFtime dw 0h

;-------------
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STA

START :
MOV AX,DATA
MOV DS,AX
;start coding here:

mov ah, 0   ;Set display mode
mov al, 13h ;13h = 320x200, 256 colors
int  10H   ;Video BIOS Services
mov cx,50h
mov dx,50h
mov si,25H
mov di,25H

PrintSquare:
;------------------------------------------------------------------------
;cx = xpos , dx = ypos, si = x-length, di = y-length, al = color

didi:
mov color,9h
mov bp,0h
do:
add cx,si
here:
mov bh,0h
mov al,color
mov ah, 0Ch   ;write pixel at coordinate
int 10h      ;draw pixel!
dec cx
cmp cx,xpos
ja here
inc dx
inc bp
cmp bp,25h
jbe do
call drawBlackBox
inc numOFtime
inc xpos;incrising to make the sqaure moving horizontically
mov cx,xpos;cx gets the xposition
mov dx,ypos
cmp numOFtime,constat
jb didi






mov ah,004Ch  ;terminate program
int 21h
;
drawBlackBox proc
mov color,0h ;black color 
mov bp,0h
mov cx,xpos
mov dx,ypos
do1:
add cx,si
here1:
mov bh,0h
mov al,color
mov ah, 0Ch   ;write pixel at coordinate
int 10h      ;draw pixel!
dec cx
cmp cx,xpos
ja here1
inc dx
inc bp
cmp bp,25h
jbe do1
mov cx,xpos
ret

drawBlackBox endp


CODE ENDS
END START

如果说移动不好,是指边缘似乎在不同的时间移动,这是一个通常通过双缓冲解决的问题(撕裂)。该问题是由于渲染到活动(可见)曲面,因此屏幕可能会显示半修改的帧

举例说明可能会有所帮助。假设您正在尝试从左图像更改为右图像:

~   ~             ^   ^
O   O             O   O
  ^      ---->      ^
|---|             \___/
如果图像从左到右更新,并且在更新过程的中途将数据发送到屏幕,您将看到如下内容:

^   ~
O   O
  ^
\_--|
这就是所谓的撕裂

要解决这个问题,您可以在一个单独的内存块中构造下一帧(您可以使用
rep stosb
在最短的时间内构造下一帧),然后使用
rep movsb
或类似的快速方式将其传输到视频内存。这将降低你的帧速率一点,但应减轻任何撕裂你可能会看到


这里有一个例子说明了这一点。它的功能与您的类似,但使用双缓冲来解决撕裂问题,而且它的结构也稍微好一点(无论如何,在我看来),在函数执行特定任务方面:


将其插入GNU Turbo汇编程序并检查它。我运行了你的原始(撕裂)代码和这个变体,后者的动画更平滑。

你能给我们展示你的盒子是什么样子吗?我能给你展示什么吗?@Sparky,我在第一段中这样做了:“问题是因为你渲染到一个活动(可见)表面,所以屏幕可能会显示半修改的帧。”。在视频硬件上
rep movsw
一个已经构建的视频屏幕要比每次调用
int 10
2500次设置一个像素快得多。这种缓慢的方法意味着你正在将部分构建的图像渲染到屏幕上,导致所谓的撕裂。@Sparky,我已经加入了一些更基本的细节,希望能更好地解释它。
stacksg segment stack
    db 0fffeh dup(?)
stacksg ends

datasg segment
    buffer dw 32000 dup(0)
datasg ends

codesg segment
assume cs:codesg, es: datasg, ds:datasg, ss:stacksg

doline: ; ax = line, bx = column, cx = width
    push        di            ; preserve
    push        ax
    push        dx            ; imul hits this

    push        bx            ; get byte offset to di
    mov         bx, 320
    imul        bx
    pop         bx
    add         ax, bx
    mov         di, ax

    push        cx            ; blat line
    mov         al, 9    
    cld
    rep stosb
    pop         cx

    pop         dx            ; restore and return
    pop         ax
    pop         di
    ret

dosquare: ; ax = line, bx = column, cx = width, dx = height
    push        ax            ; preserve
    push        bx
    push        cx
    push        dx

    push        di            ; clear buffer to black
    push        ax
    push        cx
    xor         di, di
    xor         ax, ax
    mov         cx, 32000
    cld
    rep stosw
    pop         cx
    pop         ax
    pop         di

makeline:
    call        doline
    inc         ax
    dec         dx
    jnz         makeline

    push        es            ; blat double buffer to screen
    push        si
    push        di
    xor         si, si
    mov         ax, 0a000h
    mov         es, ax
    xor         di, di
    mov         cx, 32000
    cld
    rep movsw    
    pop         di
    pop         si
    pop         es

    pop         dx            ; restore and return
    pop         cx
    pop         bx
    pop         ax
    ret

start:
    mov         ax, datasg
    mov         ds, ax
    mov         es, ax

    mov         ah, 0         ; set display mode 13h, 320x200, 8bbp
    mov         al, 13h
    int         10h

    mov         ax, 10        ; line
    mov         bx, 10        ; start column
    mov         cx, 40        ; width
    mov         dx, 40        ; height

printSquare:
    call        dosquare      ; do the square
    inc         bx            ; move right but reset at end
    cmp         bx, 310 - 40
    jne         printSquare
    mov         bx, 10
    jmp         printSquare

codesg ends
end start