I am working on an assignment for univesity, we need to create a simple breakout / arkanoid clone, everything will be fine, but I found an error that will delete everything on the screen, this error is random, but I suspect it is due to my DrawPaddle function. Perhaps you may find a bug or find out why video memory does this.
The game must be executed with a 16-bit ms-dos build, I use NASM + VAL + Dosbox to create it, I will compile it with
nasm -f obj test.asm
val test.obj
The game simply moves the paddle on a fixed screen using the keyboard arrows, you can also exit the game by pressing the escape button.
This time, while everything is in order: https://puu.sh/yeKtG/affc912d4b.png , and it looks like when the program overflows: http://puu.sh/yeKEy/caeef089d1.png or http: // puu .sh / yeKJH / 1106e1e823.png
I noticed that strange behavior only occurs when the paddle is moved, and this will happen by accident, for example, now that I have deleted almost everything else from the program, it may take several attempts to get an error.
This is the code of DrawPaddle:
DrawPaddle:
push di
mov di, [paddleposition]
mov cx, 5 ;the paddle will be 5 pixels tall
.p0:
push cx
mov cx, paddlesize
.p1:
mov byte [es:di], bl
inc di
loop .p1
add di, screenweight - paddlesize
pop cx
loop .p0
pop di
ret
And this is the full code, it uses a keyboard handler to read input and will write directly to video memory using 320x200x256.
BITS 16
stacksize EQU 0200h
;Constantes
;Direccion de inicio de la memoria de video
videobase EQU 0a000h
;Definicion de colores
black EQU 0
green EQU 00110000b
;Screen data
screenweight EQU 320
;Paddle data
startx EQU 140
starty EQU 170
paddlesize EQU 40
paddlecolor EQU 00101010b
;Paddle movement limits
leftlimit EQU starty * screenweight + 1 + 10 + 1
rightlimit EQU ((starty + 1) * screenweight) - paddlesize - 10 - 1
segment mystack stack
resb stacksize
stacktop:
segment mydata data
;Variables
escpressed dw 0
leftpressed dw 0
rightpressed dw 0
oldintseg resw 1
oldintoff resw 1
originalVideoMode resb 1
paddleposition resw 1
segment mycode code
;Subrutinas
KeybInt:
push ds ;guardamos ds:ax
push ax
mov ax, mydata ;los re-inicializamos
mov ds, ax
cli
.getstatus:
in al, 64h
test al, 02h
loopnz .getstatus ;esperando a que el puerto estΓ© listo
in al,60h ;obtenemos el codigo make o break de la tecla leida
cmp al, 01h ;revisamos si es escape
jne .revEsc
mov word [escpressed], 1
jmp .kbread
.revEsc:
cmp al, 81h ;revisamos si el escape fue soltado
jne .revIzq
mov word [escpressed], 0
jmp .kbread
.revIzq:
cmp al, 4bh ;revisamos si es la flecha izquierda
jne .revDer
mov word [leftpressed], 1
jmp .kbread
.revDer:
cmp al, 4dh ;revisamos si es la flecha derecha
jne .revIzq2
mov word [rightpressed], 1
jmp .kbread
.revIzq2:
cmp al, 0cbh ;si se solto la flecha izquierda
jne .revDer2
mov word [leftpressed], 0
jmp .kbread
.revDer2:
cmp al, 0cdh ;o la derecha
jne .kbread
mov word [rightpressed], 0
jmp .kbread
.kbread:
in al, 61h
or al, 10000000b
out 61h, al
and al, 01111111b
out 61h, al
mov al, 20h
out 20h, al
sti
pop ax ;recuperamos ds:ax
pop ds
iret
DrawStage:
push di
push bx
;movemos el cursor a la posicion 10,10
;que seria en realidad 10*320+10
mov di, (10 * screenweight) + 10
;ahora repetiremos esto 320-20 veces
mov cx, 300
.h1:
mov byte [es:di], green
inc di
loop .h1
mov di, (190 * screenweight) + 10
;ahora repetiremos esto 320-20 veces
mov cx, 301
.h2:
mov byte [es:di], green
inc di
loop .h2
;ahora volveremos al primer punto
;y dibujaremos hacia abajo
mov di, (10 * screenweight) + 10
;y lo repetiremos 200-20 veces
mov cx, 180
.v1:
mov byte [es:di], green
add di, screenweight
loop .v1
mov di, (10 * screenweight) + 310
mov cx, 180
.v2:
mov byte [es:di], green
add di, screenweight
loop .v2
pop bx
pop di
ret
;Rutina para dibujar el palo
;Recibe en bl el color del mismo
DrawPaddle:
push di
mov di, [paddleposition]
mov cx, 5 ;the paddle will be 5 pixels tall
.p0:
push cx
mov cx, paddlesize
.p1:
mov byte [es:di], bl
inc di
loop .p1
add di, screenweight - paddlesize
pop cx
loop .p0
pop di
ret
Delay1:
mov dx, 4
sub dx, 3
.pause1:
mov cx, 6000
.pause2:
dec cx
jne .pause2
dec dx
jne .pause1
ret
..start:
mov ax, mydata
mov ds, ax
mov ax, mystack
mov ss, ax
mov sp, stacktop
;guardando el manejador actual
mov ah, 35h
mov al, 9h
int 21h
mov [oldintseg], es
mov [oldintoff], bx
;instalando el manejador nuevo
mov ax, mycode
mov es, ax
mov dx, KeybInt
mov ax, cs
mov ds, ax
mov ah, 25h
mov al, 9h
int 21h
;restaurando el segmento de datos
mov ax, mydata
mov ds, ax
;guardando el modo de video y aplicando el nuevo
xor ax, ax
mov ah, 0fh
int 10h
mov [originalVideoMode], al
mov ah, 00h
mov al, 13h
int 10h
;coordenada de inicio para el palo
mov ax, (screenweight * starty) + startx
mov word [paddleposition], ax
mov ax, videobase
mov es, ax
call DrawStage
mov bl, paddlecolor
call DrawPaddle
jmp .main
.main:
call Delay1
;leemos las entradas
cmp word [escpressed], 1
je .dosexit
cmp word [rightpressed], 1
je .movRight
cmp word [leftpressed], 1
je .movLeft
jmp .main
.movRight:
mov bl, black
call DrawPaddle
cmp word [paddleposition], rightlimit
je .ending
inc word [paddleposition]
jmp .ending
.movLeft:
mov bl, black
call DrawPaddle
cmp word [paddleposition], leftlimit
je .ending
dec word [paddleposition]
jmp .ending
.ending:
mov bl, paddlecolor
call DrawPaddle
jmp .main
.dosexit:
;restaurando el modo de video original
mov ah, 00h
mov byte al, [originalVideoMode]
int 10h
;restaurando el manejador de teclado original
mov dx, [oldintoff]
mov ax, [oldintseg]
mov ds, ax
mov ah, 25h
mov al, 9h
int 21h
mov al, 0
mov ah, 4ch
int 21h
Thanks for reading!