User Tools

Site Tools


base:character_bullets
no way to compare when less than two revisions

Differences

This shows you the differences between two versions of the page.


base:character_bullets [2018-03-03 12:08] (current) – created achim64
Line 1: Line 1:
 +====== Character bullets ======
  
 +by Achim
 +
 +
 +Here're a few basic ideas on how to handle character bullets.
 +Using character bullets is a bit annoying, but it's the easiest
 +way to save sprites.
 +
 +===== Preperation =====
 +
 +
 +First thing to do is to set up a lookup table that holds the screen
 +addresses for each screen row. This will make the movements a lot easier.
 +
 +<code>
 +;create lookup table for screen rows
 +
 + lda #$00
 + sta tmp0 ;zp address
 + sta tmp0+1 ;zp address+1
 +
 + sta rowlow ;first row
 + sta rowhi
 +
 + tax
 +lookup: lda tmp0
 + clc
 + adc #40
 + sta rowlow+1,x
 + sta tmp0
 + bcc +
 + inc tmp0+1
 ++ lda tmp0+1
 + sta rowhi+1,x
 + inx
 + cpx #24 ;table for all 25 screen rows
 + bne lookup
 +
 +rowlow: !fill 25,0
 +rowhi: !fill 25,0
 +</code>
 +
 +'Rowhi' holds relative values (0 - 3) to make it versatile, e.g. for double buffering.
 +A simple 'ora #screen_hibyte' will switch to the required screen buffer.
 +
 +Now you can allocate x/y-coordinates to your bullets: 
 +
 +bullet_column = x, bullet_row = y
 +
 +Set up two tables for x and y (columns and rows):
 +
 +<code>
 +bullet_row: !fill 8,$ff ; =y coordinate, 8 bullets, $ff=bullet not active
 +bullet_column: !fill 8,0 ; =x coordinate
 +</code>
 +
 +From now on you only have to manipulate the coordinates to move the bullets. 
 +Everytime your game engine refreshes the screen data, use 'bullet_row' as an index to fetch the
 +required screen address:
 +
 +<code>
 +;x-reg pointing at current char bullet
 +
 + ldy bullet_row,x ;fetch current screen position
 + lda rowlow,y
 + sta tmp0                ;zp address
 + lda rowhi,y
 + ora #screen_screenhibyte ;hi-byte screen buffer, e.g. $40 = screnn buffer located at $4000
 + sta tmp0+1                ;zp address+1
 + ldy bullet_column,x
 +
 + ;lda (tmp0),y ;to read screen address... or
 + ;sta (tmp0),y ;to print on screen...
 +</code>
 +
 +===== Examples =====
 +
 +
 +
 +1. A simple example would be a game with following specs:
 +  * one screen buffer
 +  * no scrolling
 +  * bullets moving only left or right
 +
 +A procedure would look like this:
 +
 +  - check if bullet can be printed on screen
 +  - save char underneath char-bullet
 +  - save colorRAM of original char
 +  - print char on screen and add color
 +  - determine bullet direction
 +
 +So we need five tables:
 +
 +<code>
 +bullet_row: !fill 8,$ff ;8 bullets, row=$ff --> bullet inactive
 +bullet_column: !fill 8,0
 +bullet_direction: !fill 8,0 ;e.g.: left=00, right<>00
 +charactertmp: !fill 8,0 ;stored char underneath bullet
 +colortmp: !fill 8,0 ;stored color of char underneath char bullet
 +</code>
 +
 +In this case bullet_row=$ff means char bullet is not active and slot can be used.
 +Each bullet is switched off by setting bullet_row to $ff.
 +
 +print a new bullet on screen:
 +
 +<code>
 +newbullet: ;called if player presses fire
 + ldx #7 ;maximum of 8 bullets
 +- lda bullet_row,x ;check if there's a free slot
 + bmi setbullet
 + dex
 + bpl -
 + rts
 +
 +setbullet:
 + lda player_row ;precalculated screen row (=y-coordinate) of player
 + sta bullet_row,x ;adjust this value if necessary, e.g. +/- 1 row
 + lda player_column ;precalculated screen column (=x-coordinate) of player...
 + sta bullet_column,x ;...adjust this value if necessary, e.g. +/- 1 column
 +
 + ldy bullet_row,x ;= y-coordinate
 + lda rowlow,y ;fetch corresponding screen address
 + sta tmp0                ;zp address
 + lda rowhi,y
 + ora #screen_hibyte ;hibyte of screen buffer
 + sta tmp0+1
 +
 +printbullet:
 + ldy bullet_column,x ;= x-coordinate
 + lda (tmp0),y ;read char underneath bullet...
 + sta chararctertmp,x ;...and store it
 + lda #bullet ;value of char bullet
 + sta (tmp0),y ;print bullet on screen
 +
 + lda tmp0+1 ;switch to colorRAM
 + and #$03
 + ora #$d8
 + sta tmp0+1
 +
 + lda (tmp0),y ;read color of original char
 + sta colortmp,x ;and store it
 + lda #bulletcolor ;color of char bullet
 + sta (tmp0),y ;set color
 +
 + rts
 +</code>
 +
 +Moving the bullets:
 +
 +<code>
 + ldx #7
 +- lda bullet_row,x
 + bmi skip
 + jsr move1bullet
 +skip dex
 + bpl -
 + rts
 +
 +move1bullet:
 +
 + ;restore char and color of orignal char first
 +
 + ldy bullet_row,x ;= y-coordinate
 + lda rowlow,y ;fetch corresponding screen address
 + sta tmp0
 + lda rowhi,y
 + ora #screen_hibyte ;hibyte of screen buffer
 + sta tmp0+1
 +
 + ldy bullet_column,x ;= x-coordinate
 + lda chararctertmp,x ;restore original char
 + sta (tmp0),y
 +
 + lda tmp0+1 ;switch to colorRAM
 + and #$03
 + ora #$d8
 + sta tmp0+1
 +
 + lda colortmp,x ;restore color
 + sta (tmp0),y
 +
 +;now move the bullet
 +
 + lda bullet_direction,x
 + beq movebullet2left ;00=move to the left
 +
 + inc bullet_column,    
 + lda bullet_column,x
 + cmp #40 ;hitting right border?
 + bcc +
 + lda #$ff ;switch off bullet
 + sta bullet_row,x
 + rts
 ++ jmp printbullet ;same as above...
 +
 +movebullet2left:
 + dec bullet_column,x
 + bpl +
 + lda #$ff ;hitting left border?
 + sta bullet_row,x ;switch off bullet
 + rts
 ++ jmp printbullet ;same as above
 +</code>
 +
 +===== Multiple directions =====
 +
 +
 +'Bullet_direction' can be used for at least 8 different directions. Idea would be to use the
 +lower four bits for up (bit 0), down (bit 1), left (bit 2) and right (bit 3), similar to the joystick values you get from $dc00.
 +
 +Moving a bullet in 8 directions could look like this:
 +
 +<code>
 +;x-reg pointing at current bullet
 +
 +movebulletup:
 + lda bullet_direction,x
 + and #1 ;bit 0 set?
 + beq movebulletdown
 +
 + dec bullet_row,x
 + bpl movebulletleft ;hitting top border? if not check left & right
 + lda #$ff
 + sta bullet_row,x ;then switch off bullet
 + bmi movebulletleft ;continue with left&right
 +
 +movebulletdown:
 + lda bullet_direction,x
 + and #2 ;bit 1 set?
 + beq movebulletleft
 +
 + inc bullet_row,x
 + lda bullet_row,x
 + cmp #25 ;hitting bottom border?
 + bcc movebulletleft
 + lda #$ff ;then switch off bullet
 + sta bullet_row,x ;and continue with left&right
 +
 +movebulletleft:
 + lda bullet_direction,x
 + and #4 ;bit 2 set?
 + beq movebulletright
 +
 + dec bullet_column,x
 + bpl +
 + lda #$ff ;hitting left border?
 + sta bullet_row,x ;switch off bullet
 ++ rts
 +
 +movebulletright:
 + lda bullet_direction,x
 + and #8 ;bit 3 set?
 + beq +
 +
 + inc bullet_column,x
 + lda bullet_column,x
 + cmp #40 ;hitting right border?
 + bcc +
 + lda #$ff ;switch off bullet
 + sta bullet_row,x
 ++ rts
 +</code>
 +
 +Manipulate the coordinates like this and then again refresh the screen data ('printbullet', see above)
 +
 +
 +===== Scrolling screen =====
 +
 +Scrolling the screen data automatically moves the char bullets as well, of course.
 +The effect will be a line of char bullets on screen. So the game engine has to delete the char bullets
 +left behind. This should be done when the hardscrolling is finished. Read the bullet tables to figue out
 +which bullet is on screen. Adjust the coordinates according to the scrolling direction
 +and restore the original char of the backdrop.
base/character_bullets.txt · Last modified: 2018-03-03 12:08 by achim64