Jump to content



0

Problem with vertical sprite positioning.


2 replies to this topic

#1 R. Jones OFFLINE  

R. Jones

    Star Raider

  • 53 posts

Posted Sun Aug 5, 2007 3:21 PM

I'm trying to use the sprite positioning routine from this thread:
http://www.atariage....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.

Attached Files


Edited by R. Jones, Sun Aug 5, 2007 3:22 PM.


#2 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,543 posts
  • Location:Georgia, USA

Posted Sun Aug 5, 2007 8:02 PM

View PostR. Jones, on Sun Aug 5, 2007 5:21 PM, said:

I'm trying to use the sprite positioning routine from this thread:
http://www.atariage....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

Attached Files



#3 R. Jones OFFLINE  

R. Jones

    Star Raider

  • 53 posts

Posted Mon Aug 6, 2007 12:09 PM

View PostSeaGtGruff, on Sun Aug 5, 2007 9:02 PM, said:

[ . . . ]

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




1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users