Sparse Invaders Source - SpriteControllert.txt

Sparse Invaders Source - SpriteController.txt
The Sprite Controller manages any active sprites. This was the first module I really implemented when first working on the Sparse Invaders. That's really trying to explain that it's a little overly complex for the Beeb. In Sparse Invaders, the only sprites under this controller are the player, bullets, mothership and explosions. If you are to use this sprite controller then please be aware that it has limitations. To keep the game running faster the Invaders are drawn using a much more simplier and faster technique. However that said, when initializing the sprite, it does pre-calculate and store certain parameters within the sprite structure to speed things along alittle when drawing the sprite. There are certainly pro's and con's when using this controller, however for simple games this more then does the job.

Please refer to constants.txt for details for the sprite structure.

;---   ;  SpriteController ; Written by Neil Beresford. ;   ;  Copyright 2008,2009 Neil Beresford ;   ;    This file is part of Sparse Invaders. ;   Sparse Invaders is free software: you can redistribute it and/or modify ;   it under the terms of the GNU General Public License as published by    ;    the Free Software Foundation, either version 3 of the License, or    ;    (at your option) any later version. ;   ;    Sparse Invaders is distributed in the hope that it will be useful, ;   but WITHOUT ANY WARRANTY; without even the implied warranty of    ;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;   GNU General Public License for more details. ;   ;    You should have received a copy of the GNU General Public License ;   along with Sparse Invaders. If not, see . ;   ;    ;   Notes: ;   ;  Sprite fix array, screen active list ;   ;  Functionality... ; Sprite core system: ;    SpriteInit           - pressetup for sprite system - holds test code at present. ;    SpriteStart          - Adds sprite into control system ;    SpritesDrawActive    - Draws all activate sprites - max limit of 6 ;    SpritesWipeActive    - Wipes the area that the sprite was drawn to    ;     SpriteDraw           - sprite drawer ;    SpriteWipe           - sprite wipe ;   ;  Support Functionality; ;    SpriteClear          - clears the sprite structure within the active array ;    SpriteActivate       - marks the active position within ;    SpriteCalcScreenPos  - calculates the screen position address from X,Y ;    SpriteRetreiveDetails- gets the sprite data, width and height for the sprite from its data ;   ;---    .require "Constands" .require "Macros" ;---   ; SpriteInit - ;    inits the sprite system ;   ;---    SpriteInit: ; clear the sprite data ...      ; [NOTE] this assumes at present, less then 255 bytes for the data ...        LDA  #0 LDX #TOTAL_SPRITE_SPACE SI_Clearlist: DEX STA SPRArray,X BNE SI_Clearlist ; clear the active list ... LDX #TOTAL_ACTIVE_SPRITES - 1 LDA #$ff SI_ClearActives: STA SPRActive,X DEX BPL SI_ClearActives RTS ;---   ;  SpriteStart: ;        Starts the sprite, activating it...    ;   Regs - A sprite number for storage. (SprArray) ;         X sprite X    ;          Y sprite Y    ;     SPRITE sprite frame  <--- SPRITE is in Zero page ; CALLPARMA1 used for the callback for the control...    ; CALLPARMA2 ... ( have blank if not needed ) ;---   SpriteStart: CLC ROL ROL ROL ROL STA SCRATCH1 STX XPOS STY YPOS JSR SpriteClear LDA SCRATCH1 JSR SPriteActivate STX  CURRENT_SPRITE CLC LDA  #SPRArray ADC  #0 STA  TEMPPTR+1 LDY  #0 LDA  XPOS                ; 0 Xpos STA  (TEMPPTR), Y        INY LDA  YPOS                ; 1 Ypos STA  (TEMPPTR), Y        INY LDA  SPRITE              ; 2 frame STA  (TEMPPTR), Y           INY LDA  CALLPARAM1          ; 3 control STA  (TEMPPTR), Y        LDA   CALLPARAM2 INY STA  (TEMPPTR), Y        ; 4 ...        ; PLEASE PLEASE do not move this away from the YPOS adjust as I did! Sigh! LDA  SPRITE JSR  SpriteRetreiveDetails LDY  #SPRBLK_WIDTH STA  (TEMPPTR), Y        ; store width TXA INY STA  (TEMPPTR), Y        ; store height ; adjust Y pos to bottom of sprite, CLC ADC YPOS SEC SBC #1 STA YPOS ; adjust the YPOS to character based and store the offset in x for indexing AND #$07 STA XOFFSET LDA YPOS AND #$f8 STA YPOS jsr  SpriteCalcScreenPos LDA  #SPRFLAG_REDRAW LDY  #SPRBLK_FLAG STA  (TEMPPTR), Y        ; Mark the sprite for redraw LDY  #SPRBLK_SPRDATA LDA  CURRENTSPRITEDATA STA  (TEMPPTR),Y         ; store sprite data INY LDA  CURRENTSPRITEDATA+1 STA  (TEMPPTR),Y LDY  #SPRBLK_XOFFSET    ; Xoffset LDA  XOFFSET STA  (TEMPPTR),Y LDY  #SPRBLK_XOFFBACK STA  (TEMPPTR),Y LDA  SCREENADD          ; 6 SCREEN ADD LDY  #SPRBLK_SCREENADD STA  (TEMPPTR),Y INY LDA  SCREENADD+1        ; 7  /\  /\ STA  (TEMPPTR),Y LDY  #SPRBLK_SCRBACK    ; screen position used for wiping spr LDA  SCREENADD STA  (TEMPPTR),Y INY LDA  SCREENADD+1 STA  (TEMPPTR),Y SI_Debug: RTS ;---   ; SpriteMoveSprite - ;    Moves the sprite to the adsolute pos passed in    ;     A - sprite slot index ( sprite * 8 ) ;    X - x pos ;    y - y pos ;---   SpriteMoveSprite: CLC ROL ROL ROL ROL STA SCRATCH1 STX XPOS STY YPOS CLC LDA  #SPRArray ADC  #0 STA  TEMPPTR+1 SpriteMoveSpr: ; store the x and y position LDA  XPOS LDY  #SPRBLK_X STA  (TEMPPTR), Y       LDA   YPOS INY STA  (TEMPPTR), Y       ; get the width and height for drawing the sprite LDY  #SPRBLK_WIDTH LDA  (TEMPPTR), Y       STA   WIDTH INY LDA  (TEMPPTR), Y       STA   HEIGHT ; adjust Y pos to bottom of sprite, CLC ADC YPOS SEC SBC #1 STA YPOS ; adjust the YPOS to character based and store the offset in x for indexing AND #$07 STA XOFFSET LDA YPOS AND #$f8 STA YPOS jsr  SpriteCalcScreenPos LDA  XOFFSET LDY  #SPRBLK_XOFFSET    ; 5 Xoffset STA  (TEMPPTR),Y LDA  SCREENADD          ; 6 SCREEN ADD INY STA  (TEMPPTR),Y LDA  SCREENADD+1        ; 7  /\  /\ INY STA  (TEMPPTR),Y LDY  #SPRBLK_FLAG LDA  (TEMPPTR), Y       ORA   #SPRFLAG_REDRAW STA  (TEMPPTR), Y        ; Mark the sprite for redraw RTS ;---   ; SpriteActivate - ;    Activates the sprite slot ;    A - sprite slot index ( sprite * 8 ) ;---   SpriteActivate: TAY LDX  #TOTAL_ACTIVE_SPRITES-1 LDA  #$ff SA_Loop: CMP  SPRActive,X BEQ  SA_found DEX BPL  SA_loop RTS SA_found: TYA STA  SPRActive,X RTS ;---   ; SpriteClear - ;    clears sprite data and removes from active list if present.. ;    A - sprite slot indexed ( sprite * 16 ) ;   ;---    SpriteClear: PHA ; firstly check and remove if found in active list LDX  #TOTAL_ACTIVE_SPRITES-1 SC_checkActive: CMP SPRActive,X BNE SC_decIndex SC_foundActive: LDA #$ff STA SPRActive,X ; now clear the sprite slot ... PLA SC_ClearData: STA SCRATCH1 LDA #SPRArray ADC #0 STA TEMPPTR+1 LDY #SIZEOF_SPRITE_BLOCK -1 SC_clear: STA (TEMPPTR),Y DEY BPL SC_clear RTS SC_decIndex: DEX BPL SC_checkActive PLA          ; pop stack... RTS ;---   ; SpriteDrawActive ;       worth through the active sprites, drawing any that are needed. ;---   SpritesDrawActive: ; firstly check and remove if found in active list LDX  #TOTAL_ACTIVE_SPRITES-1 SDA_Loop: STX  ACTIVEINDEX LDA  SPRActive,X CMP  #$ff BEQ  SDA_Next SDA_Found: ; calculate the offset to the start of active sprite data STA  SPRITE CLC LDA  #SPRArray ADC  #0 STA  TEMPPTR+1 LDY  #SPRBLK_FLAG LDA  (TEMPPTR),Y AND  #SPRFLAG_REDRAW BEQ  SDA_Next STX  SCRATCH1 jsr SDA_SetupSprite LDX  STOREX LDY  STOREY ; draw the sprite to screen... JSR  SpriteDraw ; clear the redraw flag... LDY  #SPRBLK_FLAG LDA  (TEMPPTR),Y AND  #SPRFLAG_NOT_REDRAW STA  (TEMPPTR),Y LDY  #SPRBLK_CTRL LDA  (TEMPPTR),Y BEQ  SDA_Next STA  USERPTR INY LDA  (TEMPPTR),Y STA  USERPTR+1 ; NOTE - RTS pops the low then high byte, adds one ; then sets the PC to that address. The example in      ; 6502.org shows the high byte od SDA_Return with -1 ; on it as well. I can only assume it's parsed left ; to right - I'm concerned if this address falls on a 256 ; boundary. ; might be a bug in p65 - investigate later, as address calculated ; correctly as of writting. LDA  #>SDA_Return PHA LDA  #<SDA_Return-1 PHA JMP  (USERPTR) SDA_Return: SDA_Next: LDX  ACTIVEINDEX DEX BPL  SDA_Loop RTS SDA_SetupSprite: ; get the x and y and frame for drawing the sprite LDY  #0 LDA  (TEMPPTR), Y       STA   STOREX INY LDA  (TEMPPTR), Y       STA   STOREY INY LDA  (TEMPPTR), Y       TAX                          ; frame saved ; retrieve the screen position for drawing the sprite ... LDY  #SPRBLK_XOFFSET        ; sprite screen drawing LDA  (TEMPPTR), Y       STA   XOFFSET INY LDA  (TEMPPTR), Y       STA   SCREENADD STA  SCREENADD_BACK INY LDA  (TEMPPTR), Y       STA   SCREENADD+1 STA  SCREENADD_BACK+1 LDY  #SPRBLK_WIDTH          ; sprite width and height LDA  (TEMPPTR), Y       STA   WIDTH STA  CURRENT_SPR_W INY LDA  (TEMPPTR), Y       STA   HEIGHT STA  CURRENT_SPR_H LDY  #SPRBLK_SPRDATA        ; sprite data LDA  (TEMPPTR),Y STA  CURRENTSPRITEDATA INY LDA  (TEMPPTR),Y STA  CURRENTSPRITEDATA+1 TXA RTS ;---   ; SpriteWipeActive ;       worth through the active sprites, clearing any that are needed. ;---   SpritesWipeActive: ; firstly check and remove if found in active list LDX  #TOTAL_ACTIVE_SPRITES-1 SWA_Loop: STX  ACTIVEINDEX LDA  #$ff CMP  SPRActive,X BEQ  SWA_Next SWA_Found: LDA  SPRActive,X STA  SPRITE ; check the redraw flag ... CLC ADC  #SPRBLK_FLAG TAX LDA  SPRArray,X AND  #SPRFLAG_REDRAW BEQ  SWA_Next ; clear the sprite to screen... LDA  SPRITE JSR  SpriteWipe ;      ; tempptr has been set within the spritewipe function ; Set the new screen position to be the old one ... LDY  #SPRBLK_FLAG LDA  (TEMPPTR),Y AND  #SPRFLAG_KILL BEQ  SWA_SetScreen ; kill sprite ... remove from list LDX  ACTIVEINDEX LDA  #$ff STA  SprActive,X JMP  SWA_Next SWA_SetScreen: LDY  #SPRBLK_SCREENADD LDA  (TEMPPTR),Y LDY  #SPRBLK_SCRBACK STA  (TEMPPTR),Y LDY  #SPRBLK_SCREENADD2 LDA  (TEMPPTR),Y LDY  #SPRBLK_SCRBACK2 STA  (TEMPPTR),Y LDY  #SPRBLK_XOFFSET LDA  (TEMPPTR),Y LDY  #SPRBLK_XOFFBACK STA  (TEMPPTR),Y SWA_Next: LDX  ACTIVEINDEX DEX BPL  SWA_Loop RTS ;---   ; SpriteRetreiveDetails - a Sprite number ;             returns A - width, X - heighht ;   ;---    SpriteRetreiveDetails: ; calculate the index... ASL TAX CLC ; get and store the pointer to the sprtie data ...         LDA  spriteData,X ADC #spriteData STA CURRENTSPRITEDATA+1 ; grab the sprite info ... LDY #SPRDATA_HEIGHT LDA (CURRENTSPRITEDATA),Y TAX DEY LDA (CURRENTSPRITEDATA),Y RTS ;---   ; SpriteDraw - a Sprite number = referenced from SPRArray ;             The following need to be setup prior to calling this... ;             SPRITEADD, WIDTH, HEIGHT, XOFFSET, CURRENTSPRITEDATA ;---   SpriteDraw: ; store the sprite number, x and y position STA SPRITE STX XPOS STY YPOS ; now store sprite data and screen address in code LDA SCREENADD STA ScreenAddPtr+1 LDA SCREENADD+1 STA ScreenAddPtr+2 CLC LDA CURRENTSPRITEDATA ADC #2 STA SpriteDataPtr+1 LDA CURRENTSPRITEDATA+1 ADC #0 STA SpriteDataPtr+2 LDX XOFFSET SW_Width: LDY HEIGHT DEY SW_Height: SpriteDataPtr:        ; please note - self modifying code LDA $FFFF,Y BEQ SW_SkipWrite ScreenAddPtr:         ; please note - self modifying code STA $FFFF,X       ; is ->   STA  ScreenAddPtr+1,X SW_SkipWrite: DEX BPL SW_CheckHeight SW_AtCharPos: SEC LDA ScreenAddPtr+1 SBC #$80 STA ScreenAddPtr+1 LDA ScreenAddPtr+2 SBC #2 STA SCreenAddPtr+2 LDX #7 SW_CheckHeight: DEY BPL SW_Height DEC WIDTH BEQ SW_End ; move to the next column CLC LDA SpriteDataPtr+1 ADC HEIGHT STA SpriteDataPtr+1 LDA SpriteDataPtr+2 ADC #0 STA SpriteDataPtr+2 LDA SCREENADD CLC ADC #8 STA SCREENADD STA ScreenAddPtr+1 LDA SCREENADD+1 ADC #0 STA SCREENADD+1 STA ScreenAddPtr+2 LDX XOFFSET JMP SW_Width SW_End: RTS ;---   ; SpriteNoMaskDraw - a Sprite number = referenced from SPRArray ;             The following need to be setup prior to calling this... ;             SPRITEADD, WIDTH, HEIGHT, XOFFSET, CURRENTSPRITEDATA ;---   SpriteNoMaskDraw: ; store the sprite number, x and y position STA SPRITE STX XPOS STY YPOS ; now store sprite data and screen address in code LDA SCREENADD STA SScreenAddPtr+1 LDA SCREENADD+1 STA SScreenAddPtr+2 CLC LDA CURRENTSPRITEDATA ADC #2 STA SSpriteDataPtr+1 LDA CURRENTSPRITEDATA+1 ADC #0 STA SSpriteDataPtr+2 LDX XOFFSET SNMW_Width: LDY HEIGHT DEY SNMW_Height: SSpriteDataPtr:        ; please note - self modifying code LDA $FFFF,Y SScreenAddPtr:         ; please note - self modifying code STA $FFFF,X       ; is ->   STA  ScreenAddPtr+1,X DEX BPL SNMW_CheckHeight SNMW_AtCharPos: SEC LDA SScreenAddPtr+1 SBC #$80 STA SScreenAddPtr+1 LDA SScreenAddPtr+2 SBC #2 STA SSCreenAddPtr+2 LDX #7 SNMW_CheckHeight: DEY BPL SNMW_Height DEC WIDTH BEQ SNMW_End ; move to the next column CLC LDA SSpriteDataPtr+1 ADC HEIGHT STA SSpriteDataPtr+1 LDA SSpriteDataPtr+2 ADC #0 STA SSpriteDataPtr+2 LDA SCREENADD CLC ADC #8 STA SCREENADD STA SScreenAddPtr+1 LDA SCREENADD+1 ADC #0 STA SCREENADD+1 STA SScreenAddPtr+2 LDX XOFFSET JMP SNMW_Width SNMW_End: RTS ;---   ; SpriteWipe - a Sprite number ;---   SpriteWipe: STA  SCRATCH1 CLC LDA  #SPRArray ADC  #0 STA  TEMPPTR+1 LDY  #SPRBLK_XOFFBACK LDA  (TEMPPTR),Y STA  XOFFSET LDY  #SPRBLK_SCRBACK LDA  (TEMPPTR),Y STA  SCREENADD INY LDA  (TEMPPTR),Y STA  SCREENADD+1 LDY  #SPRBLK_WIDTH LDA  (TEMPPTR),Y STA  WIDTH INY LDA  (TEMPPTR),Y STA  HEIGHT Sprite_Blank: ; now store screen address in code LDA SCREENADD STA ScreenAddPtr2+1 LDA SCREENADD+1 STA ScreenAddPtr2+2 LDX XOFFSET SWipe_Width: LDY HEIGHT DEY SWipe_Height: LDA #$00 ScreenAddPtr2:         ; please note - self modifying code STA $FFFF,X         ; is ->   STA  ScreenAddPtr+1,X SWipe_SkipWrite: DEX BPL SWipe_CheckHeight SWipe_AtCharPos: SEC LDA ScreenAddPtr2+1 SBC #$80 STA ScreenAddPtr2+1 LDA ScreenAddPtr2+2 SBC #2 STA SCreenAddPtr2+2 LDX #7 SWipe_CheckHeight: DEY BPL SWipe_Height DEC WIDTH BEQ SWipe_End ; move to the next column LDA SCREENADD CLC ADC #8 STA SCREENADD STA ScreenAddPtr2+1 LDA SCREENADD+1 ADC #0 STA SCREENADD+1 STA ScreenAddPtr2+2 LDX XOFFSET JMP SWipe_Width SWipe_End: RTS ;---   ;  SpriteCalcScreenPos: ;   calculates the screen address - please note that ;   xpos($75) and ypos($76) need to be set up before. ;   This also uses $70+$71 for the screen address ( screenAdd ) ;   ;---    SpriteCalcScreenPos: ; reset the screen address ...       LDA  #SCREENLOW STA SCREENADD LDA #SCREENHIGH STA SCREENADD+1 ; now calculate the Y position in chars ( *640 ) and add ; to the screen Address LDA YPOS AND #$f8 LSR LSR TAY CLC LDA LookUp640, Y       ADC  SCREENADD STA SCREENADD INY LDA LookUp640,Y ADC SCREENADD+1 STA SCREENADD+1 ; now the X multiply then addition to screen address `MUL8ADDTOADDRESS XPOS, SCREENADD ; finally the first 3 bits of the YPos LDA YPOS AND #$07 CLC ADC SCREENADD STA SCREENADD LDA SCREENADD STA SCREENADD_BACK LDA SCREENADD+1 STA SCREENADD_BACK+1 RTS ;---   ;    ;  Sprite_SetFlag ;    A - SPrite slot * 16 ;    X - bits to set... ;   ;---    Sprite_SetFlag: STX SCRATCH1 CLC ADC #SPRBLK_FLAG TAX LDA SprArray,X ORA SCRATCH1 STA SPrArray,X RTS ;---   ; TOTAL_SPRITE_SPACE = 8 * 15 sprites = 240 bytes SPRArray: .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 SPRActive: .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff           ; the eight active sprites ...     ;--- LookUp640: .incbin "LookUpTable640" SpriteData: .incbin "Sprites" ;---