Locus classicus for this effect is Uridium: Fast scrolling graphics with fixed stars in the background. This kind of parallax shifting is simple but effective. Here's a small tutorial for a sidescrolling game using two screen buffers.
Only two steps necessary to achieve this effect:
First you've got to reserve one blank char in your charset. Then set up a table with eight values:
star: .byte $80, $40, $20, $10, $08, $04, $02, $01
This table is nothing but one bit shifted from left to right. To make the starfield static while the screen is scrolling use the soft scroll registers as an index.
lda softscroll ;bits 0-3 = value 0-7, manipulated by the main program tay ;make it an index ora #$30 sta $d016 ;soft scroll lda star,y ;read bit from table sta char ;write bit to first byte of resverved char
This has to be done in the interrupt. Now 'char' is always one centered bit, while the rest is scrolling left or right.
Some screen positions have to be defined. Set up two tables (hi-byte and offset) for each screen position.
starhi: .byte $00, $00, $01, $01, $02, $02, $03, $03 ;relative hi-bytes for eight stars staroffset: .byte $xx, $xx, ... ;some offset values from $00-$ff
The hi-bytes have to be relative values in order to make them usable for double buffering. Double buffering means that the main program switches between two screen buffers after scrolling one char length. The main program should handle two variables for both screen buffers, 'activescreen' and 'inactivescreen' and switch between both.
Stars only appear in 'space' which is usually visualized by a blank char. The screen positions have to be read with relative values in order to check wether there's 'space' or not.
ldx #$00 ;loop for all stars stx starposition ;zeropage address, lo-byte always #$00 loop lda inactivescreen ;hi-byte of inactive screen buffer, e.g. $40 for buffer at $4000 ora starhi,x ;convert relative to absolute value sta starposition+1 ;hi-byte zeropage address ldy staroffset,x ;read offset lda (starposition),y ;read screen position bne skip ;while char #$00 is blank for 'space'... lda star sta (starposition),y ;...print star on inactive screen buffer skip inx cpx ... ;max. stars bne loop ;check next star
The star will be printed if there's a blank char (in this case char #$00='space') at specific screen position. This has to be done at the right moment. A typical procedure for double buffering would look like this:
The check can be done after step 2) or 3). Next thing to do is to delete stars from previous scroll procedure as they have moved left or right. After printing the star, increment or decrement (dependent on scroll direction) y-reg and write a blank char.
One thing left to do: Write colour RAM to make the star white. Otherwise the stars would flicker in multicolour mode. This has to be done after step 4).
The same can be done for a multidirectional scrolling game. Only the first step has to be changed to make the stars fixed for vertical scrolling as well. Now the centered bit has to be shifted bytewise through the reserved char. The reserved char should be blanked out every frame. Then the centered bit can be written.
lda softscrollx ;left-right scrolling tay ;make it an index ora #$30 sta $d016 ;soft scroll x lda star,y ;read bit from table ldy softscrolly ;up-down-scrolling as index sta char,y ;write bit to specific byte of reserved char tya ora #$10 sta $d011 ;soft scroll y