Jump to content
IGNORED

Multi-Sprite Trick behavior


shazz

Recommended Posts

Hi,

 

Sorry guys, I'm back again ! icon_smile.gif

 

So, now I'm playing with the multi-sprite trick.... I successfully coded a stable 17 sprites display routine but I don't really understand how. I mean using "test and try", I finished to have a stable display (with a constant step between sprite, no overlapping...) but I don't understand why....

 

source10.png

 

I look at the working timings but it doesn't make sense to me :

 

 LDA #%00100011 ; missiles to 8 pixels + sprites close * 3
STA NUSIZ0
STA NUSIZ1

LDY #227 ; boucle sur les 227 scanlines PAL
LDX ScrollOffset

STA WSYNC

ScanlineLoop:

LDA Colors,X ; 4 (4)
STA COLUP0 ; 3 (7)
STA.w COLUP1 ; 4 (11)
LDA Font,X ; 4 (15)

STA GRP0 ; 3 (18)
STA GRP1 ; 3 (21)

INX ; 2 (23)

STA RESP0 ; 3 (26)
STA RESP1 ; 3 (29)
STA RESP0 ; 3 (32)
STA RESP1 ; 3 (35)
STA RESP0 ; 3 (38)
STA RESP1 ; 3 (41)
STA RESP0 ; 3 (44)
STA RESP1 ; 3 (47)
STA RESP0 ; 3 (50)
STA RESP1 ; 3 (53)
STA RESP0 ; 3 (56)
STA RESP1 ; 3 (59)
STA RESP0 ; 3 (62)
STA RESP1 ; 3 (65)
STA RESP0 ; 3 (68)
STA RESP1 ; 3 (71)

DEY ; 2 (73)
BNE ScanlineLoop ; 3 (76)

 

is there any logic ? a cycle before or after, one STA RESPx less and everything is screwed.

 

I read carefully the guide from Paul but I did not find the light...yet...

Edited by shazz
  • Like 2
Link to comment
Share on other sites

I've been where you've been before with this, shazz.

 

 

About ~1.5 years ago I started playing around RESPx bashing for a demo I was working on. I knew that the Kabobber prototype used some of this, but in trying it's routine I could never get sprites to stretch all the way across the screen. The key discovery I made was that 3 copies close had to be used for the sprites instead of 2 copies close. After that it was a matter of fiddling around until I found the right cycle to start the bashing at.

 

 

The screen width of the 2600 is 160 pixels. Each bash of RESPx takes 3 machine cycles or 9 pixels. At 18 sprites times 9 pixels you get 162. If you are wrapping sprites around the screen then 2 pixels will not displayed, and you have to account for that. In Circus AtariAge I handle this by correcting the first sprites graphics by a 2 pixel shift before re-writing the graphics for the remaining sprites:

 

 lax  (tB_BalloonGfxs),Y
 asl  ; shift 2 pixels
 asl
 sta  GRP1  ; 1st sprite
 nop  $EA
 stx  GRP1  ; 2nd sprite
 dey
 sty  RESP1
 nop  $EA
 sty  RESP1

 

 

In CAA I am flickering 9 sprites at a time. The reason is I have to mask these sprites with an asynchronous playfield, and draw the jumper with P0 as well. I am using a bunch of kernels so that P0 is absolutely never covered up at any time by the masking, but that is a little off topic here. ;)

 

 

You can check out this rom for seeing all 18 sprites being smoothly scrolled. I don't think anyone else has ever done that:

 

http://atariage.com/forums/topic/207391-circus-atariage-2600/?do=findComment&comment=2677582

 

 

Finally, you can also jump into the end of the line to start the positioning instead of burning an entire blank line:

 

.loopSprites:
;---------------------------------------
 dec  $2E    ;5  @4
 lax  (gfxPtr),Y  ;5  @9
 asl		 ;2  @11
 asl		 ;2  @13
 stx  GRP0   ;3  @16
 sta  GRP1   ;3  @19
 dey		 ;2  @21
 stx  GRP1   ;3  @24
 sta  RESP0  ;3  @27
 sta  RESP1  ;3  @30
 sta  RESP0  ;3  @33
 sta  RESP1  ;3  @36
 sta  RESP0  ;3  @39
 sta  RESP1  ;3  @42
 sta  RESP0  ;3  @45
 sta  RESP1  ;3  @48
 sta  RESP0  ;3  @51
 sta  RESP1  ;3  @54
 sta  RESP0  ;3  @57
 sta  RESP1  ;3  @60
StartSprites:
 sta  RESP0  ;3  @63
 sta  RESP1  ;3  @66
 sta  RESP0  ;3  @69
 sta  RESP1  ;3  @72
 bne  .loopSprites  ;2³ @74/75

Link to comment
Share on other sites

is there any logic ? a cycle before or after, one STA RESPx less and everything is screwed.

 

I read carefully the guide from Paul but I did not find the light...yet...

A while back I spent some time playing with RESPx and trying to understand the hardware notes by Andrew Towers ("Atari 2600 TIA Hardware Notes," which you can find on the web). I described my understanding of how this works in the other thread that SpiceWare linked to, but here's a revised version. To keep things simple, I'll focus on RESP0 and ignore RESP1 initially. I'm also assuming that RESP0 isn't being hit during HBLANK or too late on the line (such that the player ends up being positioned to the far left).

 

When you do STA RESP0, the player0 sprite gets repositioned at the color clock that's +5 after wherever the STA ended-- e.g., if STA RESP0 begins on cycle 23 (as in your code above), the cycle after STA RESP0 ends is cycle 26 (23+3=26), which is color clock 78 (3*26), so player0 gets positioned at color clock 83 (78+5=83). The first 68 color clocks are the HBLANK persiod, so that would be pixel number 15 on the visible scan line (83-68=15).

 

The reason for the +5 delay is explained in Andrew Tower's hardware notes, but we'll just accept it without trying to fathom the why of it-- but I recommend reading (and rereading several times) Andrew Towers' document.

 

As explained by Andrew Towers, there are "start" signals which trigger the TIA to begin drawing the various extra copies of player0, but when you strobe RESP0 there's no "start" signal to trigger the drawing of the main copy-- it will get drawn "automatically" when player0's horizontal position counter resets itself 160 active color clocks later. So this means that if you hit RESP0 only once on a line, you do *not* get the main copy of player0 on that line-- instead, the main copy doesn't show up until the next line. This isn't the same as "after the next HBLANK occurs," but rather when the player0 counter has finished counting 160 clocks and then resets itself. (So for example, if you hit RESP0 too late on line 15-- such that player0 is positioned at the left of the screen-- then player0 won't show up until line *17*, *not* line 16.)

 

On the other hand, if you're displaying two or more copies of player0 (the main copy plus one or more others), the extra copies *will* show up after you hit RESP0, since the TIA generates "start" signals for them. But this is controlled by what you've set NUSIZ0 to-- i.e., "start" signals will *not* be generated for any copies you aren't displaying.

 

The "start" signal is active for 4 color clocks, and the drawing of the sprite begins *after* the "start" signal ends. For missiles and the ball this is immediate, but the players require 1 extra color clock before they start drawing. Hence, RESM0 has a delay of 4 pixels (the "start" signal's duration), but RESP0 has a delay of 5 pixels (the "start" signal's duration plus 1 extra color clock).

 

Assuming for the sake of argument that you could enable all three extra copies of RESP0, the timing of the "start" signals would be as follows (the color clock numbers shown are relative to the current position on the line, *not* relative to HBLANK):

 

color clock 0: STA RESP0 instruction begins, lasting 3 cycles (9 color clocks)

color clock 9: "start" signal for copy 0 (main copy) begins here and lasts for 4 color clocks - but not after RESxx, only after the position counter resets itself

...

color clock 13: "start" signal is deactivated - missiles and the ball will begin here but players need 1 more color clock before they begin drawing

color clock 14: copy 0 (main copy) will begin here

...

color clock 22: copy 0 (main copy) has finished being drawn

...

color clock 25: "start" signal for copy 1 begins here if the "close" copy of the sprite is enabled

...

color clock 29: "start" signal deactivated

color clock 30: copy 1 ("close" or "near" copy) begins here

...

color clock 38: copy 1 has finished

...

color clock 41: "start" signal for copy 2 begins here if the "middle" copy of the sprite is enabled

...

color clock 45: "start" signal deactivated

color clock 46: copy 2 ("middle" or "medium" copy) begins here

...

color clock 54: copy 2 has finished

...

color clock 73: "start" signal for copy 3 begins here if the "far" copy of the sprite is enabled

...

color clock 77: "start" signal deactivated

color clock 78: copy 3 ("far" copy) begins here

...

color clock 86: copy 3 has finished

 

Now, even though strobing RESxx doesn't trigger a "start" signal, it just so happens that if you strobe RESxx at just the right time-- such that the RESxx instruction ends while a "start" signal is active-- that "start" signal will cause copy 0 (main copy) to be drawn. It can be argued that this is actually copy 1 (or 2 or 3) being drawn (depending on which "start" signal was active when RESxx ended), but for all intents and purposes it's copy 0 that's drawn, since the other copies will follow as expected.

 

Thus, the following will cause copy 0 to be drawn "right away":

 

; example 1 - hitting RESP0 during copy 1's "start" signal
  STA RESP0
  sleep 3
  STA RESP0

; example 2 - hitting RESP0 during copy 2's "start" signal
  STA RESP0
  sleep 8
  STA RESP0

; example 3 - hitting RESP0 during copy 3's "start" signal
  STA RESP0
  sleep 19
  STA RESP0

 

Now, "sleep 3" is the same length as STA RESP1, so if you do

 

  STA RESP0
  STA RESP1
  STA RESP0
  STA RESP1
  STA RESP0
  STA RESP1
; etc.

 

you will get the main copies of player0 and player1 over and over again, since each RESP0 or RESP1 after the first ones will end while the "start" signals for copy 1 of player0 or player1 are still active.

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

Thanks for all those explanations !!! I think I read those answers at least 10 times + 3 times the TIA HW Notes.... But there is still some stuff unclear, so sorry if you need to repeat again.

 

1. The "Main" copy

 

I well understood the Main copy behavior, ok for this.

 

2. The "Close" copy

 

This one is still fuzzy... I understood that the TIA, if multi-copies set (NUSIZ), "generates the Start signal for copies of the player graphics at 12, 28, 60, and 160 CLK after the Position

Counter has been reset, in order to trigger the 'close', 'medium', 'far' and 'main' copies". But I'm not sure when exactly the PosCounter is resetted relatively to the STA RESP0 end.

 

in your example, it happens at color clock 30 so 21 clocks cycles after the end of the STA.... And I'm not able to recalculate that.

 

Andrew writes : "They will appear 4+12+1=17 and 4+28+1=33 pixels after each RESPn CLK arrives in the TIA (it takes 4 extra CLK to reset the counter, and 1 extra CLK to start the graphics output)."

So I get my 12 pixels later and my 4+1 (start signal length + color delay) but 17 != 21...

 

More over, if I follow the table (and the checks I did by code), if I end my STA @78 (CPU 26), the close copy should appear at pixel 31 so TIA cycle 99, so 21 cycles after, as you wrote...

 

So can you explain me those 21 TIA cycles ?

 

Aside note : omegametrix, your Circus stuff is amazing, I'm so faaaaar so understand how it works.... but I will :)

Link to comment
Share on other sites

 


2. The "Close" copy

This one is still fuzzy... I understood that the TIA, if multi-copies set (NUSIZ), "generates the Start signal for copies of the player graphics at 12, 28, 60, and 160 CLK after the Position
Counter has been reset, in order to trigger the 'close', 'medium', 'far' and 'main' copies". But I'm not sure when exactly the PosCounter is resetted relatively to the STA RESP0 end.

 

The reset occurs as soon as you finish strobing the RESxx register. In the code in your first post, the first STA RESP0 instruction ends at cycle 26-- color clock 78 (3*26), or pixel 10 (78-68)-- so that's where the start signal begins. However, there's no start signal after resetting the position (hence no main copy), but that's where the start signal will occur 1 line later *if* you don't strobe RESP0 again.

 

Assuming you don't strobe RESP0 again, the start signals will occur at the following color clocks:

 

color clock 78 (immediately after the STA RESP0 ends) - main copy's start signal

color clock 94 (16 color clocks after the main copy's start signal) - close copy's start signal

color clock 110 (16 color clocks after the close copy's start signal) - medium copy's start signal

color clock 142 (32 color clocks after the medium copy's start signal) - far copy's start signal

 

But the start signals don't correspond to the actual positions of the sprites-- the ball and missiles begin 4 color clocks later, but the players begin 5 color clocks later because they need 1 extra color clock:

 

color clock 83 - main copy of player0 drawn

color clock 99 - close copy of player0 drawn (if enabled)

color clock 115 - medium copy of player0 drawn (if enabled)

color clock 147 - far copy of player0 drawn (if enabled)

 

 

in your example, it happens at color clock 30 so 21 clocks cycles after the end of the STA.... And I'm not able to recalculate that.

Andrew writes : "They will appear 4+12+1=17 and 4+28+1=33 pixels after each RESPn CLK arrives in the TIA (it takes 4 extra CLK to reset the counter, and 1 extra CLK to start the graphics output)."
So I get my 12 pixels later and my 4+1 (start signal length + color delay) but 17 != 21...

 

I think he must be referring to the start signals, not the sprite positions, because otherwise the 12 and 28 numbers don't make sense to me. When you use close spacing the copies are 16 pixels apart, and when you use medium spacing they're 32 pixels apart. The start signal lasts for 4 color clocks, and if we subtract 4 from 16 and 32 we get 12 and 28 as Andrew wrote.

 

 

More over, if I follow the table (and the checks I did by code), if I end my STA @78 (CPU 26), the close copy should appear at pixel 31 so TIA cycle 99, so 21 cycles after, as you wrote...

So can you explain me those 21 TIA cycles ?

The simplest way to explain the 21 color clocks is to think of them as 4+1+16=21. The 4 is for the start signal that *should* come immediately after the RESP0 (except, as already noted, RESP0 doesn't trigger it, it occurs 1 line later when the position counter resets itself). The 1 is for the extra color clock after the start signal ends that's needed before the player is drawn. And the 16 is for the spacing between the main copy and the close copy (although the main copy is 8 pixels wide, so that's 8 pixels for the main copy and 8 "blank" pixels before the close copy begins).

Link to comment
Share on other sites

Thanks, it helps.

I'll keep your explanation (else my brains stay stucked :D) even if Andrew's stuff looks strange as he seems to take into account the 4+1 cycles so the 12, 28 values are still confusing, I'll forget them for the moment.

 

 

Then, still on Andrew's doc, I tried to code what he advises when only write the RESP0 register 3 times :

STA RESP0 ;3 reset P0, call this 0 CLK.

CMP $EA ;3 nop

STA RESP0 ;3 reset P0 again, after 18 CLK.

CMP $EA ;3 nop

STA RESP0 ;3 reset P0 again, after 18 CLK.

 

The visible result of this will be a 'close' copy of P0 shifted right by two pixels from the expected position, followed by a second 'close' copy shifted right by two pixels, and finally a third 'close' copy, not shifted right. There will be an 18 pixel gap between the first two copies of P0, and only a 16 pixel gap before the third copy.

 

In order to fix up the spacing of the final copy, it is necessary to trigger P0 yet again exactly 18 CLK later, but clear GRP0 in the mean time so nothing is drawn.

So as he says, that's right, the first gap is 2 pixels wider. Then I erase GRP0 and wait 18 CLK later (6 CPU clk) but.... it doesn't work, it displays 2 sprites and not 3 sprites well spaced..

 

ScanlineLoop:	
	
	LDA Colors,X		; 4 (4)
        STA COLUP0 		; 3 (7)
	LDA Font,X		; 4 (11)		  
        STA GRP0		; 3 (14)
        
        SLEEP 6			; 6 (20)
        
	STA RESP0		; 3 (23) 
	SLEEP 3
	STA RESP0		; 3 (29) 
	SLEEP 3
	STA RESP0		; 3 (35) 

	; start code to fix 2 pixel gap between close and medium copies
	LDA #0		   	; 2 (37) 
	STA.w GRP0		; 4 (41)
	
	STA RESP0		; 3 (44) -> 6 cycles after last RESP0
      	; end code
      
        INX        		; 2 (46)
	DEY			; 2 (48)
	
	SLEEP 73-48		; to wsync (73)
	
	BNE ScanlineLoop	; 3 (76)
Any idea ?

 

And last point (until now), I did some tests and when I poke RESP0 at a given time that the medium copy should appear "before" (I mean after the right boundary of the screen), my results were a little different.

Ex :

STA RESP0 ending at : 68@CPU => Medium copy appeared at pixel 15 and not pixel 13 as Andrew's table

STA RESP0 ending at : 71@CPU => Medium copy appeared at pixel 24 and not pixel 22 as Andrew's table

 

Are they some errors in Andrew's table ? Stella's accuracy ? my code ? :)

Link to comment
Share on other sites

I believe the problem is where (when) you're clearing the sprite.

 

If you want to display many copies of player0 equally-spaced across the screen, you can use just the main copy and the close copy (i.e., disable the medium and far copies).

 

Then you can do

 

   STA RESP0
   sleep 3
   STA RESP0
   sleep 3
   STA RESP0
   sleep 3
   STA RESP0
; etc.

as many times as will fit on the line, and you'll get a series of evenly-spaced sprites across the screen-- except the very last sprite will be "out of alignment." The solution of clearing the sprite works, but you need to do it *after* the last RESP0, because you want to clear the close copy but not the main copy.

 

For the next part of this discussion, I'm going to assume that only two copies are being displayed-- the main copy and the close copy (i.e., NUSIZ0 = 1).

 

First, I must admit that I never read through Andrew Davie's tutorials, so I'm not familiar with the way he describes the multi-RESxx trick. But when I was reading Andrew Towers' "Atari 2600 TIA Hardware Notes," part of the problem I had understanding the spacing peculiariities of the multi-RESxx trick was the terminology used.

 

In particular, when you do "STA RESP0 : sleep 3 : STA RESP0," Mr. Towers refers to the first visible sprite as the *close* copy-- but it isn't aligned as expected, because the second RESP0 shifts it over to the right a bit. That may or may not be true from a technical viewpoint-- personally, I think it's a question of semantics. It's true that the first visible sprite is being triggered by the start signal for the *close* copy from the first RESP0, but I prefer to think of it as the *main* copy, as follows:

 

 

   LDA #1
   STA NUSIZ0
   STA RESP0
   sleep 3
   STA RESP0
;
; The result, as I understand the explanation by Andrew Towers:
;
; close copy from the first RESP0, but shifted to the right from where expected relative to the first RESP0
; close copy from the second RESP0, exactly where expected relative to the second RESP0
;
; Now the result as *I* think of it:
;
; main copy from the second RESP0, triggered by the start signal for the close copy from the first RESP0, exactly where expected relative to the second RESP0
; close copy from the second RESP0, exactly where expected relative to the second RESP0

 

Does it matter whether you call that first visible copy the close copy from RESP0 number 1 or the main copy from RESP0 number 2? After all, it's triggered by the start signal for the close copy, right? Well, for me it's simpler to think of it as the main copy, because for me that makes it easier to understand the spacing. If we call it the close copy then we have to say it's "out of alignment" from where expected; but if we call it the main copy then we can say it's exactly where expected.

 

So as long as you strobe RESP0 only twice (with a SLEEP 3 or other 3-cycle instruction between them) you can get two or three copies spaced "normally" at the 16-pixel close spacing. But if you continue strobing RESP0, you get more copies on the line but they start getting out of "normal" alignment. That's because 1 machine cycle = 3 color clocks, so there's no way to strobe RESP0 at just the right color clock to make the copies line up 16 pixels apart, since 16 isn't a multiple of 3. Instead you get them 18 pixels apart, because 18 *is* a multiple of 3. But as soon as you *stop* strobing RESP0 the last copies display with the normal 16-pixel spacing.

 

So if you're using NUSIZ0 = 1 (two copies-- main and close), and you want to draw many copies of player0 across the screen but don't want the last one to be "out of alignment" from the others, you must clear GRP0 *after* the last RESP0. This allows the last main copy to be drawn, but right after that last main copy is drawn the graphics will be cleared, hence the close copy will *not* be drawn:

 

 

   LDA #1
   STA NUSIZ0
   STA RESP0
   sleep 3
   STA RESP0
   sleep 3
   STA RESP0
   sleep 3
   STA RESP0
   sleep 3
   STA RESP0
   sleep 3
   STA RESP0
   sleep 3
   STA RESP0
   sleep 3
   STA RESP0
   LDA #0
   STA GRP0
  • Like 1
Link to comment
Share on other sites

Damn... explained like this.... that's.... logical..... just obvious

That's funny of how a SO techical document (Mr. Towers') require so sort of interpretation to be understood as it should...


Thanks SeaGTGruff (yes again :D)


So let's summarize what I understood from the multi-sprite trick, hope I'm on track now


Legend :

- "interval" : means space between starts of 2 sprites

- "sprites copies" are defined in this order : main copy then close/medium/far copies


Normal Case :

Always remember that if RESPx is strobed only one it will ONLY trigger the sprite "main" copy drawing 160 color clocks later, with a delay of 4+1 CPU cycles after the end of the STA instruction, at the position (((end STA@CPU)*3)+5)-68


Multi Sprite Trick (NUSIZ multi copy mode only) :

  1. After a first RESPx strobing, all consecutive RESP0 (resp. RESP1) strobes will trigger the TIA start signal and accordingly the drawing of main copy 5 pixels (due to 5 TIA cycles delay) after the end of the consecutive strobing (and so cancel the initial strobe)
  2. 3 CPU cycles are needed between 2 RESPx strobes (can be more but not less)
  3. In this case (3 cycles) all main copies will be spaced of 18 pixels (6 CPU cyles=> 18 pixels between beginning of copy n and beginning of copy n+1)
  4. After the last RESPx strobe (in the given scanline), the sprite copies (1 or 2, close/medium/far according to NUSIZx) will be displayed spaced by the close/medium/far interval (16/32/64 pixels)
  5. To have a constant spacing interval it is necessary to hide the non-main copies drawing by clearing GRPx 3 CPU cycles after the last RESPx strobe (or hide it in an other way such on top playfield)
  6. Consecutive RESPx strobes spacing resolution is 3 pixels (strobing RESPx 1 CPU cycle sooner/later will move the sprites of 3 TIA cycles = 3 pixels)
  7. As sprites size is 8 pixel max, consecutive sprite0 and sprite1 will be spaced of 2 pixels whenever it is strobed
  8. Strobing RESPx after the 68th CPU cycle will draw the main copy across the right and left sides of the screen, then on the left part, possibly well spaced

Is there any interesting property I forgot ?

Link to comment
Share on other sites

 

Multi Sprite Trick (NUSIZ multi copy mode only) :
  1. After a first RESPx strobing, all consecutive RESP0 (resp. RESP1) strobes will trigger the TIA start signal and accordingly the drawing of main copy 5 pixels (due to 5 TIA cycles delay) after the end of the consecutive strobing (and so cancel the initial strobe)
  2. 3 CPU cycles are needed between 2 RESPx strobes (can be more but not less)
  3. In this case (3 cycles) all main copies will be spaced of 18 pixels (6 CPU cyles=> 18 pixels between beginning of copy n and beginning of copy n+1)
  4. After the last RESPx strobe (in the given scanline), the sprite copies (1 or 2, close/medium/far according to NUSIZx) will be displayed spaced by the close/medium/far interval (16/32/64 pixels)
  5. To have a constant spacing interval it is necessary to hide the non-main copies drawing by clearing GRPx 3 CPU cycles after the last RESPx strobe (or hide it in an other way such on top playfield)
  6. Consecutive RESPx strobes spacing resolution is 3 pixels (strobing RESPx 1 CPU cycle sooner/later will move the sprites of 3 TIA cycles = 3 pixels)
  7. As sprites size is 8 pixel max, consecutive sprite0 and sprite1 will be spaced of 2 pixels whenever it is strobed
  8. Strobing RESPx after the 68th CPU cycle will draw the main copy across the right and left sides of the screen, then on the left part, possibly well spaced
Is there any interesting property I forgot ?

 

 

I'm a little lost on what you're saying in number 7. I assume you mean that consecutive RESP0-RESP1-RESP0-RESP1 strobes will result in consecutive P0-P1-P0-P1 sprites separate by 1 blank pixel, but you say "2 pixels."

 

As far as number 8, if you strobe RESP0 or RESP1 near the end of the line, such that the start signal for the close/near copy will occur on the left side of the screen, you can strobe them again on the left side of the screen and get the main copy if the strobe is timed to end sometime during that start signal.

 

And if you strobe RESPx at any time during HBLANK, it's the same as strobing it at cycle 22.

 

Also, I believe that if a start signal begins on or before pixel 159 (color clock 227) but doesn't end before HBLANK, it will stay on throughout HBLANK and get turned off sometime after HBLANK.

 

So if you exploit these facts and time things just right, you should be able to get copies at the left side of the screen earlier than you could by simply strobing RESPx twice after HBLANK.

 

Furthermore, if you want your sprites to be at the "correct" spacing of 16 pixels, but you want more than 6 sprites on a line (3 of P0 and 3 of P1), you can strobe RESP0 twice, then wait a bit, strobe RESP1 twice, wait a bit more, then strobe RESP0 again twice, as so:

 

 

   LDA #%00000011
   STA NUSIZ0
   STA NUSIZ1
 
; then in your loop
 
   STA RESP0
   sleep 3
   STA RESP0 ; this gives you 3 copies of P0, 16 pixels apart
 
   sleep 7
 
   STA RESP1
   sleep 3
   STA RESP1 ; this gives you 3 copies of P1, 16 pixels apart, beginning 16 pixels after the last P0
 
   sleep 7
 
   STA RESP0
   sleep 3
   STA RESP0 ; this gives you 3 more copies of P0, 16 pixels apart, beginning 16 pixels after the last P1

 

So that gives you P0 P0 P0 P1 P1 P1 P0 P0 P0, all spaced 16 pixels apart.

 

The reason this gives you the "correct" spacing is because the pair of RESP1 strobes are exactly 16 cycles after the first pair of RESP0 strobes, and likewise for the second pair of RESP0 strobes. Note that 16 cycles = 48 pixels.

 

Unfortunately, this doesn't work with just one sprite (e.g., changing the two RESP1s to RESP0s), because when you strobe RESP0 again it stops the far copy from being displayed, so you end up with this instead: P0 P0 __ P0 P0 __ P0 P0 P0.

 

Anyway, you can use all of these facts/tricks together creatively to get some results that would be impossible otherwise, such as repositioning a sprite (on one of the 3-pixel boundaries) from one line to the next without having to put a blank line between them-- i.e.:

___P0

__________P0 ; no blank line between the first P0 and the second one

 

Or you can draw 3 copies of P0 (or P1) on the left side of the screen, and 3 more on the right side:

P0 P0 P0 _________ P0 P0 P0

 

That could be useful if you were making an adventure RPG and wanted to draw, for example, 3 guards on the left side of a castle entrance and 3 more guards on the right, or something like that.

 

As far as moving the sprites around smoothly, if you draw the sprites with 6 pixels instead of 8, you can shift the pixels as needed so it looks like the sprites begin at any color clock, not just on one of the 3-color-clock boundaries:

 

XXXXXX..
.XXXXXX.
..XXXXXX
___XXXXXX..
___.XXXXXX.
___..XXXXXX
etc.

That's how Galaxian and other games that use the multi-RESPx trick get the smooth horizontal movements.

Link to comment
Share on other sites

Argh, silly Stella which display Sprite "pixels" using 2 "PC pixels".... yes you're right the spacing is only of 1 pixel.... That saves my mind, I did not understand why 3 CPU cycles can become 10 pixels... :) Thanks, I must make less confidence in my eyes :P

 

Thanks for the other tips :

- yes, I did not try to keep the 16 pixels spacing using only 3 close copies... good point

- regarding placing sprites on "borders" I'm not yet good at.... I need to practice more :) And you can see in my example, I'm hiding them....

- concerning smooth scroller... I used in my last example 4 pixels sprites that I shifted 2 times yes, I could have used 6 pixels, right

 

I tried to scroll 8 pixels sprites using shiting across sprites 0 and 1 but due to the 1 pixel spacing, I cannot make it work. I have to try with the 16 spacing pixels routine you gave me.

 

So fixed text :

 

 

Legend :
- "interval" : means space between starts of 2 sprites
- "sprites copies" are defined in this order : main copy then close/medium/far copies
Normal Case :
Always remember that if RESPx is strobed only one it will ONLY trigger the sprite "main" copy drawing 160 color clocks later, with a delay of 4+1 CPU cycles after the end of the STA instruction, at the position (((end STA@CPU)*3)+5)-68
Multi Sprite Trick (NUSIZ multi copy mode only) :
  1. After a first RESPx strobing, all consecutive RESP0 (resp. RESP1) strobes will trigger the TIA start signal and accordingly the drawing of main copy 5 pixels (due to 5 TIA cycles delay) after the end of the consecutive strobing (and so cancel the initial strobe)
  2. 3 CPU cycles are needed between 2 RESPx strobes (can be more but not less)
  3. In this case (3 cycles) all main copies will be spaced of 18 pixels (6 CPU cyles=> 18 pixels between beginning of copy n and beginning of copy n+1)
  4. After the last RESPx strobe (in the given scanline), the sprite copies (1 or 2, close/medium/far according to NUSIZx) will be displayed spaced by the close/medium/far interval (16/32/64 pixels)
  5. To have a constant spacing interval it is necessary to hide the non-main copies drawing by clearing GRPx 3 CPU cycles after the last RESPx strobe (or hide it in an other way such on top playfield)
  6. Consecutive RESPx strobes spacing resolution is 3 pixels (strobing RESPx 1 CPU cycle sooner/later will move the sprites of 3 TIA cycles = 3 pixels)
  7. As sprites size is 8 pixel max, consecutive sprite0 and sprite1 will be spaced by 1 pixel whenever it is strobed
  8. Strobing RESPx after the 68th CPU cycle will draw the main copy across the right and left sides of the screen, then on the left part, possibly well spaced
  9. Strobing RESP0 or RESP1 near the end of the line, such that the start signal for the close/near copy will occur on the left side of the screen, you can strobe them again on the left side of the screen and get the main copy if the strobe is timed to end sometime during that start signal.
  10. Constant 16 pixels spacing (P0P0P0P1P1P1) can be achieved by using P0 close copies then trigger P1 close copies at the good time : 7 CPU cycles later (STA RESP1 should begin)
  11. Strobing RESPx at any time during HBLANK, it's the same as strobing it at cycle 22.
  12. Strobing RESPx on or before pixel 159 (color clock 227) but doesn't end before HBLANK, it will stay on throughout HBLANK and get turned off sometime after HBLANK.

 

 

 

Edited by shazz
Link to comment
Share on other sites

  • 7 years later...
On 8/22/2013 at 7:40 AM, SeaGtGruff said:

Now, even though strobing RESxx doesn't trigger a "start" signal, it just so happens that if you strobe RESxx at just the right time-- such that the RESxx instruction ends while a "start" signal is active-- that "start" signal will cause copy 0 (main copy) to be drawn. It can be argued that this is actually copy 1 (or 2 or 3) being drawn (depending on which "start" signal was active when RESxx ended), but for all intents and purposes it's copy 0 that's drawn, since the other copies will follow as expected.

I've spent last evening trying to understand the RESPx multi-sprite trick, reading both Chris Tumbler's "The Multi-Sprite Trick" and Andrew Towers' "TIA Hardware Notes - The Re-trigger Trick, and all that jazz", but felt that the information there was not 100% correct, or at least not on par with what I was seeing in the Stella debugger. 

Also, I was a bit confused by Andrew's statement, saying "If you hit RESPn at least twice on every scanline, you will never see the 'main' copy of that player, ever, on any scanline", which I could not match with the sprite-copies that got displayed.

 

Maybe it's a matter of semantics and terminology, but for me, the detailed information on the multi-sprite trick by @SeaGtGruff, made it all "click" for me. So a big thanks to @SeaGtGruff, 8 years after that information was written down ?

 

 

Edited by Dionoid
  • Like 2
Link to comment
Share on other sites

The RESPx trick is quite cool. Yes, you can draw many sprites and at first it can seem confusing how it all works. Scrolling is possible too and then it gets amazing. Here is the first full screen scroll done. What is cool is that there is absolutely no flicker. Note you can use Up/Down in this rom for speed of the scroll.

 

https://atariage.com/forums/topic/207391-circus-atariage-2600/?do=findComment&comment=2677582

 

FullBalloonTest.thumb.png.970f97cffb081f778d6e9b5304897f80.png

 

FullBalloonTest.bin

 

 

I've used the RESPx trick many times over the years such as for the Warlords menu screen:

 

https://atariage.com/forums/topic/300168-original-games-updated-with-menus/?do=findComment&comment=4536885

 

WarlordsMenu.thumb.png.b556431abf1385c357867971b681dabb.png

 

While it is obvious that the rows of bricks are drawn with the trick, it might not be that the knights are too. This is because there are more than 3 sprites, and towards the bottom of them the bricks are drawn too so right away there is a limit on using GRP0 and GRP1. Anyhow repeated bashing of RESPx allows kernels like this to be created, along with some other creative touches.

 

 

  • Like 2
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...