8bitworkshop/presets/examples/missiles.a

228 lines
5.1 KiB
Plaintext

processor 6502
include "vcs.h"
include "macro.h"
org $f000
; Besides the two 8x1 sprites ("players") the TIA has
; two "missiles" and one "ball", which are just variable-length
; dots or dashes. They have similar positioning and display
; requirements, so we're going to make a subroutine that can
; set the horizontal position of any of them.
; But we can also use the HMPx/HMOVE registers directly to move the
; objects by small offsets without using this routine every time.
counter equ $81
; Initialize and set initial offsets of objects.
start CLEAN_START
lda #10
ldx #0
jsr SetHorizPos ; set player 0 horiz. pos
inx
lda #130
jsr SetHorizPos ; set player 1 horiz. pos
inx
lda #40
jsr SetHorizPos ; set missile 0 horiz. pos
lda #$10
sta NUSIZ0 ; make missile 0 2x-wide
inx
lda #70
jsr SetHorizPos ; set missile 1 horiz. pos
lda #$20
sta NUSIZ1 ; make missile 1 4x-wide
inx
lda #100
jsr SetHorizPos ; set ball horiz. pos
lda #$30
sta CTRLPF ; set ball 8x-wide
sta WSYNC
sta HMOVE
; We've technically generated an invalid frame because
; these operations have generated superfluous WSYNCs.
; But it's just at the beginning of our program, so whatever.
; Next frame loop
nextframe
VERTICAL_SYNC
; 37 lines of VBLANK
ldx #37
lvblank sta WSYNC
dex
bne lvblank
; Draw 192 scanlines
; We're going to draw both players, both missiles, and the ball
; straight down the screen. We can draw various kinds of vertical
; lines this way.
ldx #192
stx COLUBK ; set the background color
lda #0 ; A changes every scanline
ldy #0 ; Y is sprite data index
lvscan
sta WSYNC ; wait for next scanline
lda NUMBERS,y
sta GRP0 ; set sprite 0 pixels
sta GRP1 ; set sprite 1 pixels
tya ; we'll use the Y position, only the 2nd bit matters
sta ENAM0 ; enable/disable missile 0
sta ENAM1 ; enable/disable missile 1
sta ENABL ; enable/disable ball
iny
cpy #60
bne wrap1 ; wrap Y at 60 to 0
ldy #0
wrap1
dex
bne lvscan ; repeat next scanline until finished
; Clear all colors to black before overscan
stx COLUBK
stx COLUP0
stx COLUP1
stx COLUPF
; 30 lines of overscan
ldx #25
lvover sta WSYNC
dex
bne lvover
; Move all the objects by a different offset using HMP/HMOVE registers
; We'll hard-code the offsets in a table for now
ldx #0
hmoveloop
lda MOVEMENT,x
sta HMCLR
sta HMP0,x
sta WSYNC
sta HMOVE
inx
cpx #5
bcc hmoveloop
; This loop also gave us 5 extra scanlines = 30 total
; Cycle the sprite colors for the next frame
inc counter
lda counter
sta COLUP0
clc
ror
sta COLUP1
clc
ror
sta COLUPF
jmp nextframe
; SetHorizPos - Sets the horizontal position of an object.
; The X register contains the index of the desired object:
; X=0: player 0
; X=1: player 1
; X=2: missile 0
; X=3: missile 1
; X=4: ball
; This routine does a WSYNC and HMOVE before executing,
; so whatever you do here will not take effect until you
; call the routine again or do your own WSYNC and HMOVE.
SetHorizPos
sta WSYNC ; start a new line
sta HMOVE ; apply the previous fine position(s)
sta HMCLR ; reset the old horizontal position(s)
sec ; set carry flag
DivideLoop
sbc #15 ; subtract 15
bcs DivideLoop ; branch until negative
eor #7 ; calculate fine offset
asl
asl
asl
asl
sta RESP0,x ; fix coarse position
sta HMP0,x ; set fine offset
rts ; return to caller
; Hard-coded values for movement registers
MOVEMENT
.byte $f0 ; +1 pixels
.byte $e0 ; +2 pixels
.byte $c0 ; +4 pixels
.byte $10 ; -1 pixels
.byte $20 ; -2 pixels
; Bitmap pattern for digits
NUMBERS .byte $0E ; | XXX | $F5C5 Leading zero is not drawn
.byte $0A ; | X X | $F5C6 because it's never used.
.byte $0A ; | X X | $F5C7
.byte $0A ; | X X | $F5C8
.byte $0E ; | XXX | $F5C9
.byte $00
.byte $22 ; | X X | $F5CA
.byte $22 ; | X X | $F5CB
.byte $22 ; | X X | $F5CC
.byte $22 ; | X X | $F5CD
.byte $22 ; | X X | $F5CE
.byte $00
.byte $EE ; |XXX XXX | $F5CF
.byte $22 ; | X X | $F5D0
.byte $EE ; |XXX XXX | $F5D1
.byte $88 ; |X X | $F5D2
.byte $EE ; |XXX XXX | $F5D3
.byte $00
.byte $EE ; |XXX XXX | $F5D4
.byte $22 ; | X X | $F5D5
.byte $66 ; | XX XX | $F5D6
.byte $22 ; | X X | $F5D7
.byte $EE ; |XXX XXX | $F5D8
.byte $00
.byte $AA ; |X X X X | $F5D9
.byte $AA ; |X X X X | $F5DA
.byte $EE ; |XXX XXX | $F5DB
.byte $22 ; | X X | $F5DC
.byte $22 ; | X X | $F5DD
.byte $00
.byte $EE ; |XXX XXX | $F5DE
.byte $88 ; |X X | $F5DF
.byte $EE ; |XXX XXX | $F5E0
.byte $22 ; | X X | $F5E1
.byte $EE ; |XXX XXX | $F5E2
.byte $00
.byte $EE ; |XXX XXX | $F5E3
.byte $88 ; |X X | $F5E4
.byte $EE ; |XXX XXX | $F5E5
.byte $AA ; |X X X X | $F5E6
.byte $EE ; |XXX XXX | $F5E7
.byte $00
.byte $EE ; |XXX XXX | $F5E8
.byte $22 ; | X X | $F5E9
.byte $22 ; | X X | $F5EA
.byte $22 ; | X X | $F5EB
.byte $22 ; | X X | $F5EC
.byte $00
.byte $EE ; |XXX XXX | $F5ED
.byte $AA ; |X X X X | $F5EE
.byte $EE ; |XXX XXX | $F5EF
.byte $AA ; |X X X X | $F5F0
.byte $EE ; |XXX XXX | $F5F1
.byte $00
.byte $EE ; |XXX XXX | $F5F2
.byte $AA ; |X X X X | $F5F3
.byte $EE ; |XXX XXX | $F5F4
.byte $22 ; | X X | $F5F5
.byte $EE ; |XXX XXX | $F5F6
.byte $00
; Epilogue
org $fffc
.word start
.word start