User Tools

Site Tools


sd:part_ii_writing_games_in_assembly_language

This is an old revision of the document!


Part II: Writing Games in Assembly Language

Introduction

At the end of SD-8516 Stellar BASIC we wrote a game called ROBOTS.BAS. This was a fun little take on the classic CHASE or 'robots' game from the bsd games collection. Now, for our study of Assembly Language, let's write a similar game: 'robots.asm'.

Part 1: Assembling and Running a Program

An assembly language program has an .address the bytes will be compiled from at that address. Our program therefore begins:

    .address $000100

start:
    LDELM @message
    LDAH $18
    INT $10
    RET

message:
    .bytes "It works!", 13, 10, 0

If you enter this code into ed and save it as robots.asm, then you can do:

  as robots.asm robots

To run the program, just DLOAD (or LOAD) it and type “sys 256”. This can be a bit confusing; why 256? Without instructions, people might not know what to do. There are three options.

  • 1. Tell people they have to type SYS and a number.
  • 2. .address it at $030100. This is the default “SYS” location. People can run it with SYS.
  • 3. Include a BASIC stub.

For this program I will demonstrate option #3, although #2 is probably just as common. Our program now becomes:

    .address $000100

    ; BASIC stub: 10 SYS 269
    .bytes $FB, $0A, $00
    .bytes "SYS 269", $00
    .bytes $00, $00

; --- Entry point at $00010D (decimal 269) ---
start:
    LDELM @message
    LDAH $18
    INT $10
    RET

message:
    .bytes "It works!", 13, 10, 0

Enter this into ed and then save it; then assemble:

  as robots.asm r

when you dload r, now you can type LIST. It will show:

  10 SYS 269

Now you can RUN the program. This is a fun and convenient way to let users launch your assembly program.

Part 2: Program Structure

Now that we understand how to assemble and run a program, we can talk about our game – robots. Just like in BASIC, we will have:

  • A game loop
  • A subroutine that draws the map
  • A subroutine to get player input
  • A subroutine to move the robot
  • Collision detection

Just like in the BASIC version, we can start by drawing the map. First, let's define our variables and then the map drawing function. We will include a simple main loop whose only job is to call draw_map once.

Our complete listing now becomes:

.equ PX $00        ; player x
.equ PY $01        ; player y
.equ RX $02        ; robot x
.equ RY $03        ; robot y

    .address $000100

    ; BASIC stub: 10 SYS 269
    .bytes $FB, $0A, $00
    .bytes "SYS 269", $00
    .bytes $00, $00

start:
    ; First, let's initialize our variables.
    LDAL #19
    STAL [@PX]         ; Store 19 as initial player X location.
    LDAL #11
    STAL [@PY]         ; Story 11 as player's initial Y
    LDAL #1
    STAL [@RX]
    STAL [@RY]         ; The robot starts at 1,1 for now,

main_loop:
    CALL @draw_map
    RET

draw_map:
    ; VSTOP
    LDAL $81
    STAL [@VIDEO_MODE]

    ; CLS
    LDAH $10        ; CLS
    INT $10

    ; Draw top/bottom border: '*' at (0..39, 0) and (0..39, 24)
    LDBL #'*'
    LDXL #0

dm_top_bottom:
    LDYL #0
    LDAH $11        ; write char AL at XL, YL
    INT $10

    LDYL #24
    LDAH $11        ; write char
    INT $10
    INC XL
    CMP XL, #40
    JNC @dm_top_bottom

    ; Draw left/right border: '*' at (0, 0..24) and (39, 0..24)
    LDBL #'*'
    LDYL #0
dm_left_right:
    LDXL #0
    LDAH $11        ; write char
    INT $10

    LDXL #39
    LDAH $11        ; write char
    INT $10

    INC YL
    CMP YL, #25
    JNC @dm_left_right

    ; Draw player '@'
    LDBL #'@'
    LDXL [@PX]
    LDYL [@PY]
    LDAH $11        ; write char
    INT $10

    ; Draw robot 'r'
    LDBL #'r'
    LDXL [@RX]
    LDYL [@RY]
    LDAH $11        ; write char
    INT $10

    ; VSTART
    LDAL #1
    STAL [@VIDEO_MODE]

    RET

Let's go over the draw_map subroutine.

The first two things we do are we replicate VSTOP and CLS from BASIC.

  ; VSTOP
  LDAL $81
  STAL [@VIDEO_MODE]
  
  ; CLS
  LDAH $10        ; CLS
  INT $10

In assembly, we can't easily call a BASIC command, so we do things slightly differently. Setting video mode to $81 sets us up in mode 1 but stops video updates (because bit 7 is set). So $81 means “mode 1, but set bit 7 so we don't update the screen”. This is normally done to stop screen tearing caused by drawing during an update. But here we're just doing it for academic reasons since assembly is so fast the screen won't have time to update until we're done.

Secondly, INT $10 AH=$10 is the clear screen function. We can call that as an interrupt helper here.

Drawing the border

To draw the border we need to set up a loop that draws stars on the top and bottom, left and right, just like in BASIC. Here we will examine the top and bottom loop:

    ; Draw top/bottom border: '*' at (0..39, 0) and (0..39, 24)
    LDBL #'*'       ; Load character into BL
    LDXL #0         ; set X location

dm_top_bottom:
    LDYL #0         ; set Y location
    LDAH $11        ; write char AL at XL, YL
    INT $10

This simply loads the character, sets the x and y locations, and calls write_char_at_xy via INT $10.

    LDYL #24
    LDAH $11        ; write char (on the bottom of the screen this time)
    INT $10
    INC XL
    CMP XL, #40
    JNC @dm_top_bottom

Here's the loop: After the top and bottom characters are drawn, we INC XL (which is the column marker). Then we CMP XL, #40. This means “check if it's under 40”– i.e. 0-39. If we are on 39, we need to draw again. If we just drew on column 39 and then we INC XL to 40, that means don't continue the loop, and we fall-through to the next function; drawing on the left and right sides:

sd/part_ii_writing_games_in_assembly_language.1775134550.txt.gz · Last modified: by appledog

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki