[英]Extra segment won't register color data in assembly
我正在编写类似于汇编中的突破的游戏(工具:DosBOX,notepad ++,tasm),并且在“图形”模式下创建边框和平台时,偶然发现了两个问题:
这是我当前的代码,创建边框,平台和平台移动涉及的主要过程是BorderPaint
, PlatBuild
和PlatMove
IDEAL
MODEL small
STACK 100h
DATASEG
platLoc dw 63806
speed1 dw 10
speed2 dw 0FFFFh
CODESEG
;procedure to paint borders-6 px white pixels
proc BorderPaint
push ax
push bx
push di
push cx
mov ax,0A000h ;accesses graphics mode video memory
mov es,ax
xor di,di
;first line-left vertical
;sets color white
mov ax,0Fh
mov cx,200 ;enters nested loop
FirstLoop1:
push cx
mov cx,6
SecondLoop1:
mov [es:di],ax
inc di
loop SecondLoop1
sub di,6
add di,320
pop cx
loop FirstLoop1
;second line- up horizontal
mov di,7
mov cx,313
FirstLoop2:
push cx
mov cx,6
SecondLoop2:
mov [es:di],ax
add di,320
loop SecondLoop2
sub di,1920
inc di
pop cx
loop FirstLoop2
mov di,314
mov cx,200
FirstLoop3:
push cx
mov cx,6
SecondLoop3:
mov [es:di],ax
inc di
loop SecondLoop3
sub di,6
add di,320
pop cx
loop FirstLoop3
; xor di,di
; mov ax,0Fh
; mov cx,200
; FirstLoop4:
; push cx
; mov cx,6
; SecondLoop4:
; mov [es:di],ax
; inc di
; loop SecondLoop4
; sub di,6
; add di,320
; pop cx
; loop FirstLoop4
pop cx
pop di
pop bx
pop ax
ret
endp BorderPaint
proc PlatBuild
push di
push cx
push ax
mov di,[platLoc]
mov ax,5
mov cx,40
LoopPaint2:
push cx
mov cx,10
LoopPaint1:
mov [es:di],ax
sub di,320
loop LoopPaint1
add di,320*10
inc di
pop cx
loop LoopPaint2
pop ax
pop cx
pop di
ret
endp PlatBuild
Proc PlatErase
push di
push cx
push ax
mov di,[platLoc]
mov ax,0
mov cx,40
LoopPaint4:
push cx
mov cx,10
LoopPaint3:
mov [es:di],ax
sub di,320
loop LoopPaint3
add di,320*10
inc di
pop cx
loop LoopPaint4
pop ax
pop cx
pop di
ret
endp PlatErase
Proc PlatMove
push ax
push cx
push dx
push di
mov ax,0A000h
mov es,ax
call BorderPaint
;Input
CheckPress1:
mov ah,0h
int 16h
cmp al,'a'
jne nxt11
jmp MoveLeft1
Nxt11:
cmp al,'d'
jne nxt12
jmp MoveRight1
Nxt12:
cmp al,'q'
jne CheckPress1
jmp endproc1
MoveLeft1:
call Delay
mov dx,[platLoc]
add dx,8*320
sub dx,1d
mov di,dx
mov ax,[es:di]
cmp ax,0Fh
jne move1
jmp CheckPress1
move1:
call PlatErase
dec [platLoc]
call PlatBuild
mov ah,1h
int 16h
je MoveLeft1
jmp CheckPress1
MoveRight1:
call Delay
mov dx,[platLoc]
add dx,41
mov di,dx
mov ax,[es:di]
cmp ax,0Fh
jne move2
jmp CheckPress1
move2:
call PlatErase
inc [platLoc]
call PlatBuild
mov ah,1h
int 16h
je MoveRight1
jmp CheckPress1
EndProc1:
pop di
pop dx
pop cx
pop ax
ret
endp PlatMove
proc Delay
push cx
mov cx, [speed2]
LoopLong:
push cx
mov cx, [speed1]
LoopShort:
loop LoopShort
pop cx
loop LoopLong
pop cx
ret
Endp Delay
start:
mov ax,@data
mov ds,ax
mov ax,13h
int 10h
call BorderPaint
call PlatBuild
mov ax, [es:63680]
call PlatMove
exit:
mov ax,4c00h
int 21h
END startenter code here
mov [es:di],ax
将WORD(两个字节)写入VRAM, ax = 0x000F
,因此您以[es:di]
值0x0F
和[es:di+1]
值0x00
(黑色)进行写入。 sub di,6
add di,320
这是亵渎神灵:// ... add di,320-6
在源代码级别仍保持可见的意图,但对机器的了解也较少,从而减少了使用的指令数量。
顺便说一句,如果要存储6个字节的0x0F值,则还可以存储3个字的0x0F0F值,从而节省了一半的VRAM访问(这很昂贵)。 所以呢
mov di,<some VRAM address>
mov cx,<number of lines>
mov ax,0F0Fh ; <color><color> (two pixels at same time)
Draw6PixelsLoop:
mov [es:di],ax
mov [es:di+2],ax
mov [es:di+4],ax
add di,320
dec cx
jnz Draw6PixelsLoop
是一种最佳的硬编码方式,即如何绘制6个像素(仅写入3个VRAM)并在其下方移动1行。
PlatMove
VRAM中读取单词(两个像素),然后将它们与0Fh cmp ax,0Fh
进行比较,即两个像素“ white + black” = 000Fh
。 因此,在左侧可能会很好地工作,但是在右侧,它只会在边框的末尾找到两个像素(请记住,在右侧的最后一个像素之后,下一个字节是像素上的第一个左侧像素下一行,因此,如果您有6个像素的边框,则第一个白色+黑色像素位于左边框结束的下一行。 由于您的程序可在320x200 256色视频模式13h下工作,因此每个像素均由VRAM中的单个字节表示。 在您的代码中,最重要的问题是Ped7g已经指出这一点,即您始终在应该读写字节的地方连续读写字 。
我将通过写顶部边框的更正来表明我们的意思。 不要忘记在其他地方进行类似的更改!
;second line- up horizontal
mov di,6 ; (6,0) <--- See 1.
mov cx,320-6-6 ; Width <--- See 2.
FirstLoop2:
push cx
mov cx,6 ; Height
SecondLoop2:
mov [es:di],al ; Color 0Fh, Byte from AL instead of word from AX
add di,320 ; Go down 1 line
loop SecondLoop2
sub di,320*6 ; Take back 6 additions of 320
inc di ; Go right 1 pixel
pop cx
loop FirstLoop2
我选择此部分是因为它还存在一些其他错误:
上面的代码可以进行很多优化,但是目前您正在努力使工作正常。 因此,请勿尝试一次处理超过1个像素。 编程中的一个重要座右铭是:“首先使其工作, 然后使其变得更好”。
也要像我写的那样写评论。 这将有助于您了解自己在做什么。
MoveLeft1: call Delay mov dx,[platLoc] add dx,8*320 ??? sub dx,1d mov di,dx mov ax,[es:di] ??? cmp ax,0Fh ???
在MoveLeft1代码中,您从错误计算的地址中读取了! 通过将8 * 320添加到dx
寄存器,您将降落在屏幕下方 ,从而离开屏幕。 实际上,由于段环绕,您将错误地寻址VRAM顶部的某些随机像素。
MoveLeft1:
call Delay
mov di, [platLoc]
mov al, [es:di-1] ; Pixel to the left of the platform
cmp al, 0Fh ; Is it white?
jne move1
jmp CheckPress1
move1:
call PlatErase
dec [platLoc]
call PlatBuild
mov ah, 01h
int 16h ; Key pending?
je MoveLeft1
jmp CheckPress1
MoveRight1: call Delay mov dx,[platLoc] add dx,41 ??? mov di,dx mov ax,[es:di] ??? cmp ax,0Fh ???
在MoveRight1代码中,您还会从错误的地址中读取数据。 该平台的宽度为40像素,因此最后一个像素为platLoc + 39,因此需要检查的像素为platLoc + 40。
MoveRight1:
call Delay
mov di, [platLoc]
mov al, [es:di+40] ; Pixel to the right of the platform
cmp al, 0Fh ; Is it white?
jne move2
jmp CheckPress1
move2:
call PlatErase
inc [platLoc]
call PlatBuild
mov ah, 01h
int 16h ; Key pending?
je MoveRight1
jmp CheckPress1
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.