我正在使用带有tasm的dosbox。
这是用汇编程序编写的代码的主要部分。
IDEAL
MODEL small
STACK 100h
P186
include 'GL1.asm'
DATASEG
ballX DW 160
ballY DW 100
ballColor DB 4
BALL_SIZE EQU 20
ballDeltaX DW ?
ballDeltaY DW ?
scorr db 0
randChangeCounter DW ?
CODESEG
start:
mov ax, @data
mov ds, ax
mov ax, 13h
int 10h
mov al,[ballColor]
call glBall
mov CX,60
mov [ballDeltaX],-2
mov [ballDeltaY],-1
mov cx,300
call SetCursor
Gameloop:
mov BH ,00h
call TickDelay
call mouse
call Score
cmp [scorr] , 20
je exit
call randChange
call changeOnborder
call renderBall
call mouse
call Score
cmp [scorr] , 20
je exit
jmp Gameloop
exit:
mov ah, 0
mov al, 2
int 10h
mov ax, 4c00h
int 21h
proc renderBall
PUSHA
xor al,al ; balck
call glBall
mov cx,[ballDeltaX]
add [ballX],cx
mov cx,[ballDeltaY]
add [ballY],cx
mov al,[ballColor]
call glBall
POPA
ret
endp renderBall
proc waitKey
PUSHA
mov ah,00h
int 16h
POPA
ret
endp waitKey
proc glBall
PUSHA
mov cx,[ballX]
mov dx,[ballY]
mov ah,BALL_SIZE
mov bl,BALL_SIZE
call glBox
POPA
ret
endp glBall
proc glBox
PUSHA
@@ONE_LINE :
call glVLine
inc dx
dec bl
jnz @@ONE_LINE
POPA
ret
endp
proc glVLine
PUSHA
mov bl,ah
mov bh,0
mov ah,0ch
@@ONE_PIXEL :
int 10h
inc cx
dec bl
jnz @@ONE_PIXEL
POPA
ret
endp
proc randChange
push ax
inc [randChangeCounter]
cmp [randChangeCounter],20
jne @@skip
mov [randChangeCounter],0
mov ax,13 ; +-6
call rand_max
sub ax,6
mov [ballDeltaX],ax
mov ax,13 ; +-4
call rand_max
sub ax,6
mov [ballDeltaY],ax
mov ax,6
call rand_max
add ax,2
mov [ballColor],al
@@skip:
pop ax
ret
endp randChange
proc SetCursor
mov ax, 0h
int 33h
mov ax, 1h
int 33h
mov ax, 3h
int 33h
ret
endp SetCursor
proc mouse
mov ax, 3h
int 33h
ret
endp mouse
proc Score
mov ax,3h
int 33h
cmp bl,1
je Check_X1_Cords
ret
Check_X1_Cords:
cmp cx, [ballX]
jg Check_X2_Cords
ret
Check_X2_Cords:
cmp cx,[ballX+20]
jl Check_Y1_Cords
ret
Check_Y1_Cords:
cmp dx, [ballY]
jg ScoreLabel
ret
Check_Y2_Cords:
cmp dx, [ballY+20]
jl ScoreLabel
ret
ScoreLabel:
inc [scorr]
ret
endp Score
proc changeOnborder
push ax
mov ax,[ballX]
add ax,[ballDeltaX]
cmp ax,320-BALL_SIZE
jg X_FIX
cmp ax,0
jge X_OK
X_FIX:
mov [ballColor],1
neg [ballDeltaX]
X_OK:
mov ax,[ballY]
add ax,[ballDeltaY]
cmp ax,200- BALL_SIZE
jg Y_FIX
cmp ax,0
jge Y_OK
Y_FIX:
mov [ballColor],1
neg [ballDeltaY]
Y_OK:
pop ax
ret
endp changeOnborder
END start
这是GL1.asm
RANDPRIME equ 401
segment biosdata at 40h
org 6ch
timer dw ? ; clock ticks
ends
DATASEG
lastrand dw 0
FastCounter DW 0 ;
SlowCounter DW 0 ;
CODESEG
;
; timeticks - get time ticks from bios data segment.
;
; Register Arguments:
; None.
;
; Returns:
; ax - current ticks
;
proc timeticks
push es
mov ax, biosdata
mov es, ax
assume es:biosdata
mov ax, [timer]
assume es:nothing
pop es
ret
endp
;
; random - pseudo generate random number
;
; Register Arguments:
; None.
;
; Returns:
; ax - random number.
;
codeseg
proc random
push dx
push bx
mov bx, [lastrand]
mov ax, bx
mov dx, RANDPRIME
mul dx
mov dx, ax
call timeticks
xor ax, dx
xchg dh, dl
xor ax, dx
xchg bh, bl
xor ax, bx
mov [lastrand], ax
pop bx
pop dx
ret
endp
proc rand_max
push dx
push bx
mov bx,ax ; store max
call random ; -> ax
xor dx,dx
div bx
mov ax,dx ; the reminder [0..max]
pop bx
pop dx
ret
endp rand_max
;===================== Delay =====================
Proc delay
push ax
push cx
push dx
push es
mov dx,0
mov cx , 55
div cx
mov cx, ax
cmp cx,0
je Finish
DelayLoop:
call timeticks
mov dx,ax
Tick:
call timeticks
cmp dx,ax
je Tick
loop DelayLoop
Finish:
pop es
pop dx
pop cx
pop ax
ret
endp Delay
proc TickDelay
pusha
mov cx, 4
each_sync:
call wait_for_vsync
loop each_sync
popa
ret
endp TickDelay
proc wait_for_vsync
pusha
mov dx, 03dah
@@previous_not_ended:
in al, dx
test al, 08h
jnz @@previous_not_ended
@@next_not_started:
in al, dx
test al, 08h
jz @@next_not_started
@@exit:
popa
ret
endp
我不知道该怎么做我认为问题出在GL1中,但我不确定。
根据问题或代码风格的任何帮助都会非常适用。
提前多多感谢。
答案 0 :(得分:1)
快速浏览显示以下内容:
您的 timeticks 程序根本不会读取BIOS计时器!
您已为ES
段寄存器设置了所有内容,但mov ax, [timer]
指令完全取决于DS
段寄存器。
这会破坏 rand_max 和延迟程序。
难怪它不起作用!
换句话说,以下内容变为无限循环(因为 timeticks 最有可能总是返回相同的值!):
call timeticks
mov dx, ax
Tick:
call timeticks
cmp dx, ax
je Tick
答案 1 :(得分:0)
很难说,什么“不起作用”的意思,以及你的代码应该做什么,但我会试着猜测,以下部分没有做到预期的事情(也许,你没有评论任何事情)。
...
; cx = 0..639 mouse.x position
Check_X1_Cords:
cmp cx, [ballX]
jg Check_X2_Cords
ret
Check_X2_Cords:
cmp cx,[ballX+20]
jl Check_Y1_Cords
ret
...
问题是,ballX
符号是DW
(两个字节)保留空间的内存地址。例如地址0x1234。并且地址0x1234处的存储器包含例如两个字节:0x88 0x01
(0x0188 = 392)。让我们说鼠标位于x位置550。
然后第一个cmp
会将cx
(550)与地址0x1234
(0x0188 = 392)的值进行比较,然后jg
跳转到Check_X2_Cords
}。
第二个cmp
会将cx
(550)与地址0x1234+20
= 0x1248
的值进行比较,这是内存中的任何值,但很可能不会一些有用的东西(可能为零,因为它超出了你在数据段中的其他变量)。
您可能确实想要将第二个测试编写为:
...
Check_X2_Cords:
add cx,20
cmp cx,[ballX]
jl Check_Y1_Cords
...
cmp cx,[ballX+20]
不会在内存中添加20,但它会向ballX
添加20,这是符号标签(内存中的地址),而不是值/变量。
虽然一些汇编程序(MASM)支持mov ax,ballX
之类的语法,这使得看起来像ballX
一样变量(就像在高级语言中一样) ),IMO只是混淆了谬误,因为该指令的真实性质是mov ax,[offset_of_some_address]
,ballX
是地址,而不是价值。
可能还有其他错误,我没有做完整的代码审查,只是在我看到的第一个可疑的东西时停止了(大约10秒钟)。
还有一个快速的问题,在random
中你使用一些时间数据生成每个随机数?不要这样做,那也是错误。仅使用时间滴答来计算一些初始“种子”值,之后随机生成器将起作用。每次调用将时间数据混合到其中实际上会使其成为非随机数据。你的RANDPRIME
太小了,但只是谷歌的一些非常简单和快速(并且不足以用于安全目的,但对于游戏它会做得很好)RNGR算法,经典的算法肯定几乎无处不在。< / p>