User Tools

Site Tools


base:character_bullets

Differences

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

Link to this comparison view

base:character_bullets [2018-03-03 12:08] (current)
achim64 created
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,​x ​    
 + 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