Jump to content
IGNORED

How can I draw my sprites in less cycles?


Recommended Posts

I am drawing these 2 sprites and want to reduce the cycles in the kernel.

 

What are the better methods?

 

I am looping through x 96 times...

 

Thanks,

 

.IsInsideSpriteP0Check:      ;   check if should render sprite player0
	txa                      ; 2 transfer X to A
	sec                      ; 2 make sure carry flag is set
	sbc RiderYPos            ; 3 subtract sprite Y coordinate
	cmp #RIDER_HEIGHT        ; 2 are we inside the sprite height bounds?
	bcc .DrawSpriteP0        ; 2 if result < SpriteHeight, call subroutine
	lda #0                   ; 2 else, set lookup index to 0
.DrawSpriteP0:
	tay                      ; 2 load Y so we can work with pointer
	lda (RiderSpritePtr),Y   ; 5 load player bitmap slice of data
	sta GRP0                 ; 3 set graphics for player 0

.IsInsideSpriteP1Check:      ; check if should render sprite player1
    txa                      ; 2 transfer X to A
    sec                      ; 2 make sure carry flag is set
    sbc CoasterYPos          ; 3 subtract sprite Y coordinate
    cmp #COASTER_HEIGHT      ; 2 are we inside the sprite height bounds?
    bcc .DrawSpriteP1        ; 2 if result < SpriteHeight, call subroutine
    lda #0                   ; 2 else, set index to 0
.DrawSpriteP1:
    tay						  ; 2
    lda (CoasterSpritePtr),Y  ; 5 load player bitmap slice of data
    sta GRP1                  ; 3 set graphics for player 0
    lda (CoasterColorPtr),Y   ; 5 load player color from lookup table
    sta COLUP1                ; 3 set color for player 0 slice	

 

Thank you!

Link to comment
Share on other sites

1 hour ago, Andrew Davie said:

Just in case you weren't aware; your cycle counts look OK... but remember the branch is +1 cycle when taken, and +1 more cycle if the branch crosses a page boundary.

Thanks for responding. I will see if I can get that method to work.

 

I thought I saw another method that took 15 cycles??? Did I dream that? ?

Link to comment
Share on other sites

22 minutes ago, Robert Gremillion said:

I thought I saw another method that took 15 cycles??? Did I dream that? ?


Using a mask takes 13 cycles for monochrome player, 21 for multicolor. Trade off is it uses more RAM and ROM. 
 

 

  • Like 1
Link to comment
Share on other sites

21 minutes ago, SpiceWare said:


Using a mask takes 13 cycles for monochrome player, 21 for multicolor. Trade off is it uses more RAM and ROM. 
 

I don't understand what's happening with a Mask.

 

I have this sprite that can be monochrome.

 

RiderSprite:
    .byte #%00000000         ;
    .byte #%00011000         ;    ##  
    .byte #%00100100         ;   #  #
    .byte #%01101010         ;  ## # #
    .byte #%11100110         ; ##  ##
    .byte #%11101010         ; ## # #
    .byte #%10100101         ; # #  # #
    .byte #%10011001         ; #  ##  #
    .byte #%10000001         ; #      #  

 

Does the mask match the size of the sprite? Or does it match the size of the arena?

 

Thanks!

 

21 minutes ago, SpiceWare said:

 

 

Link to comment
Share on other sites

the mask is a bunch of $00, followed by enough $FF to match the height of your image, followed by a bunch of $00.

 

When you set the pointer for the mask you calculate it so that the $FF section will be read during the same scanlines that the graphics should show up.

 

During the kernel:

  • Above the graphic the AND (MASK),y points at a $00. Any value AND $00 = $00, so no graphic is put into GRP0.
  • During the graphic the AND (MASK),y points at a $FF. Any value AND $FF = the value, so the graphic data is put into GRP0.
  • Below the graphic the AND (MASK),y points at a $00. Any value AND $00 = $00, so no graphic is put into GRP0.

 

Do note that if your use a mask large enough to cover the screen you'll end up crossing the page, which adds a +1 to the cycle count, so it would be 14 cycles instead of 13.

 

For Stay Frosty I used zones (each platform is the bottom of a zone), so the mask only had to be large enough for the biggest zone. Using zones uses more RAM as you need a graphic pointer and a mask pointer for each zone.

 

 

If you're not able to grasp it I can write you up a quick demo, but it won't be until next week as I have family in town.

 

  • Like 3
Link to comment
Share on other sites

5 minutes ago, SpiceWare said:

If you're not able to grasp it I can write you up a quick demo, but it won't be until next week as I have family in town.

 

I will play around with it this weekend and see if I can "get" it.

 

I did create a post asking for a simple Mask example using my Sprite.

 

I might need help next week if I cannot get it.

 

Thank you for responding!

 

P.S. I see you are in Houston! I am in Clear Lake!

Link to comment
Share on other sites

2 hours ago, Robert Gremillion said:

Yeah, I guess I need help.  The part that is messing me up is setting the Mask pointer.

 

Was able to whip up a quick demo using Step 3 of my Collect Tutorial as a starting point.

 

mask.zip

 

 

  • BLUE = player 0, used to show graphics without the mask applied

  • BLACK = ball, used to show the mask

  • GREEN = player 1, used to show graphics with the mask applied

1156683224_ScreenShot2022-05-06at4_51_05PM.thumb.png.45369a024be81f22548252443b307e7c.png

 

 

 

If you move the the player up, the mask moves up as well:

 

47480509_ScreenShot2022-05-06at4_51_09PM.thumb.png.60bfc9d70f94bd4f2c6f0fb2d7cd22a2.png

 

I purposely made the 0 padding below the player too small so you can see what happens if you don't have enough 0s:

 

        ds 100, $00 ; below the player   
RiderMask:
        ds 8, $ff
        ds 190, $00 ; above the player       

 

1282303844_ScreenShot2022-05-06at4_51_13PM.thumb.png.147b1c81bfb05f7688d46638596addb3.png

 

The graphics and the mask are purposely intermingled with the code. I would usually put then together towards the end, along side the digit graphics, but then a bunch of 0s show up with the graphics making it difficult to see what's going on:

 

1384225233_ScreenShot2022-05-06at4_57_21PM.thumb.png.5abcb16e81553eb901dc4c8c986cac39.png

 

 

 

  • Like 2
  • Thanks 1
Link to comment
Share on other sites

2 hours ago, SpiceWare said:

Was able to whip up a quick demo using Step 3 of my Collect Tutorial as a starting point.

I was able to make it work!!! I made the sprites both 8 lines high so I could share the same mask graphic.

 

I have some weird issues when it falls through the screen.

 

My main goal was to reduce the drawing speed so I could draw double track lines. You can see the before and after videos here...

 

 

 

I don't have enough clock cycles to color the coaster sprite. I think it looks better with the gray bottom.

 

 

    ldy #96                  ; X counts the number of remaining scanlines	
	
.GameLineLoop:

;--------------------------------------------------------------------------------------------
.SetupPlayfield:

	sta WSYNC                ; first scanline
       
	ldx PFOffset		; 3 03
	lda $80,x		; 4 07
	sta PF0			; 3 10
	lda $81,x		; 4 14
	sta PF1			; 3 17
	lda $82,x		; 4 21
	sta PF2			; 3 24 ; set PF0, PF1, and PF2 playfield/terrain pattern
	
    lda (RiderSpritePtr),y	; 5 29
	and (RiderMaskPtr),Y	; 5 34
 	sta GRP0 		; 3 37

	lda $83,x		; 4 41
	sta PF0			; 3 44
	lda $84,x		; 4 48
	sta PF1			; 3 51
	lda $85,x		; 4 54
	sta PF2			; 3 57 ; set PF0, PF1, and PF2 playfield/terrain pattern
	
    lda (CoasterSpritePtr),Y	; 5 62
	and (CoasterMaskPtr),Y	; 5 67
  	sta GRP1		; 3 70 
	;lda (CoasterColorPtr),y
	;sta COLUP1             


;--------------------------------------------------------------------------------------------
	sta WSYNC					; second scanline
	
	ldx PFOffset
	lda $80,x
	sta PF0
	lda $81,x
	sta PF1
	lda $82,x
	sta PF2                  ; set PF0, PF1, and PF2 playfield/terrain pattern
	
	nop
	nop
	
	lda $83,x
	sta PF0
	lda $84,x
	sta PF1
	lda $85,x
	sta PF2                  ; set PF0, PF1, and PF2 playfield/terrain pattern
	
	cpy #55 ; compare x to 55
	bcs .SkipSetPlayfields ; 
	cpy #44 ; compare x to 44
	bcc .SkipSetPlayfields ; 
	
	lda PFOffset				; this code is upping the offset by 6
	sbc #6						; move this code near end of frame
	sta PFOffset				; update if over x over 45 lines
								; stop incrementing if x over 55 lines?

.SkipSetPlayfields	

    dey                      ; Y--
    bne .GameLineLoop        ; repeat next main game scanline until finished

 

 

I don't know if I will keep the double lines or not. If I get rid of them I guess I could add a ball or missile?

 

Thanks for helping me!!!!

  • Like 2
Link to comment
Share on other sites

37 minutes ago, Robert Gremillion said:

I don't have enough clock cycles to color the coaster sprite. I think it looks better with the gray bottom.

I think that if that first part had the color change added back in, and it was EXACTLY 76 cycles (which it almost is) then the WSYNC for the second scanline could be left out and you'd still be starting exactly on cycle 0 for that line.

 

That said, I'm not really a 2600 programmer, but I've ported a few to 8-bits...

 

EDIT: And I suppose the 'ldx PFOffset' would need to be moved to BEFORE the first WSYNC to give the extra time...

Edited by glurk
Link to comment
Share on other sites

9 hours ago, glurk said:

EDIT: And I suppose the 'ldx PFOffset' would need to be moved to BEFORE the first WSYNC to give the extra time...

 

I did have ldx PFOffset above the first WSYNC in one of my tests but I still didn't have enough time to get the coaster color set up.

 

I think the two commented out lines take 8 cycles to perform.

 

10 hours ago, Robert Gremillion said:

;lda (CoasterColorPtr),y

;sta COLUP1

There was one more method to show the sprite without a mask.

 

I don't know if that can be used here also to save 5 cycles from the rider being drawn???

 

Thanks for responding!

Link to comment
Share on other sites

If your bankswitching scheme has lots of free ram, can also have a huge screen height sized sprite that the kernel draws every line with no decisions required. It could be 192 bytes or 96 bytes depending if it's a 1 or 2 line kernel. The kernel loads sprite data from ram with a LDA ABCD,X or LDA ABCD,y format, depending on which register manages the screen line. Then it's up to the pre-kernel processing to blot out sections in the RAM where there is no sprite needed with "0's". The lack of decision making within the kernel allows the most efficient time-wise method to draw a sprite. But, it comes at a cost of wasting ram and precious overscan/vblank time on "rendering" the sprite.

  • Like 1
Link to comment
Share on other sites

The last example you posted has a 2-line kernel... in which you're setting both sprites on only one of those lines.

 

If you're okay with the double resolution that provides, you can split your sprite graphics/color across those two lines.  Do sprite 0 color/graphics one line 1 and do sprite 1 color/graphics on line 2.

 

My Congo Bongo POC does that for it's kernel.

  • Thanks 1
Link to comment
Share on other sites

1 minute ago, Robert Gremillion said:

My dream is to make something that doesn't need bankswitching.

 

The 4K ROM / 128byte RAM programming model is the purest form of 2600 programming. It is thrilling and humbling to see programmers still trying to push the console to its limits within the very restricted boundaries, despite there being a growing array of "turbocharger" addons available these days. 

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

50 minutes ago, splendidnut said:

The last example you posted has a 2-line kernel... in which you're setting both sprites on only one of those lines.

 

If you're okay with the double resolution that provides, you can split your sprite graphics/color across those two lines.  Do sprite 0 color/graphics one line 1 and do sprite 1 color/graphics on line 2.

 

My Congo Bongo POC does that for it's kernel.

I tried to re-arrange the lines like this but had no luck getting the track lines to look OK.

 

I will try again on Sunday and see if I can squeeze this down.

 

Thanks for responding!!!

Link to comment
Share on other sites

  • 3 months later...
On 5/7/2022 at 7:59 AM, MarcoJ said:

The 4K ROM / 128byte RAM programming model is the purest form of 2600 programming. It is thrilling and humbling to see programmers still trying to push the console to its limits within the very restricted boundaries, despite there being a growing array of "turbocharger" addons available these days. 

See It's Conner time which complies with those ristrictions, includes a (Hopefully not terrible) sound track and is only just over 2K.

 

Link to comment
Share on other sites

On 5/7/2022 at 7:58 AM, splendidnut said:

The last example you posted has a 2-line kernel... in which you're setting both sprites on only one of those lines.

 

If you're okay with the double resolution that provides, you can split your sprite graphics/color across those two lines.  Do sprite 0 color/graphics one line 1 and do sprite 1 color/graphics on line 2.

 

My Congo Bongo POC does that for it's kernel.

I think you need to mention that it means while you have a 2-scanline kernal, you can have finer vertical movement because you have VDELP0 and VDELP1. So you can have an 8 bit YPOS instead of a 7 bit one.

Link to comment
Share on other sites

37 minutes ago, Ecernosoft said:

I think you need to mention that it means while you have a 2-scanline kernal, you can have finer vertical movement because you have VDELP0 and VDELP1. So you can have an 8 bit YPOS instead of a 7 bit one.

I don't need to mention anything... you just did.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...