我是汇编语言的新手8086。我正在使用MASM611。我正在制作恐龙游戏(Google Chrome离线游戏(。我绘制的越多,屏幕就越开始闪烁。我尝试了一切,但找不到任何东西。代码完美地编译而没有错误。这是代码
MainLoop:
;call clearRegisters
mov ah,01h
int 16h
mov bh,ah
mov bl,0
mov al,0
mov ah,0Ch
int 21h
cmp bh,12h
je Exit
call SelectScreen
mov ax,dinoObj.x
mov x,ax
mov ax,dinoObj.y
mov y,ax
call clearRegisters
call DrawBackground
call clearRegisters
call drawDinoBase
call clearRegisters
call drawDino
call clearRegisters
jmp MainLoop`
selectscreen funtion如下
SelectScreen proc
mov ah,0
mov al,12h
int 10h
Terminate:
ret
SelectScreen Endp`
drawdino函数的片段
drawDino proc
mov ax,y
mov tempY,ax
mov cx,8
outer1:
push cx
mov ax,x
mov tempX,ax
mov cx,20
inner1:
push cx
mov ah,0ch
mov al,10
mov cx,tempX
mov dx,tempY
int 10h
inc tempX
pop cx
loop inner1
inc tempY
pop cx
loop outer1
mov ax,y
add ax,8
mov tempY,ax
mov cx,12
outer2:
push cx
mov ax,x
mov tempX,ax
mov cx,38
inner2:
push cx
mov ah,0ch
mov al,10
mov cx,tempX
mov dx,tempY
int 10h
inc tempX
pop cx
loop inner2
inc tempY
pop cx
loop outer2
mov ax,y
add ax,21
mov tempY,ax
mov cx,8
outer3:
push cx
mov ax,x
mov tempX,ax
mov cx,20
inner3:
push cx
mov ah,0ch
mov al,10
mov cx,tempX
mov dx,tempY
int 10h
inc tempX
pop cx
loop inner3
inc tempY
pop cx
loop outer3
您所描述的称为闪烁。直接引用Wikipedia:
例如,直接在框架缓冲区中掩盖区域的实践,然后在其"顶部"绘制,使空白区域可以暂时出现在屏幕上。
这是由于您对框架缓冲区的写入与视频子系统刷新周期之间缺乏同步引起的。
为了维持一致的图形状态,您应仅在反弯曲期间修改框架缓冲区,通常由于其更长的延伸而进行垂直反转。
在视频子系统正在阅读时写入框架缓冲区会产生不一致的状态,因为只有当前扫描线以下的屏幕部分才会更新。
此问题的解决方案全部共享相同的轮廓 - 回顾期间立即写下框架缓冲区。
最佳解决方案是页面翻转,并已在评论中建议。
它包括在显示适配器内存的两个不同区域之间切换活动帧缓冲区。
不幸的是,VGA适配器不支持您选择 1 的视频模式 - 只有一个页面。
替代方案是双重缓冲,其中包括使用后部缓冲区(与框架缓冲区一样大(与通常的图形启动。
然后呈现后缓冲区,在下一次可用回溯期间,它将被复制(位混合(到框架缓冲区中。
软件体系结构的确切写作太广泛了,有很多方法可以实现这一目标,并且每个方法都有不同的必需技能。
最简单的方法是使用同步介绍 - 代码在后退缓冲区上执行所有图形操作,然后等待下一个垂直撤回曲线以展示它。
如果您的代码足够快,浪费的时间等待回顾就无关紧要。
但是请记住,渲染循环将以显示器刷新速度的速度运行(在游戏中通常是一件好事,因为它是时间安排的免费壁钟(。
不幸的是,您将BIOS服务用作图形原则,并且仅在框架缓冲区中写入(实际上是活动页面,但只有一个(。
正如CodyGray所提醒的那样,替代方案是直接写入框架缓冲区 - 您选择的视频模式并不容易使用,因为它涉及位平面。模式13H取而代之的是将框架缓冲区视为内存的连续区域 - 几乎就像矩阵。
如果您不想沿着重写绘制的代码的道路,可以尝试使用一些胶带进行调整。
可以通过测试VGA适配器的输入状态#1寄存器的位3来确定显示器何时处于垂直回溯 - 当该位是一个位置时,监视器是在垂直回溯中的。
的想法是在开始绘制新框架之前等待垂直回溯。
这可能与您编写渲染循环的方式兼容或可能不兼容 - 此外,我从未使用过BIOS调用和垂直回溯逻辑的混合方法。
由于它与视频子系统的互动方式,我无法排除BIOS实施的可能性。
尤其是,科迪格雷指出,BIOS呼叫将无情地导致闪烁。
为了避免在接近端撤回上启动框架的风险,最好等待a new retrace。
waitForNewVR:
mov dx, 3dah
;Wait for bit 3 to be zero (not in VR).
;We want to detect a 0->1 transition.
_waitForEnd:
in al, dx
test al, 08h
jnz _waitForEnd
;Wait for bit 3 to be one (in VR)
_waitForNew:
in al, dx
test al, 08h
jz _waitForNew
ret
我没有保存寄存器dx
和ax
,您可能需要根据您的需求添加一对push/pop
。
1 根据PED7G,可以直接实施页面直接操纵硬件。
,因此我能够通过以下2个步骤来解决这个'闪烁'问题:
- 通过添加 timedelay (睡觉(绘制画布。
- 增加 dosbox的CPU周期 到340000000。
谢谢大家的回答。