We're doing a game which consists of a block that deslocates itself through different columns. This blocks catches little points that fall and when that happends the player gets points. This is a kind of pong game. We already have a beginning of the game in which we have a square, a little point and the mouse. There are several things that we don't know how to do but my first question is: how can I deslocate the square horizontaly with the help of the mouse or the arrow keys? The next step will be to make the little points fall randomly.
I'm sorry, I forgot to post my code:
stack segment para stack
db 64 dup ('mystack' )
stack ends
mycode segment para 'code'
myproc proc far
assume cs:mycode, ss:stack
push ds
sub ax,ax
push ax
mov ah, 00h ; prepara para definir o mod grafico
mov al, 04 ;modo graf 320x200 color mode
int 10h ;invoca a int 10h da BIOS
mov ah,11 ;prepara configuração da palete de cores
mov bh,00 ;inicializa a cor de background
mov bl,01 ;background azul
int 10h ;invoca a interrupção 10h da BIOS
mov ah,11 ;prepara configuração da palete de cores
mov bh,01 ;prepara conf do foreground
mov bl,00 ;verde,vermelho e amarelo
int 10h ;invoca a intrrupção 10h 10 da Bios
call rato
;desenhar o pontinho
mov dx,64h ;selecciona a linha 100
mov cx,9eh ; seleciona a coluna 158
mov al,02 ;cor dos pontos vermelho, configura
mov ah,12 ;conf int 10h para plot do pixel
;inc dx ;vai incrementar o número de vezes que for chamado dentro do FOR
int 10h
;desenhar o primeiro rectangulo
mov dx,98h ;selecciona a linha 100
mov cx,32h ;selecciona a coluna 158
call proc1
;2 rectangulo
;mov dx,64h ;selecciona a linha 50
;mov cx,032h ;selectiona a coluna 64
;call proc1
;desenhar um ponto
;terceiro rectangulo
;mov dx,32h ;selecciona a linha 50
;mov cx,064h ;selectiona a coluna 64
;call proc1
mov ah,01 ;apenas espera
int 21h ;por outra tecla
mov ah,00h ;prepara para definir o modo grafico
mov al,02h ;repor modo texto.80.25
int 10h
;invoca a intrrupção 10h 10 da Bios
ret
myproc endp
proc1 proc near
mov bl,0h ;
mov bh,0h ;
um:
mov al,bl
cmp al,20 ;compara o valor que esta em AL é igual a 20
jg iniciofor2 ; salta se for igual a 20
call linha1
inc bl
jmp um
;linhas na vertical
iniciofor2:
mov bl,0h ;inicia for a zero
dois:
mov al,bl ;colocar o valor de bl em al
cmp al,30 ;compara se o valor que está no al é igual a 30
jg iniciofor3
call coluna1
inc bl
jmp dois
;linha horizontal
iniciofor3:
mov bl,0 ;coloca o 0 no bl
tres:
mov al,bl
cmp al,20
jg iniciofor4 ; salta para inicio4 se for menor 20
call linha2 ; senão chama o procedimento linha esquerda, que é para desenhar as linhas
inc bl ;incrementa o bl
jmp tres ;salta para 3
;++++++++++++++++++++++++linha vertical em comprimentos ao anterior++++++++++++++++++++++++++++++++++++++++
iniciofor4:
mov bl,0h ;inicia a zero
quatro:
mov al,bl
cmp al,30 ; número de vezes que faz
jg sair
call coluna2
inc bl
jmp quatro
sair:
ret
proc1 endp ; acaba o procedimento forproc
linha1 proc near
mov al,02 ;cor dos pontos vermelho, configura
mov ah,12 ;conf int 10h para plot do pixel
inc dx ; vai incrementar o número de vezes que for chamado dentro do FOR
int 10h ;invoca a int 10h
ret
linha1 endp
linha2 proc near
mov al,02 ;cor dos pontos vermelho, configura
mov ah,12 ;conf int 10h para plot do pixel
dec dx ; vai decrementar o número de vezes que for chamado dentro do FOR
int 10h ;invoca a int 10h
ret
linha2 endp
coluna2 proc near
mov al,02 ;cor dos pontos vermelho, configura
mov ah,12 ;conf int 10h para plot do pixel
inc cx ; vai incrementar o número de vezes que for chamado dentro do FOR
int 10h ;invoca a int 10h
ret
coluna2 endp
coluna1 proc near
mov al,02 ;cor dos pontos vermelho, configura
mov ah,12 ;conf int 10h para plot do pixel
dec cx ; vai decrementar o número de vezes que for chamado dentro do FOR
int 10h ;invoca a int 10h
ret
coluna1 endp
rato proc near ;
mov ax,00
int 33h
mov ax,01
int 33h
ret
rato endp
mycode ends
end
Hi,
Just took a quick look. But what you are going to want
is probably something like the following pseudo code:
MainLoop:
Check for key
If key is Right, then
Erase Box
Inc Box X position
Draw Box
End if
If key is Left, then
Erase Box
Dec Box X position
Draw Box
End if
Erase Point1
Inc Point1 Y position
Draw Point1
Erase Point2
{And so forth}
...
Wait for a short while,
Loop MainLoop
Steve
Yes, thank you for your reply. But how can I do it with the mouse? Do you know an example from which I can guide myself?
Hi,
Here are two examples. Simple paint programs.
HTH,
Steve N.
Thanks!!
I have a problem with this game. I have a procedure in which I define the color of the square with the code:
mov al ,01
But when I move the square with the arrow keys I have to paint the square with the color of the background and paint it again to the left. It would be simple to create a variable:
color db 02
and that way I would easily change the value of the variable. But when I change the code to:
mov al,color
I get the error:
"Cannot address with segment register"
How can I solve this problem?
Hi,
You need to correctly initialize the DS segment register.
And then tell MASM that you did so with an ASSUME
statement.
How you initialize DS depends on where you are putting
the "color" variable. Are you making a separate data
segment or putting it in the code segment? If the first
try something like.
DATASEG SEGMENT
color DB 0
DATASEG ENDS
... then go to where you have.
push ds
sub ax,ax
push ax
... and add
; - - - Initialization - - -
MOV AX,SEG DATASEG ; Set DS for rest of code ...
MOV DS,AX
ASSUME DS:DATASEG
Regards,
Steve N.
Yes, a very basic mistake, I forgot to put the assume directive. Thanks
Our game has changed and now we detect if the user has clicked the left key and in that case we paint the square with the color of the background. But the problem is that the square doesn't disappear and letters appear on the screen. The program ends if we click the enter key. On the end we receive the message that the program is doing an ilegal instruction. Here is our code:
stack segment para stack
db 64 dup ('mystack' )
stack ends
mydata segment para 'data'
color db 02
lado dw 0
mydata ends
mycode segment para 'code'
myproc proc far
assume cs:mycode, ss:stack, ds:mydata
push ds
sub ax,ax
push ax
mov ah, 00h ; prepara para definir o mod grafico
mov al, 04 ;modo graf 320x200 color mode
int 10h ;invoca a int 10h da BIOS
mov ah,11 ;prepara configuração da palete de cores
mov bh,00 ;inicializa a cor de background
mov bl,01 ;background azul
int 10h ;invoca a interrupção 10h da BIOS
mov ah,11 ;prepara configuração da palete de cores
mov bh,01 ;prepara conf do foreground
mov bl,00 ;verde,vermelho e amarelo
int 10h ;invoca a intrrupção 10h 10 da Bios
call rato
;desenhar o pontinho
mov dx,10h ;selecciona a linha 100
mov cx,9eh ; seleciona a coluna 158
mov al,02 ;cor dos pontos vermelho, configura
mov ah,12 ;conf int 10h para plot do pixel
;inc dx ;vai incrementar o número de vezes que for chamado dentro do FOR
int 10h
;desenhar o primeiro rectangulo
mov dx,98h ;selecciona a linha 100
mov cx,32h ;selecciona a coluna 158
call proc1
here:mov ah,01 ;apenas espera
int 21h ;por outra tecla
cmp ax, 4b00h
mov lado,4b00h
je apaga
cmp ax,4d00h
mov lado,4d00h
je apaga
mov ah,01 ;apenas espera
int 21h ;por outra tecla
cmp al, 0dh ;enquanto for diferente de ENTER não sai do programa
jne here
apaga:mov color,01
call proc1
mov ah,00h ;prepara para definir o modo grafico
mov al,02h ;repor modo texto.80.25
int 10h ;invoca a interrupção 10h 10 da Bios
ret
myproc endp
proc1 proc near
mov bl,0h ;
mov bh,0h ;
um:
mov al,bl
cmp al,20 ;compara o valor que esta em AL é igual a 20
jg iniciofor2 ; salta se for igual a 20
call linha1
inc bl
jmp um
;linhas na vertical
iniciofor2:
mov bl,0h ;inicia for a zero
dois:
mov al,bl ;colocar o valor de bl em al
cmp al,30 ;compara se o valor que está no al é igual a 30
jg iniciofor3
call coluna1
inc bl
jmp dois
;linha horizontal
iniciofor3:
mov bl,0 ;coloca o 0 no bl
tres:
mov al,bl
cmp al,20
jg iniciofor4 ; salta para inicio4 se for menor 20
call linha2 ; senão chama o procedimento linha esquerda, que é para desenhar as linhas
inc bl ;incrementa o bl
jmp tres ;salta para 3
;++++++++++++++++++++++++linha vertical em comprimentos ao anterior++++++++++++++++++++++++++++++++++++++++
iniciofor4:
mov bl,0h ;inicia a zero
quatro:
mov al,bl
cmp al,30 ; número de vezes que faz
jg sair
call coluna2
inc bl
jmp quatro
sair:ret
cmp color,01
je muda
ret
proc1 endp ; acaba o procedimento proc1
muda proc near
mov color,02
jmp here
ret
muda endp
linha1 proc near
mov al,color ;cor dos pontos vermelho, configura
mov ah,12 ;conf int 10h para plot do pixel
inc dx ; vai incrementar o número de vezes que for chamado dentro do FOR
int 10h ;invoca a int 10h
ret
linha1 endp
linha2 proc near
mov al,color ;cor dos pontos vermelho, configura
mov ah,12 ;conf int 10h para plot do pixel
dec dx ; vai decrementar o número de vezes que for chamado dentro do FOR
int 10h ;invoca a int 10h
ret
linha2 endp
coluna2 proc near
mov al,color ;cor dos pontos vermelho, configura
mov ah,12 ;conf int 10h para plot do pixel
inc cx ; vai incrementar o número de vezes que for chamado dentro do FOR
int 10h ;invoca a int 10h
ret
coluna2 endp
coluna1 proc near
mov al,color ;cor dos pontos vermelho, configura
mov ah,12 ;conf int 10h para plot do pixel
dec cx ; vai decrementar o número de vezes que for chamado dentro do FOR
int 10h ;invoca a int 10h
ret
coluna1 endp
rato proc near ;
mov ax,00
int 33h
mov ax,01
int 33h
ret
rato endp
mycode ends
end
Hi,
You put in the ASSUME, but Idon't see where you
actually initialize DS.
Steve N.
also a good idea to name the entry point in the END directive...
END myproc
I have been dividing my game into several parts . In this part I have the little "balls" falling and on the other part I have the square going to the right and to the left. But now I have this problem. I need to have the little balls continuously falling so this means I have an infinite loop. But when I'm in this infinite loop nothing else goes on. But how can I make the infinite loop go on and simultaneously wait for the user to press some keys. For example if he presses 1 it means that the balls fall at velocity one and if he presses 2 it means they'll fall at velocity two and so on. What I mean is that I have my game at an infinite loop but I need other things to go on. How do I do that? Here goes my code:
STACK SEGMENT PARA STACK
DB 64 DUP ('MYSTACK ')
STACK ENDS
MYDATA SEGMENT PARA 'DATA'
frase1 db 'DDDddddddddd','$'
nivel dw 200
coluna dw 96h
MYDATA ENDS
MYCODE SEGMENT PARA 'CODE'
MYPROC PROC FAR
ASSUME CS:MYCODE,SS:STACK,DS:MYDATA
PUSH DS
SUB AX,AX
PUSH AX
MOV AX,MYDATA
MOV DS,AX
MOV AH, 00h
MOV AL, 04h
INT 10h
; MOV AH, 11
; MOV BH, 00
; MOV BL, 01
; INT 10h
MOV AH, 11
MOV BH, 01
MOV BL, 00
INT 10h
;push ax
;push bx
;por a mensagem no ecran
;MOV DX,0 ;256 * row + column (0,0 = upper left corner)
;MOV BH,0
;MOV AH,2
;INT 10h
;lea dx,frase1 ;coloca mensagem
;mov ah,09h ;inicialização de parâmetro de interrupção
;int 21h ;interrupção que envia frase para o ecran
;pop bx
;pop ax
;
push ax
pix:call pixel
mov ax,10
call MsDelay
jmp pix
pop ax
push dx
mov ah,6 ;apenas espera
mov dl,0ffh
int 21h ;por outra tecla
cmp al,31h ;se o utilizador carrega na tecla 1 escolhe o nivel um
je um
cmp al,32h ;se o utilizador carrega no 2 escolhe nivel dois (mais lento)
je dois
um:mov nivel,200
dois:mov nivel,500
pop dx
MOV ah, 01
INT 21h
MOV AH, 00h
MOV AL, 02h
INT 10h
RET
MYPROC ENDP
pixel proc near
push ax
push bx
mov ah,2ch ;para ir buscar as centésimas de segundo
int 21h
sub dh,dh
mov ax,dx ;para fazer a multiplicação do valor por ah
mov cx,0ah
mul cx
;mov aleatorio, ax ;guarda os centesimos de segundo em aleatorio
;o resultado da multiplicação está em ax
;o resto fica em dx
;vai dividir ax por 2bch
mov bx,2bch
div bx
cmp dx,12ch ;verificar se o resto da divisao é maior q 300
jg maior
maior: mov coluna,12ch ; se o resto da divisao for maior que 300 retorna a coluna 300
mov coluna,dx ;poe o resto da divisao na coluna
pop bx
pop ax
mov dx,10h ;selecciona a linha 100
mov cx,coluna ; seleciona a coluna
;MOV DX, 64h
MOV CX,180
Game:
PUSH CX
MOV AL, 02 ;pixel cor vermelha
MOV AH, 12
MOV CX, coluna
INT 10h
;MOV ah, 01
;INT 21h ;espera por uma tecla
mov ax, nivel
call MsDelay
MOV AL, 00 ;pixel cor preto
MOV AH, 12
MOV CX, coluna ;considerando que temos 300 colunas
INT 10h
INC DX
POP CX
Loop Game
pixel endp
MsDelay proc near
; -----------------------------------------------------------
; This proc delays for the specified number of milliseconds.
; It does this by counting memory refresh requests, which
; for AT-class systems are generated by system timer 1,
; normally programmed by the BIOS to generate an output once
; every 18/1193182 = 15.09 microseconds. Each request toggles
; bit 4 of I/O port 61h. We are counting full cycles of the
; bit, with two toggles per cycle, so each cycle takes 30.18
; microseconds and we count 34 cycles for each millisecond.
;
; Call with the number of milliseconds in AX.
;
; Preserves all registers other than AX.
;
; Note that the delay will be much shorter when running
; under the NT versions of Windows.
; -----------------------------------------------------------
push cx
mov cx, ax ; load msLoop count
msLoop:
push cx ; preserve msLoop counter
mov cx, 34 ; load repeat count
wait1:
in al, 61h ; read byte from port
test al, 10h ; test bit 4
jz wait1 ; jump if bit clear
wait2:
in al, 61h ; read byte from port
test al, 10h ; test bit 4
jnz wait2 ; jump if bit not clear
dec cx ; decrement repeat count
jnz wait1 ; jump if count not zero
pop cx ; recover msLoop counter
dec cx ; decrement msLoop count
jnz msLoop ; jump if count not zero
pop cx
ret
MsDelay endp
MYCODE ENDS
END
I think I didn't explain myself very well. I have 2 procedures. One is continuously making these balls fall. And the other is waiting for the user to press the keys for right and left to move a rectangle right and left. If I can't use threads of course I will have to interrupt the procedure that makes the balls fall to wait for the keys that are pressed by the user. Is there a way in which I can make a procedure function for some milliseconds and then make the other procedure function another milliseconds?
tomorrow, i will have a look at it and see what we can figure out :U
Hi,
If you can use the timer ticks (18.2 times a second) you
can read the value in the BIOS data segment and use it to
determine if the routine should exit.
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BIOSSEG SEGMENT AT 40H ; BIOS Data area
ORG 6CH
ClockTic LABEL DWORD ; 55 ms timer ticks since CPU reset
BIOSSEG ENDS
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MOV AX,WORD PTR [ClockTic]
MOV [TestTic],AX
DoWork:
; Insert your routine here.
MOV AX,WORD PTR [ClockTic]
CMP [TestTic],AX ; Have we used enough time to quit?
JE DoWork ; No, continue.
RET
This gives about the same resolution you would get with
using the timer interrupt, but is a bit simpler.
If shorter periods are required, you can try Int 15H, function 83H.
This gives about 1 millisecond resolution, if allowed by your computer.
On my computers, Windows 2000 and XP do not allow it.
MOV AX,8300H
XOR CX,CX ; CX:DX = Microsecond count.
MOV DX,10000 ; 10 milliseconds
PUSH ES ; ES:BX = user memory byte.
PUSH DS
POP ES
MOV BX,OFFSET TestTic
INT 15H
POP ES
MOV [TestTic],0 ; Zero flag byte.
DoWork:
; Insert your routine here.
CMP [TestTic],0 ; Have we used enough time to quit?
JE DoWork ; No, continue.
RET
If these will not work for you, you can program timer 2 to
generate a square wave of your choice of duration. Then
have one routine run when the timer output is high and the
other when it is low.
Regards,
Steve N.
amrac - i wonder if i could get you to explain, as well as you can, how you want the game to play
i don't understand what is supposed to happen with the keys
is there some other game that is similar ? - it kind of sounds like Centipede - lol
or - is there a game like it already written that we could try ?
also - are the comments in Portuguese ? (Brazil ?)
some of it i can understand because it's similar to Spanish :P
i had 3 years of Latin in high school, but i don't remember very much - lol
i can use a translator
maybe that is the best way for you to convey how it is supposed to play
Yes the comments are in portuguese. I think that there is an old game that is very similar. I have a block that stays on the bottom of the screen and deslocates itself to the right and to the left. The old game that I know had a ball bouncing and you had to touch the ball with the block when it touched the ground. In my game you have several balls falling, one at each time, and you have to touch the ball with the block to have ponctuation. One procedure makes the balls fall. The other procedure makes the block move . But you have to give a little time to each other and interrupt each procedure for a little time. The code that I left only had the balls falling. The code that I'm going to leave now has the procedure quadrado which draws the block to the right and to the left and the procedure pixeis which makes the balls fall. The procedures call each other but it isn't working. What is supposed to happen with the keys is to deslocate the block to the right and to the left. n for right, m for left ENTER to exit the game.
stack segment para stack
db 64 dup ('mystack' )
stack ends
mydata segment para 'data'
color db 02
lado dw 0
nivel dw 200
inicio dw 32h
coluna dw 96h
mydata ends
mycode segment para 'code'
myproc proc far
assume cs:mycode, ss:stack, ds:mydata
PUSH DS
SUB AX,AX
PUSH AX
MOV AX,MYDATA
MOV DS,AX
mov ah, 00h ; prepara para definir o mod grafico
mov al, 04 ;modo graf 320x200 color mode
int 10h ;invoca a int 10h da BIOS
mov ah,11 ;prepara configuração da palete de cores
mov bh,00 ;inicializa a cor de background
mov bl,01 ;background azul
int 10h ;invoca a interrupção 10h da BIOS
mov ah,11 ;prepara configuração da palete de cores
mov bh,01 ;prepara conf do foreground
mov bl,00 ;verde,vermelho e amarelo
int 10h ;invoca a intrrupção 10h 10 da Bios
call rato
call quadrado ;procedimento que vai desenhar e apagar os quadrados
mov ah,00h ;prepara para definir o modo grafico
mov al,02h ;repor modo texto.80.25
int 10h ;invoca a interrupção 10h 10 da Bios
ret
myproc endp
pixeis proc near ;procedimento que vai continuamente fazer cair os pixeis
push ax
pix:call pixel ;procedimento que faz cair um pixel
mov ax,10
call MsDelay
;++++++++++++++++++++++++++++++++chama o procedimento quadrado++++++++++++++++++++++++++++++++++++++++++++++++
call quadrado
jmp pix
pop ax
pixeis endp
quadrado proc near
;desenhar o rectangulo
quad: mov dx,98h ;selecciona a linha 100
mov cx,inicio ;selecciona a coluna 158
call proc1
;++++++++++++++++++++++++++++++chama o procedimento pixeis+++++++++++++++++++++++++++++++++
call pixeis
here:
push dx
mov ah,6 ;apenas espera
mov dl,0ffh
int 21h ;por outra tecla
pop dx
cmp al, 6eh ;se for igual a tecla n vai apagar quadrado
je apaga
cmp al,6dh ;se for igual a tecla m vai apagar quadrado
je apaga
cmp al,0dh ;se for ENTER sai do programa
je fim
push dx
mov ah,6 ;apenas espera
mov dl,0ffh
int 21h ;por outra tecla
pop dx
cmp al, 0dh ;enquanto for diferente de ENTER não sai do programa
jne here
apaga:mov color,00
mov ax,10
call MsDelay
sub ah,ah
mov lado,ax
call proc1
mov color,02
cmp lado,6dh ;se foi escolhida a tecla para a direita vai ser desenhado o quadrado à direita
je inicio2
cmp lado,6eh ;se foi escolhida a tecla para a esquerda vai ser desenhado o quadrado à esquerda
je inicio1
inicio2:add inicio,10h
jmp quad
inicio1:sub inicio, 10h
jmp quad
fim:
mov ah,1 ;apenas espera
int 21h ;por outra tecla
quadrado endp
proc1 proc near
mov bl,0h ;
mov bh,0h ;
um:
mov al,bl
cmp al,20 ;compara o valor que esta em AL é igual a 20
jg iniciofor2 ; salta se for igual a 20
call linha1
inc bl
jmp um
;linhas na vertical
iniciofor2:
mov bl,0h ;inicia for a zero
dois:
mov al,bl ;colocar o valor de bl em al
cmp al,30 ;compara se o valor que está no al é igual a 30
jg iniciofor3
call coluna1
inc bl
jmp dois
;linha horizontal
iniciofor3:
mov bl,0 ;coloca o 0 no bl
tres:
mov al,bl
cmp al,20
jg iniciofor4 ; salta para inicio4 se for menor 20
call linha2 ; senão chama o procedimento linha esquerda, que é para desenhar as linhas
inc bl ;incrementa o bl
jmp tres ;salta para 3
;++++++++++++++++++++++++linha vertical em comprimentos ao anterior++++++++++++++++++++++++++++++++++++++++
iniciofor4:
mov bl,0h ;inicia a zero
quatro:
mov al,bl
cmp al,30 ; número de vezes que faz
jg sair
call coluna2
inc bl
jmp quatro
sair:ret
cmp color,01
je muda
ret
proc1 endp ; acaba o procedimento proc1
muda proc near
mov color,02
jmp here
ret
muda endp
linha1 proc near
mov al,color ;cor dos pontos vermelho, configura
mov ah,12 ;conf int 10h para plot do pixel
inc dx ; vai incrementar o número de vezes que for chamado dentro do FOR
int 10h ;invoca a int 10h
ret
linha1 endp
linha2 proc near
mov al,color ;cor dos pontos vermelho, configura
mov ah,12 ;conf int 10h para plot do pixel
dec dx ; vai decrementar o número de vezes que for chamado dentro do FOR
int 10h ;invoca a int 10h
ret
linha2 endp
coluna2 proc near
mov al,color ;cor dos pontos vermelho, configura
mov ah,12 ;conf int 10h para plot do pixel
inc cx ; vai incrementar o número de vezes que for chamado dentro do FOR
int 10h ;invoca a int 10h
ret
coluna2 endp
coluna1 proc near
mov al,color ;cor dos pontos vermelho, configura
mov ah,12 ;conf int 10h para plot do pixel
dec cx ; vai decrementar o número de vezes que for chamado dentro do FOR
int 10h ;invoca a int 10h
ret
coluna1 endp
rato proc near ;
mov ax,00
int 33h
mov ax,01
int 33h
ret
rato endp
pixel proc near
push ax
push bx
mov ah,2ch ;para ir buscar as centésimas de segundo
int 21h
sub dh,dh
mov ax,dx ;para fazer a multiplicação do valor por ah
mov cx,0ah
mul cx
;mov aleatorio, ax ;guarda os centesimos de segundo em aleatorio
;o resultado da multiplicação está em ax
;o resto fica em dx
;vai dividir ax por 2bch
mov bx,2bch
div bx
cmp dx,12ch ;verificar se o resto da divisao é maior q 300
jg maior
maior: mov coluna,12ch ; se o resto da divisao for maior que 300 retorna a coluna 300
mov coluna,dx ;poe o resto da divisao na coluna
pop bx
pop ax
mov dx,10h ;selecciona a linha 100
mov cx,coluna ; seleciona a coluna
;MOV DX, 64h
MOV CX,180
Game:
PUSH CX
MOV AL, 02 ;pixel cor vermelha
MOV AH, 12
MOV CX, coluna
INT 10h
;MOV ah, 01
;INT 21h ;espera por uma tecla
mov ax, nivel
call MsDelay
MOV AL, 00 ;pixel cor preto
MOV AH, 12
MOV CX, coluna ;considerando que temos 300 colunas
INT 10h
INC DX
POP CX
Loop Game
pixel endp
MsDelay proc near
; -----------------------------------------------------------
; This proc delays for the specified number of milliseconds.
; It does this by counting memory refresh requests, which
; for AT-class systems are generated by system timer 1,
; normally programmed by the BIOS to generate an output once
; every 18/1193182 = 15.09 microseconds. Each request toggles
; bit 4 of I/O port 61h. We are counting full cycles of the
; bit, with two toggles per cycle, so each cycle takes 30.18
; microseconds and we count 34 cycles for each millisecond.
;
; Call with the number of milliseconds in AX.
;
; Preserves all registers other than AX.
;
; Note that the delay will be much shorter when running
; under the NT versions of Windows.
; -----------------------------------------------------------
push cx
mov cx, ax ; load msLoop count
msLoop:
push cx ; preserve msLoop counter
mov cx, 34 ; load repeat count
wait1:
in al, 61h ; read byte from port
test al, 10h ; test bit 4
jz wait1 ; jump if bit clear
wait2:
in al, 61h ; read byte from port
test al, 10h ; test bit 4
jnz wait2 ; jump if bit not clear
dec cx ; decrement repeat count
jnz wait1 ; jump if count not zero
pop cx ; recover msLoop counter
dec cx ; decrement msLoop count
jnz msLoop ; jump if count not zero
pop cx
ret
MsDelay endp
mycode ends
end
added code tags
ohhh - maybe similar to BreakOut
give me some time to mess with it - i have just gotten busy, here - lol
Quote from: FORTRANS on January 05, 2010, 01:21:22 PM
Hi,
If you can use the timer ticks (18.2 times a second) you
can read the value in the BIOS data segment and use it to
determine if the routine should exit.
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BIOSSEG SEGMENT AT 40H ; BIOS Data area
ORG 6CH
ClockTic LABEL DWORD ; 55 ms timer ticks since CPU reset
BIOSSEG ENDS
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MOV AX,WORD PTR [ClockTic]
MOV [TestTic],AX
DoWork:
; Insert your routine here.
MOV AX,WORD PTR [ClockTic]
CMP [TestTic],AX ; Have we used enough time to quit?
JE DoWork ; No, continue.
RET
This gives about the same resolution you would get with
using the timer interrupt, but is a bit simpler.
If shorter periods are required, you can try Int 15H, function 83H.
This gives about 1 millisecond resolution, if allowed by your computer.
On my computers, Windows 2000 and XP do not allow it.
MOV AX,8300H
XOR CX,CX ; CX:DX = Microsecond count.
MOV DX,10000 ; 10 milliseconds
PUSH ES ; ES:BX = user memory byte.
PUSH DS
POP ES
MOV BX,OFFSET TestTic
INT 15H
POP ES
MOV [TestTic],0 ; Zero flag byte.
DoWork:
; Insert your routine here.
CMP [TestTic],0 ; Have we used enough time to quit?
JE DoWork ; No, continue.
RET
If these will not work for you, you can program timer 2 to
generate a square wave of your choice of duration. Then
have one routine run when the timer output is high and the
other when it is low.
Regards,
Steve N.
How do I initialize this segment in the assume directive? In the first example if I want to give the procedure a time of 55 milliseconds how do I initialize this time?
something like this...
BIOSSEG SEGMENT AT 0 ;absolute Data area
ORG 46CH
ClockTic LABEL DWORD ; 55 ms timer ticks since CPU reset
BIOSSEG ENDS
.
.
.CODE
.
.
ASSUME DS:BIOSSEG
push ds
xor ax,ax
mov ds,ax
MOV AX,ClockTic
pop ds
ASSUME DS:DGROUP
MOV TestTic,AX
.
.
.
EDIT - fixed an address :bg
btw amrac - you should make your stack at least 512 bytes :bg
here is a template you can use for 16-bit programs...
.MODEL SMALL
.STACK 512
;------------------------------------------------------------------------
;libraries
;------------------------------------------------------------------------
;externals
;------------------------------------------------------------------------
;macros
;------------------------------------------------------------------------
;equates
;------------------------------------------------------------------------
;data
.CONST
;constant data
.DATA
;initialized data
Message db 'Hello World',13,10,36
.DATA?
;uninitialized data
;------------------------------------------------------------------------
;code
.CODE
_main PROC FAR
;initialize the data segment
mov ax,@DATA
mov ds,ax
;display the message
mov dx,offset Message
mov ah,9
int 21h
;terminate program
mov ax,4C00h
int 21h
_main ENDP
;------------------------------------------------------------------------
;subroutine
;------------------------------------------------------------------------
;subroutine
;------------------------------------------------------------------------
END _main
i cleaned up the file a bit and got it to assemble with no errors - now i am ready to have a look at it
i see a few PROCs with no RET :bg
today, i have some things i need to do - tomorrow we will see if we can make things move
Hi Dave,
Typo?
ASSUME DS:BIOSSEG
push ds
MOV AX,40H ; Not XOR
mov ds,ax
MOV AX,ClockTic
pop ds
ASSUME DS:DGROUP
Regards,
Steve N.
it looks ok to me Steve
ohhhhhhhhh
you access it via 40h
i always access the BIOS data segment from segment 0000
it makes no diff in the address sizes (just add 400h)
but it saves a byte by using XOR AX,AX instead of MOV AX,40h
it also allows you to access the interrupt vector table without changing segments :bg
Thanks for cleaning my file, that must have been a lot of work! About that other reply what does it mean:
ORG 46CH
Can't I just add the
ClockTic LABEL DWORD in my data segment?
Hi Dave,
Okay I see what you are doing. Oops. The references
I have differentiate between the interrupt vector segment
at 0, and the BIOS data segment at 40H. Should have
read a bit closer. Good ole habits...
Hi amrac,
No, it is a specific place in memory that is updated by
the BIOS on each timer interrupt. It is at 40:6C or 0:46C,
which address the same piece of memory, using segment:offset.
You generally load the tick count into a register, and then
store it into a variable in your data segment.
Steve
well - actually, you can place it in any segment
it is simply a label that has to have a specific offset
i don't know how well "SEGMENT AT" works with newer versions of masm, it wasn't great with older versions - lol
i think you can do it without a label at all like this.....
push ds
xor ax,ax
mov ds,ax
mov ax,ds:[46Ch]
pop ds
you shouldn't need an ASSUME directive, either
at any rate, the BIOS data segment is at 0040:0000
at offset 6Ch into that segment is the value for the clock tick (3 bytes i think)
0040:006C is the same physical address as 0000:046C
you can get it another way by using INT 1Ah (which is typically a pretty fast interrupt)
mov ah,0
int 1Ah
;clock tick is in CX:DX, max value = 1800AFh
I'm sorry I must be really stupid. The thing is, I already have a data segment and I can´t have two data segments. So what are the necessary modifications that I have to make to make things work? I'm sorry to ask this again but I didn't really understand.
well - the term "data segment" can be used in different context
in a broader definition, it might be any segment where you read or write data, including the video buffer
in a narrower definition, it is a specific section of an executable program
in this case, the BIOS code uses the area from 0040:0000 to 0040:00FF - that area is refered to as the "BIOS data segment"
a variety of low-level information is kept there
there are locations that hold the I/O addresses of serial and parallel ports
the keyboard buffer is in there, the amount of memory, and so on
a program can access the information, even though it is not really a data segment of that program
as for your program, you can have more than one data segment
it just isn't needed for most small programs because you do not have more than 64 Kb of data
the only stupid questions are the ones that aren't asked - lol
Hi,
As Dave says, you can have many segments in your
program. Normally you will have one data segment for a
small program. I defined "ClockTic" as a location in the
BIOS data segment, as that was a way I like. Dave has
showed how to access that location without a segment
declared in a SEGMENT directive. If you want to have
more than one data segment, you declare them with
different names.
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Set up the code definitions the operating system wants. Data segment:
DATASEG SEGMENT PUBLIC
...
DATASEG ENDS
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Set up the code definitions the operating system wants. Data segment 2:
EXTRASG SEGMENT PUBLIC
...
EXTRASG ENDS
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Set up the code definitions the operating system wants. Data segment 3:
MORESEG SEGMENT PUBLIC
...
MORESEG ENDS
You can specify the BIOS data segment and the video
display segment in SEGMENT AT directives to give them
names, or just set the segment register directly. If using
a name makes things clearer, use that. If the extra level
of indirection is confusing, then just set the registers as
needed.
A minor "advantage" of using the SEGMENT way of doing
things, is that you then have to use the ASSUME directive to
tell MASM what is going on, or it will generate an error message.
That is either extra work, or a way to check that you have
correctly set the segment registers.
So an amendment/correction to my code snippit.
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BIOSSEG SEGMENT AT 40H ; BIOS Data area
ORG 6CH
ClockTic LABEL DWORD ; 55 ms timer ticks since CPU reset
BIOSSEG ENDS
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PUSH DS ; Save data segment pointer.
MOV AX,SEG BIOSSEG
MOV DS,AX ; Point data references to the BIOS.
ASSUME DS:BIOSSEG ; And tell MASM what we are doing.
MOV AX,WORD PTR [ClockTic]
POP DS ; Restore data segment, so we can access our data.
ASSUME DS:MYDATA ; Use the name you have set up.
MOV [TestTic],AX
DoWork:
; Insert your routine here.
PUSH DS
MOV AX,SEG BIOSSEG
MOV DS,AX
ASSUME DS:BIOSSEG
MOV AX,WORD PTR [ClockTic]
POP DS
ASSUME DS:MYDATA
CMP [TestTic],AX ; Have we used enough time to quit?
JE DoWork ; No, continue.
RET
A side note: van Gilluwe in "The Undocumented PC" says
that the Int 1aH function 0 should be used only by the OS.
This is because if it is used, it clears the "24-hour overrun
flag", and if you manage to do that, instead of the os doing
it, you have caused the OS to lose a day. Seems unlikely?
Regards,
Steve N.
Edit: Fix dumb error...
SRN
you're absolutely right about the rollover flag, Steve
i had never thought much about it - always ignored the flag
that means there is a lot of broken software out there - lol
of course, you can set the flag at 0040:0070, but, if you are doing that, you may as well get the tick count from 006C :bg
amrac,
As a test I threw together an app that does what I think you are describing. I ended up with ~200 lines of code, not including the comments, blank lines, etc. While I am not going to post the complete source, the attachment does contain the EXE. I tested only under Windows 2000, where the app had to be run full-screen. There is only one ball in flight at a time. For the ball paths the x coordinates are random. I set the ball animation speed so it starts out slow, and then speeds up every 10 balls, to the point of becoming completely unplayable in the vicinity of 50 balls. Under DOS or Windows 9x the animation speed should be about 1/3 of what it is under Windows NT/2000/XP. Use the left and right cursor-control keys to move the paddle. The ball number is displayed in the upper-left corner and the current score in the upper-right corner. Intercepting a ball with the paddle will increment the score, and missing it will decrement the score. Press Escape to exit at any time.
In case you are not already aware of the feature of the Interrupt 10h, Function 0Ch that allows it to XOR the pixel onto the screen, I included a demo app.
amrac - i was playing around with some code
at the same time, thinking about what the best approach to your problem is BigGrin
i think the best way to go might be to write your own keyboard driver
the keyboard, by design, sends a signal whenever a key is pressed and again when it is released
the BIOS driver converts this into scan codes and key codes and handles the repeat delay and rate - all that
the repeat delay and rate are not desirable for what you want to do
i have done this kind of thing in the past (many years ago - lol)
it is a bit involved - but, i can do it again
the thing is - it will take me some time
right now, i had promised Zulfi i would work on a boot-sector for him
(another little thing i have wanted to do for a long time)
let me take care of that project, then come back to this one
that will give me some time to toss it around in my head for a while and let it ferment BigGrin
in the mean time, i wrote this little quicky demo for video mode 13h that you might like
when we employ a keyboard driver, we may want to use that mode to get 256 colors ThumbsUp
oh - press any key to exit the program
then, you can use Alt-Enter to toggle between full-screen and normal dos window
i like it Michael :U
it looks like the makings of single-player pong, breakout, centipede or even space invaders - lol
i don't know what he has in mind when the ball hits the paddle
i don't know how many hours i spent playing "Digger" - a DigDug knockoff :P
(http://blog.photos2view.com/files/07-07-digger.gif)
Hi Michael
Yes, that's exactly what I'm looking for. Thanks!
Hi dedndave
Thanks for the file I liked it. I think I have the solution for my problem. I have to join the procedures altogether. I have to put the little balls falling and wait for the user to press the keys at the same time. I really don't want you to waist time with my project because I think I have the solution. I don't know if I'm going to find another problem because I'm going to try this other way of solving my problem. But anyway, thanks a lot! :U
yes - you should be able to have a routine for each, then service them in "round robin" fashion
i.e. a loop where you call the keyboard routine, call the paddle routine, call the ball routine, then start at the top of the loop again
I've solved the problem and now I have another problem that has to do with preserving the values of registers.
My procedure is working like this:
-determine the column for the ball
-if the ball didn't rich the bottom
-1(true)make the ball fall
-2(true)draw the rectangle
-3(true)make the ball fall
-4(true) wait for a pressed key
-(false)determine the column of the ball
But the problem is that the first time the ball falls it falls correctly. The second time it falls, it jumps from one column to another. That is, it falls till the middle of the screen and then jumps to another column. And it falls always in the same columns (two columns alternately). And I know that the code that makes the balls fall randomly in several columns, work because I've already tested it. This means that it is getting the value for the column from some other procedure. My code that generates the columns randomly is:
push ax
push bx
push dx
push cx
mov quedas,180
mov ah,2ch ;para ir buscar as centésimas de segundo
int 21h
sub dh,dh
mov ax,dx ;para fazer a multiplicação do valor por ah
mov cx,0ah
mul cx
;mov aleatorio, ax ;guarda os centesimos de segundo em aleatorio
;o resultado da multiplicação está em ax
;o resto fica em dx
;vai dividir ax por 2bch
mov bx,2bch
div bx
cmp dx,12ch ;verificar se o resto da divisao é maior q 300
jg maior
maior: mov coluna,12ch ; se o resto da divisao for maior que 300 retorna a coluna 300
mov coluna,dx ;poe o resto da divisao na coluna
pop cx
pop dx
pop bx
pop ax
Aren't those pushes enough to preserve the values of the registers? How to procede to preserve correctly the values of the registers?
hiya amrac
first - this code can be simplified a little bit...
sub dh,dh
mov ax,dx ;para fazer a multiplicação do valor por ah
mov cx,0ah
mul cx
MOV DH,0 is as small as SUB DH,DH
you might use that on a word register to make the code 1 byte smaller
MOV DX,0 is 3 bytes - SUB DX,DX is 2 bytes
but, just put 10 into the AL register and multiply it by DL - the result will be in AX, CX and DX won't be affected...
mov al,10
mul dl
as for the column jump, the code modifies the "coluna" value, whether the registers are pushed or not
maior: mov coluna,12ch ; se o resto da divisao for maior que 300 retorna a coluna 300
mov coluna,dx ;poe o resto da divisao na coluna
that code doesn't make sense :bg
Quote from: dedndave on January 12, 2010, 12:21:24 PM
as for the column jump, the code modifies the "coluna" value, whether the registers are pushed or not
maior: mov coluna,12ch ; se o resto da divisao for maior que 300 retorna a coluna 300
mov coluna,dx ;poe o resto da divisao na coluna
that code doesn't make sense :bg
I've runned this code and it runs fine. Sometimes I get a value in dx which is bigger than 12ch and in that case I want the value in coluna to be 12ch. That's because I want the ball to fall only in the left most 300 columns.
But I still don't know what is the right manner to preserve the registers in the procedures. That I think is the problem of my code. The random column code is running fine in another program without the rectangle.
it looks like this code is used to generate a random column number for a new ball to drop
if it is causing the ball to jump columns, it is because it is being executed before the ball hits the last row
perhaps you are trying to have more than one ball at a time ?
i don't know, as i can't see the rest of the code :P
if you want to replace that code with something a little nicer, try this code...
mov quedas,180 ;falls = 180
push ax
push bx
push dx
push es
xor ax,ax
mov es,ax
les ax,es:[46Ch]
mov dx,es
mov bx,301
div bx
mov coluna,dx
pop es
pop dx
pop bx
pop ax
one problem that your code has is something like this...
a new random column is selected from a range of 0 to 699
if it is over 300, you set it to the limit value of 300
the problem is - it will be 300 more often than any other value
just divide by 301 - the remainder can never be more than 300 :U
Hi dedndave
Thanks for your reply.
I've copied you're code and run it and the result is exactly the same. The ball falls and then jumps to another column. This only confirms what I suspected. I'm not preserving the registers the right way in another procedure.
One question. What does this code do:
les ax,es:[46Ch]
LES is really just a shortcut
i wanted to load the timer value from 0000:046C, which is a dword
LES AX,xxxx gets the dword, low order word into AX, high order word into ES
then, i put the high order word into DX, where i wanted it
you could do the same thing with this code...
mov ax,es:[46Ch]
mov dx,es:[46Eh]
put your asm file into a zip
below the reply window is a link for Additional Options...
click that, and attach the zip file
i will look at the entire code and see if i can spot the problem :U
come to think of it, this code is one byte shorter because there is no segment override :bg
mov quedas,180 ;falls = 180
push ax
push bx
push dx
push ds
xor ax,ax
mov ds,ax
lds ax,ds:[46Ch]
mov dx,ds
mov bx,301
pop ds
div bx
mov coluna,dx
pop dx
pop bx
pop ax
LDS is similar to LES, except it uses the DS register instead of ES
I've copied you're code and run it and the result is still exactly the same. The ball falls and then jumps to another column. I don't want to be dull but I think I'm not preserving the registers the right way in another procedure.
I still don't understand that line of code:
lds ax,ds:[46Ch]
put your ASM file into a ZIP file
below the reply window is a link for Additional Options...
click that, and attach the ZIP file
i will look at the entire code and see if i can spot the problem
lds ax,ds:[46Ch]
that line of code is the same thing as
mov ax,ds:[46Ch]
mov ds,ds:[46Eh]
LDS stands for Load DS
LDS AX,[nnnn] loads DS and AX at the same time from the dword addressed by [nnnn]
it could be a label like SomeDwordPointer
LDS AX,SomeDwordPointer
you might see it used with SI
LDS SI,SomeDwordPointer
http://www.arl.wustl.edu/~lockwood/class/cs306/books/artofasm/Chapter_6/CH06-1.html#HEADING1-102
Hi
Here goes my code.
hiya amrac
i am looking at the "pixel" proc
i think there is something wrong with the way the count is kept
let me play with it a little bit....