Author Topic: Pong in Assembly  (Read 21581 times)

0 Members and 1 Guest are viewing this topic.

Offline Phoenix

  • C= 64
  • **
  • Posts: 99
  • Karma: 4
    • View Profile
Pong in Assembly
« on: September 22, 2007 »
I'm attempting to create pong, in FASM. Maybe it seems quite pointless, but I want to brush my assembly skills. So far, I have been progressing quite well, until I wanted to add movement. When the I press the up key, y1 is increased, but the paddle doesn't move. Instead, a colored dot appears at the top of the screen. This dot also comes if I change y1 to, well any variable I have defined. My guess is that I'm accessing the video memory at some place where I shouldn't be doing it, but I'm unsure where. Good news though, is that nowadays I comment my code ;)
Code: [Select]
; ASM Pong
; By Phoenix September 22, 2007
org 100h                       ; COM

mov al, 13h                    ; Set up 13h resolution (320x200 256 colors)
int 10h                        ; Change to the resolution
mov ax, 0a000h                 ; 0a000h = Video memory start
mov ds, ax                     ; Move ds to the 0a000h

Render:     mov cx, 30         ; Reset the height counter
            mov bx, 0
            jmp DrawPaddle     ; Draw the first rectangle

Update:     mov bh, 0
            mov ah, 00         ; Prepare for key input
            int 16h            ; Check for input, stores it in ah
            cmp ah, 48h        ; Was it the 'up' key?
            je MoveLeft        ; If so, move!
            cmp ah, 01         ; Was it escape?
            jne Render         ; If not, then just continue to playing

mov ax, 4c00h                  ; Prepare for exit
int 21h                        ; Exit

DrawPaddle: mov ax, 320        ; Start of with the screen width in the coordinate formula
            mov bx, y1         ; Set up the next parameter in the multiplication; y value
            add bx, cx         ; Add the current vertical position to the multiplication
            mul bx             ; Calculate!
            add ax, x1         ; Add the x position to the final product
            mov si, ax         ; Set the drawing position, screen coordinates described as ScreenWidth*y+x
            mov al, 255        ; Color 255 in the default palette (White)
            mov [si], al       ; Poke the pixel into memory

            loop DrawPaddle    ; Loop until cx (rectangle height counter) is 0
            jmp Update         ; Then go back to the main loop

MoveLeft:   inc [y1]
            jmp Render         ; Go back to the main loop


; Variables
x1 db 10                       ; Player 1's x
x2 db 160                      ; Player 2's y
y1 db 100                      ; Player 1's x
y2 db 100                      ; Player 2's y
rectLoop db 0

scoretext db "              Score: $" ; The text that goes before the score, centered using spaces
score1 db "0$"                        ; Player 1's score
dash db "-$"                          ; Dash separating scores
score2 db "0$"                        ; Player 2's score

Why am I experiencing this weird behavior? How do I fix it?

Many many thanks in advance,
Martin :)

Offline Stonemonkey

  • Pentium
  • *****
  • Posts: 1315
  • Karma: 96
    • View Profile
Re: Pong in Assembly
« Reply #1 on: September 22, 2007 »
You're variables are bytes but instructions like:

mov bx, y1

will load 2 bytes into the bx reg. And I had to change the colour, i tried 25 instead of 255.

can't seem to get it working with the x position and there's still a pixel that changes colour near the top.

« Last Edit: September 22, 2007 by Stonemonkey »

Offline Stonemonkey

  • Pentium
  • *****
  • Posts: 1315
  • Karma: 96
    • View Profile
Re: Pong in Assembly
« Reply #2 on: September 22, 2007 »
Aha, the flashing pixel is because it's addressing that byte of screen memory instead of the y1 variable and when you press the up arrow it's incrementing the value in that.

Offline Phoenix

  • C= 64
  • **
  • Posts: 99
  • Karma: 4
    • View Profile
Re: Pong in Assembly
« Reply #3 on: September 22, 2007 »
Aha, that's the problem. I'll change the code and see if I can get it working. Thanks :)

Edit: But how am I supposed to increase y1 if I can't type inc [y1]?
« Last Edit: September 22, 2007 by Phoenix »

Offline Stonemonkey

  • Pentium
  • *****
  • Posts: 1315
  • Karma: 96
    • View Profile
Re: Pong in Assembly
« Reply #4 on: September 22, 2007 »
inc byte [y1]

Offline Phoenix

  • C= 64
  • **
  • Posts: 99
  • Karma: 4
    • View Profile
Re: Pong in Assembly
« Reply #5 on: September 22, 2007 »
The dot still flashes that way :-\

Edit: Updated code, with screen clearing:
Code: [Select]
; ASM Pong
; By Phoenix September 22, 2007
org 100h                       ; COM

mov al, 13h                    ; Set up 13h resolution (320x200 256 colors)
int 10h                        ; Change to the resolution
mov ax, 0a000h                 ; 0a000h = Video memory start
mov ds, ax                     ; Move ds to the 0a000h

Main:       mov cx, 65535      ; Start the counter at the end of the screen
            mov al, 0          ; Set the color to black
            jmp ClearScreen    ; Clear the screen
Render:     mov cx, 30         ; Reset the height counter
            mov bx, 0
            jmp DrawPaddle     ; Draw the first rectangle
Update:     mov bh, 0
            mov ah, 00         ; Prepare for key input
            int 16h            ; Check for input, stores it in ah
            cmp ah, 48h        ; Was it the 'up' key?
            je MoveUp          ; If so, move!
            cmp ah, 01         ; Was it escape?
            jne Main           ; If not, then just continue to playing

mov ax, 4c00h                  ; Prepare for exit
int 21h                        ; Exit

DrawPaddle: mov ax, 320        ; Start of with the screen width in the coordinate formula
            mov bl, [y1]       ; Set up the next parameter in the multiplication; y value
            add bx, cx         ; Add the current vertical position to the multiplication
            mul bx             ; Calculate!
            add al, [x1]       ; Add the x position to the final product
            mov si, ax         ; Set the drawing position, screen coordinates described as ScreenWidth*y+x
            mov al, 255        ; Color 255 in the default palette (White)
            mov [si], al       ; Poke the pixel into memory

            loop DrawPaddle    ; Loop until cx (rectangle height counter) is 0
            jmp Update         ; Then go back to the main loop

MoveUp:     inc byte [y1]
            jmp Main           ; Go back to the main loop

ClearScreen: mov si, cx        ; Set the position to clear
             mov [si], al      ; Clear that pixel
             loop ClearScreen  ; Go to the next pixel
             jmp Render        ; Return to the main loop

; Variables
x1 db 10                       ; Player 1's x
x2 db 160                      ; Player 2's y
y1 db 100                      ; Player 1's x
y2 db 100                      ; Player 2's y

scoretext db "              Score: $" ; The text that goes before the score, centered using spaces
score1 db "0$"                        ; Player 1's score
dash db "-$"                          ; Dash separating scores
score2 db "0$"                        ; Player 2's score

Offline Stonemonkey

  • Pentium
  • *****
  • Posts: 1315
  • Karma: 96
    • View Profile
Re: Pong in Assembly
« Reply #6 on: September 22, 2007 »
Yup, since you've changed the data segment register it's looking in the wrong place for your variables. I'm not sure what the best way to deal with that is but what I've done is this when drawing the paddle:

first set up the registers and do the calculations so the registers hold the data to draw the paddle
push the DS
load the offset for the screen memory into DS
draw the paddle
pop the original value back into DS

And not to load the offset at the start of the code.

Offline Phoenix

  • C= 64
  • **
  • Posts: 99
  • Karma: 4
    • View Profile
Re: Pong in Assembly
« Reply #7 on: September 22, 2007 »
The dot isn't showing up now :) But the paddle won't react when I push the up key, I must be doing something wrong.
Code: [Select]
; ASM Pong
; By Phoenix September 22, 2007
org 100h                       ; COM

mov al, 13h                    ; Set up 13h resolution (320x200 256 colors)
int 10h                        ; Change to the resolution

Main:       push ds            ; Store the data segment's position on the stack, so we can get it back later
            mov ax, 0a000h     ; 0a000h = Video memory start
            mov ds, ax         ; Move ds to the 0a000h
            mov cx, 65535      ; Start the counter at the end of the screen, so we can loop through all pixels
            mov al, 0          ; Set the color to black
            jmp ClearScreen    ; Clear the screen
Render:     mov cx, 30         ; Reset the height counter, making the paddle 30px high
            jmp DrawPaddle     ; Draw the first rectangle
Update:     pop ds             ; Return the old data segment to non-video memory
            mov ah, 0          ; Prepare for key input, 0=read a key
            int 16h            ; Check for input, stores it in ah
            cmp ah, 48h        ; Was it the 'up' key?
            je MoveUp          ; If so, move!
            cmp ah, 01         ; Was it escape?
            jne Main           ; If not, then just continue to playing

mov ax, 4c00h                  ; Prepare for exit
int 21h                        ; Exit

DrawPaddle: mov ax, 320        ; Start of with the screen width in the coordinate formula
            mov bl, [y1]       ; Set up the next parameter in the multiplication; y value
            add bx, cx         ; Add the current vertical position to the multiplication
            mul bx             ; Calculate!
            add al, [x1]       ; Add the x position to the final product
            mov si, ax         ; Set the drawing position, screen coordinates described as ScreenWidth*y+x
            mov al, 255        ; Color 255 in the default palette (White)
            mov [si], al       ; Poke the pixel into memory

            loop DrawPaddle    ; Loop until cx (rectangle height counter) is 0
            jmp Update         ; Then go back to the main loop

MoveUp:     inc byte [y1]
            jmp Main           ; Go back to the main loop

ClearScreen: mov si, cx        ; Set the position to clear
             mov [si], al      ; Clear that pixel
             loop ClearScreen  ; Go to the next pixel
             jmp Render        ; Return to the main loop

; Variables
x1 db 10                       ; Player 1's x
x2 db 160                      ; Player 2's y
y1 db 100                      ; Player 1's x
y2 db 100                      ; Player 2's y

scoretext db "              Score: $" ; The text that goes before the score, centered using spaces
score1 db "0$"                        ; Player 1's score
dash db "-$"                          ; Dash separating scores
score2 db "0$"                        ; Player 2's score

Offline Stonemonkey

  • Pentium
  • *****
  • Posts: 1315
  • Karma: 96
    • View Profile
Re: Pong in Assembly
« Reply #8 on: September 22, 2007 »
You're setting DS then trying to read the values from y1 and x1, you need to get those values before you change DS.

Offline Phoenix

  • C= 64
  • **
  • Posts: 99
  • Karma: 4
    • View Profile
Re: Pong in Assembly
« Reply #9 on: September 22, 2007 »
Yes! That's it! Thanks a lot Stonemonkey :) Now, I just need to detect if the user is holding down a key.

Offline rain_storm

  • Here comes the Rain
  • DBF Aficionado
  • ******
  • Posts: 3088
  • Karma: 182
  • Rain never hurt nobody
    • View Profile
    • org_100h
Re: Pong in Assembly
« Reply #10 on: September 23, 2007 »
I tried runnin this but it wont render for me I'm just getting a black screen but it still escapes normally which is a bit confusing.
But from looking at the code I dont think you should be juggling DS like that you should use ES to write to the video buffer (have look at how stosb works) and that will free up DS for reading values.

Challenge Trophies Won:

Offline Rbz

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 2757
  • Karma: 493
    • View Profile
    • https://www.rbraz.com/
Re: Pong in Assembly
« Reply #11 on: September 23, 2007 »
It's a nice exercise coding those stuff, you will learn alot!

My suggestion:

- Use another segment for video address, for example "es"
- You need to setup your own vga palette, 255 it's not white color here for example.
Challenge Trophies Won:

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: Pong in Assembly
« Reply #12 on: September 23, 2007 »
Much better off, as Rbraz says, to use 'es' segment to point at the screen.  Right now, your variables are being stored in the first few pixels of the screen!

Second, 320x200 means that bytes (db) aren't going to be big enough to hold all the x and y positions.  Much better to make them words (dw).  I can't believe fasm lets you write mov bx,[ x] when x is only a byte without warning you that you've done something silly.

Third, try using suboutines instead of jumping around.  ie. use 'jsr' to call the functions instead of 'jmp' and use 'ret' to go back to the instruction after the 'jsr'.  Define proper interfaces to these functions, for example always use ax to return a result, always use si to pass an address, cx for a count.  'Push' and 'pop' any other registers you use, to avoid corrupting things in the main loop.  Document these parameters.  It might not be important for this little program, but if you ever do anything more complex you won't regret it.

Keep at it! ;D

Jim
<edit>ez-code got the better of my example
« Last Edit: September 23, 2007 by Jim »
Challenge Trophies Won:

Offline Phoenix

  • C= 64
  • **
  • Posts: 99
  • Karma: 4
    • View Profile
Re: Pong in Assembly
« Reply #13 on: September 23, 2007 »
I can't find any information on how to use subroutines, how do they work?

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: Pong in Assembly
« Reply #14 on: September 23, 2007 »
Well, instead of this
Code: [Select]
main:
  jmp draw_it
done_draw_it:
  jmp main
draw_it:
 ..whatever
  jmp done_draw_it
you could write
Code: [Select]
main:
  jsr draw_it
  jmp main
draw_it:
 ..whatever
 ret

That way you can re-use draw_it from anywhere.

Jim
Challenge Trophies Won:

Offline Phoenix

  • C= 64
  • **
  • Posts: 99
  • Karma: 4
    • View Profile
Re: Pong in Assembly
« Reply #15 on: September 23, 2007 »
FASM doesn't like that, and says that jsr is an illegal instruction. Also, jsr doesn't exist in the FASM manual. Are you using another assembler?
« Last Edit: September 23, 2007 by Phoenix »

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: Pong in Assembly
« Reply #16 on: September 23, 2007 »
My apologies, it should be 'call' not 'jsr'.

Jim
Challenge Trophies Won:

Offline Stonemonkey

  • Pentium
  • *****
  • Posts: 1315
  • Karma: 96
    • View Profile
Re: Pong in Assembly
« Reply #17 on: September 23, 2007 »
Quote
I dont think you should be juggling DS like that you should use ES to write to the video buffer

I thought there'd be a better solution to it.


JSR doesn't work in fasm, CALL can be used like that though.

EDIT: oops, was reading and didn't realise there was another page in the thread.

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: Pong in Assembly
« Reply #18 on: September 23, 2007 »
Like I said, really sorry, Z80 and x86 is 'call', 68000 (Amiga, ST) is 'bsr' or 'jsr' ;D

Jim
Challenge Trophies Won:

Offline Phoenix

  • C= 64
  • **
  • Posts: 99
  • Karma: 4
    • View Profile
Re: Pong in Assembly
« Reply #19 on: September 23, 2007 »
That works, and my code looks a little better now :) However, I'm having a little problem with keyboard input. I found this code here on DBF:
Code: [Select]
in al,60h ; keyboard check
dec al   ; check for esc key
But I don't understand how that's supposed to check if escape is pushed. Is it possible to use this method for other keys as well?