0
org 0x7c00  
jmp _main

; _data:
playerPosition dw 0
; %1 == coluna (x)
; %2 == linha (y)
%macro drawRacket 2
    
    mov ah, 0ch ; print pixels mode
    mov dx, %2

    for1:
        mov bx, 32 ;racket height 
        add bx, %2
        cmp dx, bx  ; racket end (row)
        je .fim1
        mov cx, %1  ; racket beggining (column)
        jmp .for2
        jmp for1

        .fim1:
        jmp mainLoop

        ; loop to draw each line
        .for2:
        mov bx, 8 ;racket width
        add bx, %1
        cmp cx, bx   ;
        je .fim2
        mov al, 0x0f
        mov ah, 0ch
        int 10h
        inc cx
        jmp .for2

        .fim2:
        inc dx
        jmp for1

%endmacro


_main:
    ; 
    xor ax, ax
    mov ds, ax
    mov cx, ax
    mov dx, ax

    call setVideoMode

    ;racket initial position
    mov word[playerPosition], 10

    mainLoop:

        mov ah, 01h
        int 16h

        cmp al, 115
        je moveDown
        jmp mainLoop
    


jmp $

; 
setVideoMode: 
    mov ah, 0       ; 
    mov al, 13h     ;
    int 10h
ret

 moveDown:
     drawRacket 10, word[playerPosition]
     mov ax, word[playerPosition]
     inc ax
     mov word[playerPosition], ax
 jmp mainLoop


times 510-($-$$) db 0
dw 0xaa55

That's the assembly code. I am trying to make a "Pong game", and I am at the very beggining. I was trying to draw the 1st player's racket, but it is not working. When I press "s" (mainLoop function) on the keyboard, it actually works and jumps to the macro drawRacket and draws it. But, if I press "s" again nothing works.. I already tried to change a lot of things on the mainLoop function but nothing works, what makes me think that I have some problems with the macro drawRacket. I would appreciate any hints or answers.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Deepak C
  • 33
  • 5
  • 2
    You might want to see [this answer](https://stackoverflow.com/questions/58822549/int-16h-ah-1-repeatedly-gives-the-same-key-press-even-after-user-presses-another). `int 16h` function `01` tests for a keystroke, but doesn't remove it from the buffer. – sj95126 Aug 03 '22 at 18:20
  • Or see this [another answer](https://stackoverflow.com/questions/71115361/bios-keyboard-input-only-reading-2-letters-loop-not-working/71117191#71117191) to a similar problem. – vitsoft Aug 03 '22 at 18:28
  • 2
    Also: your macro defines a label `foo`. There can only be one label with this name in your program. Consider using a local label instead. Also, what assembler are you programming for? – fuz Aug 03 '22 at 18:40
  • @fuz I am programming for NASM. Thanks for the hint – Deepak C Aug 03 '22 at 18:44
  • @sj95126 Thank you for the hint. That should be fine, I just would like to know why it doesn't print the racket below the first one when I press "s" – Deepak C Aug 03 '22 at 18:45
  • 1
    Note that you don't actually *jump* to the macro, it gets expanded at the place you use it. But I guess you mean when you single-step, your debugger shows execution in the source code of the macro? When you single-step with a debugger (e.g. in Bochs), what happens on later keypresses? What's the path of execution? That's an important part of a [mcve]. – Peter Cordes Aug 03 '22 at 23:16

1 Answers1

2

But, if I press "s" again nothing works..

Regardless of the keyboard issue about using function 01h instead of function 00h, your macro does get its second invokation and draws the racket a second time, but it does so exactly where the first racket was drawn. You don't see anything moved, that way! (For the sensation of true movement you would have to remove the first racket (partially) before drawing the second racket (partially)).

The reason is that the macro's execution stops with a jmp mainLoop. This bypasses your code that increments the playerPosition variable. The quick solution is to place the .fim1 label near the bottom of the macro.

%macro drawRacket 2
        mov     ah, 0Ch
        mov     dx, %2

        ...

    .fim2:
        inc     dx
        jmp     .for1

    .fim1:                            ; New position!
%endmacro

Now the macro code will fall through in the code that increments Y. This happens because of how macro's work. In your program the line drawRacket 10, word[playerPosition] gets replaced by all the code you have between the tags %macro drawRacket 2 and %endmacro. This process is called macro expansion.
The expanded version looks like this:

moveDown:
        mov     ah, 0Ch              ; \
        mov     dx, [playerPosition] ;  \
                                     ;   \
        ...                          ;    \
                                     ;      The expanded macro code   
    drawRacket.fim2:                 ;    /
        inc     dx                   ;   /
        jmp     drawRacket.for1      ;  /
    drawRacket.fim1:                 ; /
        mov     ax, [playerPosition]
        inc     ax
        mov     [playerPosition], ax
        jmp     mainLoop

The keyboard function 01h checks to see if a key is available and reports about the fact. You receive a preview of the key in AX, and the key is not removed from the keybuffer. Next time your code uses this keyboard function 01h, you still get the preview of that same key, even if you pushed another key on the keyboard.
Your program just needs to wait for a key and act upon it. Use the keyboard function 00h that does exactly that.

mov     ah, 00h   ; BIOS.GetKeyboardKey
int     16h       ; -> AL is ASCII, AH is scancode
Sep Roland
  • 33,889
  • 7
  • 43
  • 76