Error in emulator output for pong game in assembly language

65 Views Asked by At

Pong game in assembly language

I am trying to make a small pong game for my own practice in assembly language as I'm a beginner in this area.

I'm running the code on my x86 64-bit Windows pc. I'm using DOSBox emulator to run my game and test it.

The issue I'm running into is: while trying to draw the ball for my pong game the emulator is displaying a rectangular horizontal line and I cannot fix it to make a square block.

This is the code I have written so far:

STACK SEGMENT PARA STACK
    DB 64 DUP (' ')
STACK ENDS

DATA SEGMENT PARA 'DATA'

    BALL_X DW 0Ah        ;current X position (column) of the ball
    BALL_Y DW 0Ah        ;current Y position (line) of the ball
    BALL_SIZE DW 04h     ;size of the ball (how many pixels does the ball have in width and height)


DATA ENDS

CODE SEGMENT PARA 'CODE'

    MAIN PROC FAR
    ASSUME CS:CODE,DS:DATA,SS:STACK ;assume as code, data and stack segments the respective registers
        PUSH DS         ; Push the DS segment to the stack
        SUB AX, AX      ; Clean the AX register
        PUSH AX         ; Push AX to the stack
        MOV AX, DATA    ; Load the DATA segment into AX
        MOV DS, AX      ; Set DS to the DATA segment
        POP AX          ; Release top item from stack
        POP AX          ; Release top item from stack
        
        MOV AH, 00h     ; Set the video mode configuration
        MOV AL, 13h     ; Choose the video mode (320x200 256-color VGA mode)
        INT 10h         ; Execute the configuration
       
        MOV AH, 0Bh     ; Set the background color
        MOV BH, 00h     ; Page number (usually 0)
        MOV BL, 00h     ; Choose black as the background color
        INT 10h         ; Execute the configuration

        CALL DRAW_BALL
        
        RET
    MAIN ENDP   

       
    DRAW_BALL PROC NEAR
    
       MOV CX,BALL_X ;set the column (X)
       MOV DX,BALL_Y ;set the line (Y)
       
    DRAW_BALL_HORIZONTAL:
        MOV AH,0Ch ;set configuration to writing a pixel
        MOV AL,0Fh ;set pixel color white
        MOV BH,00h ;set the page number
        INT 10h ;exec the config

        INC CX ;CX = CX+1
        MOV AX,CX ;CX - BALL_X > BALL_SIZE (Y-> We go to the next line, N-> We continue to the next column)
        SUB AX,BALL_X
        CMP AX,BALL_SIZE
        JNG DRAW_BALL_HORIZONTAL 

        MOV CX,BALL_X ;the CX register goes back to initial column
        INC DX ;DX = DX + 1


        MOV AX,DX ;DX - BALL_Y > BALL_SIZE (Y-> We got to the next line, N-> We continue to the next column)
        SUB DX,BALL_Y
        CMP AX,BALL_SIZE
        JNG DRAW_BALL_HORIZONTAL

    RET   
    DRAW_BALL ENDP

CODE ENDS

The code for the ball is written in DRAW_BALL_HORIZONTAL.

I have tried different iterations to fix it to represent a square block but I'm still not able to do it.

What seems to be the issue here? How do I fix it?

3

There are 3 best solutions below

0
Nassau On

I changed last part of draw_ball proc to this code:

    mov ax,dx
    mov bx,BALL_Y   
    add bx,10
    cmp dx,bx        
    jng DRAW_BALL_HORIZONTAL

and it worked. Because ball_y is the first line where code starts to draw ball and drawing should end at ball_y + 10.

0
vitsoft On

Using interrupt for each pixel in VGA mode 13h will make it unacceptably slow; its better to write directly to the videomemory located at segment address A000h. Also program format COM is better for beginners, as you don't have to bother with stack and segment register initialization.

I tried to write your assignment using €ASM, assembled it with euroasm.exe Ayxux.asm and it works as expected.

Ayxux PROGRAM Format=COM
        MOV AH, 00h     ; Set the video mode configuration
        MOV AL, 13h     ; Choose the video mode (320x200 256-color VGA mode).
        INT 10h         ; Execute the configuration
        MOV AX,0A000h
        MOV ES,AX        ; Let ES address videomemory
        CALL DRAW_BALL
        MOV AH,0
        INT 16h           ; Wait for keypress.
        MOV AX,0003h
        INT 10h           ; Restore text video mode 80*25 before termination.
        RET               ; Return to DOS.

DRAW_BALL PROC            ; Calculate address of the ball: DI=320*BALL_Y + BALL_X
       MOV AX,320         ; Size of one videoline.
       MUL [BALL_Y]
       ADD AX,[BALL_X]
       MOV DI,AX
       MOV AL,[BALL_COLOR]
       MOV BX,[BALL_SIZE]
       MOV DX,BX          ; Initialize row counter DX.
  DRAW_BALL_HORIZONTAL:
       MOV CX,BX          ; Initialize column counter CX.
       REP STOSB          ; Store CX pixels with color AL to videomemory at ES:DI, increment DI.
       SUB DI,BX          ; Return the pointer back to initial column.
       ADD DI,320         ; Point at the next row.
       DEC DX
       JNZ DRAW_BALL_HORIZONTAL ; The next ball row.
       RET
     ENDP DRAW_BALL

BALL_X     DW 0Ah          ;current X position (column) of the ball
BALL_Y     DW 0Ah          ;current Y position (line) of the ball
BALL_SIZE  DW 04h          ;size of the ball (how many pixels does the ball have in width and height)
BALL_COLOR DB 0Fh          ; Pixel color 0..255.
    ENDPROGRAM Ayxux
0
Sep Roland On

Issue 1

STACK SEGMENT PARA STACK
    DB 64 DUP (' ')
STACK ENDS

64 bytes is too little for a stack, and certainly if you're using BIOS functions. I suggest 512 bytes.

Issue 2

PUSH DS         ; Push the DS segment to the stack
SUB AX, AX      ; Clean the AX register
PUSH AX         ; Push AX to the stack
...
POP AX          ; Release top item from stack
POP AX          ; Release top item from stack

You'll need to remove these pop's. The two items that were pushed on the stack are essential for your .EXE program to be able to exit to DOS using the single ret (far) instruction.

Issue 3

INC CX
MOV AX,CX
SUB AX,BALL_X
CMP AX,BALL_SIZE
JNG DRAW_BALL_HORIZONTAL

The famous one-off error! This will produce 5 pixels in contrast to the BALL_SIZE being equal to 4. Simply write:

JB  DRAW_BALL_HORIZONTAL

Issue 4

MOV CX,BALL_X ;the CX register goes back to initial column
INC DX ;DX = DX + 1
MOV AX,DX
SUB DX,BALL_Y         <<< typo
CMP AX,BALL_SIZE
JNG DRAW_BALL_HORIZONTAL

The same one-off error, but this time aggravated by a typo! The sub needs to subtract from the temporary register AX.

MOV AX,DX
SUB AX,BALL_Y
CMP AX,BALL_SIZE
JB  DRAW_BALL_HORIZONTAL

Issue 5

MOV AH, 0Bh     ; Set the background color
MOV BH, 00h     ; Page number (usually 0)
MOV BL, 00h     ; Choose black as the background color
INT 10h         ; Execute the configuration

This is redundant code. Having set up the 320x200 256-color graphics mode 13h, the background already defaults to black.