Jump to content
IGNORED

Problem with vertical sprite positioning.


Recommended Posts

I'm trying to use the sprite positioning routine from this thread:

http://www.atariage.com/forums/index.php?showtopic=38020

 

I attached an example program that shows the problem. Whenever I begin pulling data from the table where the sprite data is kept, the table is treated like it extends full screen. I'm pretty sure that I'm misusing tables, so if there's some place that has good documentation on how to use them correctly that would help also.

example.bin

example.txt

Edited by R. Jones
Link to comment
Share on other sites

I'm trying to use the sprite positioning routine from this thread:

http://www.atariage.com/forums/index.php?showtopic=38020

 

I attached an example program that shows the problem. Whenever I begin pulling data from the table where the sprite data is kept, the table is treated like it extends full screen. I'm pretty sure that I'm misusing tables, so if there's some place that has good documentation on how to use them correctly that would help also.

There are a few problems you need to fix, and there are some ways you can improve the code. First, the problems...

 

The program is drawing too many lines-- z26 says it's drawing 292 lines. This is mainly caused by where you've put the code to initialize the zero-page memory. To fix that, cut the code that begins with "Start," down 19 more lines (20 in all), and paste that code right below the "Reset" line. That section of code only needs to be performed once, before you enter your loop, and it contains a loop ("ClearMem") that will cause the vertical blanking to run too long (hence the 292 lines).

 

Also, in the beginning of the "StartOfFrame" section, you have a "lda #0" and "sta VBLANK." You need to cut those 2 lines, because they're turning off VBLANK just before you turn on VSYNC, and you need to leave VBLANK turned on during the VSYNC.

 

Then go down to the bottom of where you're drawing 37 blank lines, and paste the 2 lines that you just cut ("lda #0" and "sta VBLANK"), putting them after the 37th "sta WSYNC" line.

 

Next, just above "ScanLoop," change "LDY #191" to "LDY #192" so you'll draw 192 scanlines of picture, rather than just 191 scanlines.

 

Now go down a few lines. Add "tax" between ".MBDraw3" and "lda BigHeadGraphic,y" and then change that "y" to "x" ("lda BigHeadGraphic,x"). This is the reason it acts like it's trying to draw the head for the entire height of the screen, because you're using "y" as the index to your scanline loop (to draw 192 scanlines), so "y" is going to vary from 192 to 0 in descending order. Instead, that section of code between "ScanLoop" and ".MBDraw3" is computing the correct value to use for indexing the head, but the value is being computed in the accumulator, so after you've calculated it, you need to transfer it from the accumulator into the "x" register (because you're already using the "y" register as a counter for drawing 192 scanlines).

 

Then recompile with those changes and rerun it.

 

Now, on to a couple of ways you can improve the code...

 

Instead of saying "sta WSYNC" so many times in a row, it's better to use "sta WSYNC" just once, and put it in a loop, as follows:

 

			 ; 37 scanlines of vertical blank...

		   ldy #37

Draw37BlankLines

		   sta WSYNC

		   dey

		   bne Draw37BlankLines

 

			 ; 30 scanlines of overscan...

		   ldy #30

Draw30BlankLines

		   sta WSYNC

		   dey

		   bne Draw30BlankLines

 

Actually, it's better still to use the interval timer (INTIM) instead of using WSYNC in a loop, because if you use INTIM, you can use that time to do game-processing logic that could last for unpredictable lengths of time depending on which branches were taken, etc., and then check the timer when you're done to see if it's time to go on to the next part of the kernel, as follows:

 

			 ; 37 scanlines of vertical blank...

		   ldy #44
		   sty TIM64T

		 ; Insert some game-processing stuff here...

		 ; ... and after you're done, continue as follows...

Draw37BlankLines

		   ldy INTIM
		   bne Draw37BlankLines

		   sta WSYNC

 

			 ; 30 scanlines of overscan...

		   ldy #36
		   sty TIM64T

		 ; Insert some more game-processing stuff here...

		 ; ... and after you're done, continue as follows...

Draw30BlankLines

		   ldy INTIM
		   bne Draw30BlankLines

		   sta WSYNC

 

This is a little bit harder to understand, but it's really pretty simple. In the first case, you want 37 blank lines, and each line is 76 cycles long, so multiply 37 by 76 to find the number of cycles (2812). So you want to tell the VCS to wait for 2812 cycles, by setting the interval timer for that long (more or less). But you can only use 1-byte values, so 2812 is too big. You can set the timer for four types (lengths) of intervals-- 1 cycle per interval, 8 cycles per interval, 64 cycles per interval, or 1024 cycles per interval. 2812 divided by 1 is too big (2812, more than 1 byte), and 2812 divided by 8 is still too big (351.5, still more than 1 byte), but 2812 divided by 64 is okay (43.9375, which we'll call 44). In fact, 64 cycles is the closest interval length to 76 cycles (1 scanline), so that's the interval length you would normally use to wait a certain number of scanlines. That's why you say "ldy #44" and "sty TIM64T," to set the interval timer to 44 intervals of 64 cycles each. Even though 44 times 64 is 2816-- a little bit longer than 37 lines (2812 cycles), the timer decrements by 1 as soon as you set it, so setting it to 44 intervals of 64 cycles will actually give you *43* intervals of 64 cycles (2752 cycles, more than 36 lines but less than 37 lines). So once the timer has counted down to 0, you need to do a "sta WSYNC" to finish off the 37th line.

 

It's the same with the 30 lines-- 30 * 76 = 2280, and 2280 / 64 = 35.625, so set TIM64T to 36.

 

Next, the color changes are happening in the visible area at the far left of the screen, and the last line of picture is getting blanked right after it starts being drawn, so you can cut the "STA WSYNC" that's just after "ScanLoop," and paste it just in front of "sty COLUBK" (right after ".skipMBDraw3"). Now the color changes will happen before the line starts being drawn.

 

You're actually turning on VBLANK before that last line of picture gets drawn, but it's going to be a black line anyway, so we won't worry about that.

 

Finally, there are some RAM variables and a data table that you aren't actually using in the program, so you could take them out... but I'll leave them in, since I don't know if you're planning to use them. The modified code, with the changes described above, is attached below.

 

Michael

problem_with_vertical_sprite_positioning.txt

problem_with_vertical_sprite_positioning.bin

Link to comment
Share on other sites

[ . . . ]

 

Now go down a few lines. Add "tax" between ".MBDraw3" and "lda BigHeadGraphic,y" and then change that "y" to "x" ("lda BigHeadGraphic,x"). This is the reason it acts like it's trying to draw the head for the entire height of the screen, because you're using "y" as the index to your scanline loop (to draw 192 scanlines), so "y" is going to vary from 192 to 0 in descending order. Instead, that section of code between "ScanLoop" and ".MBDraw3" is computing the correct value to use for indexing the head, but the value is being computed in the accumulator, so after you've calculated it, you need to transfer it from the accumulator into the "x" register (because you're already using the "y" register as a counter for drawing 192 scanlines). [ . . . ]

Thank you, Mike.

 

I kind of understood what I was doing wrong, but the ways I set about fixing it kept breaking things. You have no idea how much that helped. I'm going to look more at your other suggestions, too. My attention is just focused on the display loop(s) at the moment.

 

Here's the replacement loop with your advice:

ScanLoop 
STA WSYNC 	
	


CenterHoleDraw			; This draws a hole in the center line.  Must be drawn early, so not to tear.
   tya				   ;scanline to accumulator, 2
   sbc CenterHoleYPos		 ;the elevation of the center hole, 3
   adc #30					;the height of the center hole, 2
   bcs .DrawCenterHole		  ; draw it?,2(3)

   lda #%10000000		;The center line is draw, 5
   sta PF2	 ; 3
   sec				   ; 2
   bcs .DontCenterDrawHole		;And the hole rountine is skipped, 3

.DrawCenterHole	; Draw the center hole
   lda #000000		; 5
   sta PF2	 ; 3
   nop;2
   nop;2
   
.DontCenterDrawHole



EnemyDraw					;The antagonist is drawn from GRP1.
   tya				   ; 2
   sbc EnemyYPos		 ; 3
   adc #EnemyHeight   ; 2
   tax
   bcs .DrawEnemy		  ; 2(3)

   nop				   ; 2
   nop				   ; 2
   sec				   ; 2
   bcs .DontDrawEnemy		; 3

.DrawEnemy	
   lda BigHeadGraphic,x		; 5
   sta GRP1	 ; 3
   
.DontDrawEnemy



PrizeDraw
   sec				   ; 2, The prize is drawn from GRP0. 

   tya				   ; 2
   sbc PrizeYPos		 ; 3
   adc #PrizeHeight   ; 2
   tax
   bcs .DrawPrize		  ; 2(3)

   nop				   ; 2
   nop				   ; 2
   sec				   ; 2
   bcs .DontDrawPrize		; 3

.DrawPrize
   lda GraphicPlaceHolder,x		; 5
   sta GRP0	 ; 3
   lda ColourPlaceholder,x;5, The prize is multicolour.
   sta COLUP0; 3
   
.DontDrawPrize



DEY		
BNE ScanLoop

 

Thanks again,

- Robert

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...