2018-08-13 22:17:36 +00:00
|
|
|
|
2016-12-16 01:21:51 +00:00
|
|
|
processor 6502
|
|
|
|
include "vcs.h"
|
|
|
|
include "macro.h"
|
|
|
|
include "xmacro.h"
|
|
|
|
|
|
|
|
; Given all the heavy lifting it requires to put a single
|
|
|
|
; sprite on the screen, we'd like to abstract away the process
|
|
|
|
; of putting multiple sprites on the screen so we can actually
|
|
|
|
; make a game. This is called the "kernel" because it is
|
|
|
|
; particularly timing-sensitive and the CPU will spend a lot
|
|
|
|
; of time in that loop.
|
|
|
|
|
|
|
|
; We'll start with drawing two overlapping sprites with full
|
|
|
|
; resolution (1 scanline per sprite line) and full color
|
|
|
|
; (1 color per scanline). To do this our kernel (DrawSprites)
|
|
|
|
; will have to update four TIA registers after each WSYNC,
|
|
|
|
; pulling from four lookup tables, and handling edge cases
|
|
|
|
; where sprites overlap partially in the Y-dimension.
|
|
|
|
; This will use up almost an entire scanline of CPU time.
|
|
|
|
|
|
|
|
; Right now we'll just hard-code the horizontal position
|
|
|
|
; of each sprite, limiting ourselves to two sprites.
|
|
|
|
|
|
|
|
seg.u Variables
|
|
|
|
org $80
|
|
|
|
|
|
|
|
Counter byte ; increments each frame
|
|
|
|
Scanline byte ; scanline to draw next
|
|
|
|
|
|
|
|
PData0 word ; pointer (lo/hi) to player 0 bitmap data
|
|
|
|
PData1 word ; pointer to player 1 bitmap data
|
|
|
|
PColr0 word ; pointer to player 0 color data
|
|
|
|
PColr1 word ; pointer to player 1 color data
|
|
|
|
SIndx0 byte ; index into player data (0 = inactive)
|
|
|
|
SIndx1 byte ; index into player data (0 = inactive)
|
|
|
|
SSize0 byte ; sprite size for each player
|
|
|
|
SSize1 byte ; sprite size for each player
|
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
|
|
seg Code
|
|
|
|
org $f000
|
|
|
|
|
|
|
|
; Initialize and set initial offsets of objects.
|
|
|
|
Start CLEAN_START
|
|
|
|
; Hard-code the horizontal player positions.
|
|
|
|
lda #70
|
|
|
|
ldx #0
|
|
|
|
jsr SetHorizPos ; set player 0 horiz. pos
|
|
|
|
lda #73
|
|
|
|
ldx #1
|
|
|
|
jsr SetHorizPos ; set player 1 horiz. pos
|
|
|
|
sta WSYNC
|
|
|
|
sta HMOVE
|
|
|
|
|
|
|
|
; Next frame loop
|
|
|
|
NextFrame
|
|
|
|
TIMER_SETUP 37
|
|
|
|
VERTICAL_SYNC
|
|
|
|
; Set some colors
|
|
|
|
lda #$80
|
|
|
|
sta COLUBK ; set the background color
|
|
|
|
; Setup the two sprites
|
|
|
|
lda #50
|
|
|
|
sta SIndx0
|
|
|
|
lda Counter ; changes every frame
|
|
|
|
sta SIndx1
|
|
|
|
lda #17
|
|
|
|
sta SSize0
|
|
|
|
sta SSize1
|
|
|
|
lda #<Frame0
|
|
|
|
sta PData0
|
|
|
|
lda #>Frame0
|
|
|
|
sta PData0+1
|
|
|
|
lda #<ColorFrame0
|
|
|
|
sta PColr0
|
|
|
|
lda #>ColorFrame0
|
|
|
|
sta PColr0+1
|
|
|
|
lda #<Frame1
|
|
|
|
sta PData1
|
|
|
|
lda #>Frame1
|
|
|
|
sta PData1+1
|
|
|
|
lda #<ColorFrame0
|
|
|
|
sta PColr1
|
|
|
|
lda #>ColorFrame0
|
|
|
|
sta PColr1+1
|
|
|
|
TIMER_WAIT
|
|
|
|
|
|
|
|
; Scanline loop
|
|
|
|
lda #0
|
|
|
|
sta Scanline
|
|
|
|
NextScanline
|
|
|
|
jsr DrawSprites
|
|
|
|
inc Scanline
|
|
|
|
; WSYNC and then clear sprite data
|
|
|
|
sta WSYNC
|
|
|
|
lda #0
|
|
|
|
stx GRP0
|
|
|
|
stx GRP1
|
|
|
|
; repeat until all scanlines drawn
|
|
|
|
lda Scanline
|
|
|
|
cmp #192
|
|
|
|
bcc NextScanline
|
|
|
|
|
|
|
|
; Clear all colors to black before overscan
|
|
|
|
stx COLUBK
|
|
|
|
stx COLUP0
|
|
|
|
stx COLUP1
|
|
|
|
stx COLUPF
|
|
|
|
|
|
|
|
; 30 lines of overscan
|
|
|
|
TIMER_SETUP 30
|
|
|
|
TIMER_WAIT
|
|
|
|
; Jump to next frame
|
|
|
|
inc Counter
|
|
|
|
jmp NextFrame
|
|
|
|
|
|
|
|
; Here is our sprite kernel.
|
|
|
|
; Inputs:
|
|
|
|
; ssize0, ssize1 (size in lines of each sprite)
|
|
|
|
; sindx0, sindx1 (# scanlines to bottom of sprites)
|
|
|
|
; pdata0, pdata1 (ptr to sprite bitmaps)
|
|
|
|
; pcolr0, pcolr0 (ptr to sprite color tables)
|
|
|
|
DrawSprites
|
|
|
|
; Find out the maximum # of lines to draw
|
|
|
|
; by taking the maximum of the two sprite heights
|
|
|
|
lda SIndx0
|
|
|
|
cmp SIndx1
|
|
|
|
bpl Cmp1 ; sindx0 < sindx1
|
|
|
|
lda SIndx1
|
|
|
|
Cmp1 tax ; X = # of lines left to draw
|
|
|
|
cmp #0 ; no lines?
|
|
|
|
beq NoSprites
|
|
|
|
; add total draw height to scanline count
|
|
|
|
clc
|
|
|
|
adc Scanline
|
|
|
|
sta Scanline
|
|
|
|
DrawNextScanline
|
|
|
|
; Fetch next pixels/colors for sprite 0
|
|
|
|
ldy SIndx0
|
|
|
|
cpy SSize0
|
|
|
|
bcs Inactive0 ; index >= size? (unsigned)
|
|
|
|
lda (PData0),y
|
|
|
|
; Do WSYNC and then quickly store pixels/colors for player 0
|
|
|
|
sta WSYNC
|
|
|
|
sta GRP0
|
|
|
|
lda (PColr0),y
|
|
|
|
sta COLUP0
|
|
|
|
DrawSprite1
|
|
|
|
; Fetch next pixels/colors for sprite 1
|
|
|
|
ldy SIndx0+1
|
|
|
|
cpy SSize0+1
|
|
|
|
bcs Inactive1 ; index >= size? (unsigned)
|
|
|
|
lda (PData1),y
|
|
|
|
sta GRP1
|
|
|
|
lda (PColr1),y
|
|
|
|
sta COLUP1
|
|
|
|
Inactive1
|
|
|
|
; Decrement the two sprite indices
|
|
|
|
dey
|
|
|
|
sty SIndx0+1
|
|
|
|
dec SIndx0
|
|
|
|
dex
|
|
|
|
bne DrawNextScanline
|
|
|
|
NoSprites
|
|
|
|
; Clear player data on exit
|
|
|
|
rts
|
|
|
|
Inactive0
|
|
|
|
; Alternate sprite 0 path when inactive
|
|
|
|
lda #0
|
|
|
|
sta WSYNC
|
|
|
|
sta GRP0
|
|
|
|
sta COLUP0
|
|
|
|
beq DrawSprite1 ; always taken due to lda #0
|
|
|
|
|
|
|
|
; 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
|
|
|
|
|
|
|
|
; Height of our sprite in lines
|
|
|
|
SpriteHeight equ 18
|
|
|
|
|
|
|
|
; To avoid nasty timing issues,
|
|
|
|
; we'll start the bitmap data at a page boundary
|
|
|
|
org $f800
|
|
|
|
|
|
|
|
; Bitmap data "standing" position
|
|
|
|
Frame0
|
|
|
|
.byte #0
|
|
|
|
.byte #%01101100;$F6
|
|
|
|
.byte #%00101000;$86
|
|
|
|
.byte #%00101000;$86
|
|
|
|
.byte #%00111000;$86
|
|
|
|
.byte #%10111010;$C2
|
|
|
|
.byte #%10111010;$C2
|
|
|
|
.byte #%01111100;$C2
|
|
|
|
.byte #%00111000;$C2
|
|
|
|
.byte #%00111000;$16
|
|
|
|
.byte #%01000100;$16
|
|
|
|
.byte #%01111100;$16
|
|
|
|
.byte #%01111100;$18
|
|
|
|
.byte #%01010100;$18
|
|
|
|
.byte #%01111100;$18
|
|
|
|
.byte #%11111110;$F2
|
|
|
|
.byte #%00111000;$F4
|
|
|
|
|
|
|
|
; Bitmap data "throwing" position
|
|
|
|
Frame1
|
|
|
|
.byte #0
|
|
|
|
.byte #%01101100;$F6
|
|
|
|
.byte #%01000100;$86
|
|
|
|
.byte #%00101000;$86
|
|
|
|
.byte #%00111000;$86
|
|
|
|
.byte #%10111010;$C2
|
|
|
|
.byte #%10111101;$C2
|
|
|
|
.byte #%01111101;$C2
|
|
|
|
.byte #%00111001;$C2
|
|
|
|
.byte #%00111000;$16
|
|
|
|
.byte #%01101100;$16
|
|
|
|
.byte #%01111100;$16
|
|
|
|
.byte #%01111100;$18
|
|
|
|
.byte #%01010100;$18
|
|
|
|
.byte #%01111100;$18
|
|
|
|
.byte #%11111110;$F2
|
|
|
|
.byte #%00111000;$F4
|
|
|
|
|
|
|
|
; Color data for each line of sprite
|
|
|
|
ColorFrame0
|
|
|
|
.byte #$FF;
|
|
|
|
.byte #$F6;
|
|
|
|
.byte #$86;
|
|
|
|
.byte #$86;
|
|
|
|
.byte #$86;
|
|
|
|
.byte #$C2;
|
|
|
|
.byte #$C2;
|
|
|
|
.byte #$C2;
|
|
|
|
.byte #$C2;
|
|
|
|
.byte #$16;
|
|
|
|
.byte #$16;
|
|
|
|
.byte #$16;
|
|
|
|
.byte #$18;
|
|
|
|
.byte #$18;
|
|
|
|
.byte #$18;
|
|
|
|
.byte #$F2;
|
|
|
|
.byte #$F4;
|
|
|
|
|
|
|
|
; Epilogue
|
|
|
|
org $fffc
|
|
|
|
.word Start
|
|
|
|
.word Start
|