boutell Posted January 23, 2007 Share Posted January 23, 2007 Is it practical to have two nonflickering, freely moving, single-height player sprites without using VDEL? My vertical positioning code takes 20-ish cycles to handle just one sprite, and that's about all the horizontal blank time there is to play with. But I get the impression there are games out there that have this problem licked, as long as I don't make other demands as well (playfield changes, etc). Any code out there that demonstrates how to nail this? I need to be able to move the sprites arbitrarily, so a trick kernel that works only when the players are on the same horizontal line (for instance) won't do the job for me. Does the Batari BASIC kernel do this somehow (I'm coding in assembly)? Or does it use VDEL and double-height sprites? Thanks for any information! (2600 development looks quiet since 2007 began...) Quote Link to comment Share on other sites More sharing options...
vdub_bobby Posted January 23, 2007 Share Posted January 23, 2007 Why don't you want to use VDEL? But for non-VDELxx two-sprite code, try this: Loop ; 23 SLEEP 35 ;+35 58 lda #PLAYER1HEIGHT dcp Player1Counter bcs DoDraw1 lda #0 .byte $2C DoDraw1 lda (Player1Ptr),Y sta GRP1 ;+18 76 lda #PLAYER0HEIGHT dcp Player0Counter bcs DoDraw0 lda #0 .byte $2C DoDraw0 lda (Player0Ptr),Y sta GRP0 ;+18 18 dey bpl Loop ;+5 23 Other things to consider: are your sprites positioned across the entire X-axis? If they are never at the very edge of the screen then you can get away with writing to GRPx close to, but not inside, the horizontal blank. Quote Link to comment Share on other sites More sharing options...
Cybergoth Posted January 23, 2007 Share Posted January 23, 2007 But for non-VDELxx two-sprite code, try this: Shouldn't it at least have WSYNC somewhere? Well, in theory the desired effect is pretty simple to achieve: ; Loop overhead ; Do whatever RhabarberDraw Technique you want to get shape 1 into X ; Do whatever RhabarberDraw Technique you want to get shape 2 into A STA WSYNC STX GRP0 STA GRP1 ; Loop underhead Voilà, both sprites set in only 6 cycles of HBLANK I always work like that or similar, I believe outside some sixchar techniques almost non of my code uses VDEL. Quote Link to comment Share on other sites More sharing options...
vdub_bobby Posted January 23, 2007 Share Posted January 23, 2007 But for non-VDELxx two-sprite code, try this: Shouldn't it at least have WSYNC somewhere? Well, I assume you enter the loop at the indicated cycle. Otherwise... Well, in theory the desired effect is pretty simple to achieve: ; Loop overhead ; Do whatever RhabarberDraw Technique you want to get shape 1 into X ; Do whatever RhabarberDraw Technique you want to get shape 2 into A STA WSYNC STX GRP0 STA GRP1 ; Loop underhead Voilà, both sprites set in only 6 cycles of HBLANK I forgot about that - I always tend to be using X as another counter and/or don't have the extra cycles to spare for that - good suggestion. Quote Link to comment Share on other sites More sharing options...
+batari Posted January 23, 2007 Share Posted January 23, 2007 Is it practical to have two nonflickering, freely moving, single-height player sprites without using VDEL? My vertical positioning code takes 20-ish cycles to handle just one sprite, and that's about all the horizontal blank time there is to play with. But I get the impression there are games out there that have this problem licked, as long as I don't make other demands as well (playfield changes, etc). Any code out there that demonstrates how to nail this? I need to be able to move the sprites arbitrarily, so a trick kernel that works only when the players are on the same horizontal line (for instance) won't do the job for me. Does the Batari BASIC kernel do this somehow (I'm coding in assembly)? Or does it use VDEL and double-height sprites? Thanks for any information! (2600 development looks quiet since 2007 began...) All bB kernels use VDEL and double-height sprites The VDEL is done not because of the 2-line kernel but because writes for one player and the ball would otherwise occur during the visible screen, which IMO is the most useful aspect of VDEL. Quote Link to comment Share on other sites More sharing options...
Cybergoth Posted January 24, 2007 Share Posted January 24, 2007 I forgot about that - I always tend to be using X as another counter and/or don't have the extra cycles to spare for that That's where the real fun begins - and what LAX(),Y was invented for Anyway, main thing to realize and what I was trying to illustrate with my dummy code, is that _before_ the STA WSYNC you have (almost) all the time in the world to prepare stuff - and that your loop doesn't have to start with it. Here Look at this: ; Loop overhead ; Prepare stack pointer ; Do whatever RhabarberDraw Technique you want to get shape 1 into X ; Do whatever RhabarberDraw Technique you want to get shape 2 into A CPY Particle1 STA WSYNC PHP STX GRP0 STA GRP1 CPY Particle2 PHP CPY Particle3 PHP ; Loop underhead Both sprites, both missiles and the ball done during HBLANK 1 Quote Link to comment Share on other sites More sharing options...
boutell Posted January 27, 2007 Author Share Posted January 27, 2007 (edited) But for non-VDELxx two-sprite code, try this: Shouldn't it at least have WSYNC somewhere? Well, in theory the desired effect is pretty simple to achieve: ; Loop overhead ; Do whatever RhabarberDraw Technique you want to get shape 1 into X ; Do whatever RhabarberDraw Technique you want to get shape 2 into A STA WSYNC STX GRP0 STA GRP1 ; Loop underhead Voilà, both sprites set in only 6 cycles of HBLANK I always work like that or similar, I believe outside some sixchar techniques almost non of my code uses VDEL. Interesting - but what is the RhabarberDraw technique? Thanks! Edit: oh. Rhabarber = rhubarb = joke. Gotcha. Edited January 27, 2007 by boutell Quote Link to comment Share on other sites More sharing options...
boutell Posted January 27, 2007 Author Share Posted January 27, 2007 Is it practical to have two nonflickering, freely moving, single-height player sprites without using VDEL? My vertical positioning code takes 20-ish cycles to handle just one sprite, and that's about all the horizontal blank time there is to play with. But I get the impression there are games out there that have this problem licked, as long as I don't make other demands as well (playfield changes, etc). Any code out there that demonstrates how to nail this? I need to be able to move the sprites arbitrarily, so a trick kernel that works only when the players are on the same horizontal line (for instance) won't do the job for me. Does the Batari BASIC kernel do this somehow (I'm coding in assembly)? Or does it use VDEL and double-height sprites? Thanks for any information! (2600 development looks quiet since 2007 began...) All bB kernels use VDEL and double-height sprites The VDEL is done not because of the 2-line kernel but because writes for one player and the ball would otherwise occur during the visible screen, which IMO is the most useful aspect of VDEL. Thanks for answering that one. My planned game doesn't need a ball, and it looks like I can avoid VDEL in that situation and have full-res sprites. Yay! Quote Link to comment Share on other sites More sharing options...
boutell Posted January 27, 2007 Author Share Posted January 27, 2007 Why don't you want to use VDEL? With VDEL, I can only have double-height sprites. And late-era 2600 games in the same genre - Super Football, to be specific - manage not only single-height sprites, but single-height sprites that change color on every scanline! So I'm trying real hard here not to write a game that looks like Gunslinger. Super Football manages a LOT of impressive stuff. Quote Link to comment Share on other sites More sharing options...
supercat Posted January 27, 2007 Share Posted January 27, 2007 With VDEL, I can only have double-height sprites. Despite the name, VDEL does not limit you to double-height sprites. Many games with single-height sprites use VDEL a lot. Quote Link to comment Share on other sites More sharing options...
boutell Posted January 27, 2007 Author Share Posted January 27, 2007 But for non-VDELxx two-sprite code, try this: Shouldn't it at least have WSYNC somewhere? Well, in theory the desired effect is pretty simple to achieve: ; Loop overhead ; Do whatever RhabarberDraw Technique you want to get shape 1 into X ; Do whatever RhabarberDraw Technique you want to get shape 2 into A STA WSYNC STX GRP0 STA GRP1 ; Loop underhead Voilà, both sprites set in only 6 cycles of HBLANK I always work like that or similar, I believe outside some sixchar techniques almost non of my code uses VDEL. This tactic actually works very well for me. A variation on it is doing the job nicely. Is it also practical to change the player colors on each scanline? Or is that unrealistic given the time constraints we're under? I've tried alternating bitmap bytes with color bytes, placing the color bytes in a second table after the bitmap table, etc., but any way I slice it I wind up taking too long and consuming a second scanline. I've been looking at Super Football and thinking "I should be able to match that!" but apparently that game uses the 6-digit score technique which is an entirely different kettle of fish and probably won't suit my plans. Quote Link to comment Share on other sites More sharing options...
boutell Posted January 27, 2007 Author Share Posted January 27, 2007 But for non-VDELxx two-sprite code, try this: Loop ; 23 SLEEP 35 ;+35 58 lda #PLAYER1HEIGHT dcp Player1Counter bcs DoDraw1 lda #0 .byte $2C DoDraw1 lda (Player1Ptr),Y sta GRP1 ;+18 76 lda #PLAYER0HEIGHT dcp Player0Counter bcs DoDraw0 lda #0 .byte $2C DoDraw0 lda (Player0Ptr),Y sta GRP0 ;+18 18 dey bpl Loop ;+5 23 Other things to consider: are your sprites positioned across the entire X-axis? If they are never at the very edge of the screen then you can get away with writing to GRPx close to, but not inside, the horizontal blank. This is impressive but I sure don't understand it yet. (: How should the player counters be initialized? To the starting scanline of the player in question? And in the spirit of actually understanding rather than blindly using stuff: You load the accumulator, you use dcp which decrements a memory location without borrow (no impact on A that I can see), you branch if carry is set, if not you load zero into the accumulator. Then waht did the first load of the accumulator accomplish? And what does .byte $2C (BIT ABS?) do? I can't find an intelligible explanation of that one. Thanks! Quote Link to comment Share on other sites More sharing options...
boutell Posted January 27, 2007 Author Share Posted January 27, 2007 With VDEL, I can only have double-height sprites. Despite the name, VDEL does not limit you to double-height sprites. Many games with single-height sprites use VDEL a lot. ... Because you can write to PF0 at a "bad" time and get that magically copied to the real PF0 when you write to PF1, which you cleverly do at a "good" time. ... Right? My early results there are encouraging though my code is definitely still sloppy. Thanks for the hint! Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted January 27, 2007 Share Posted January 27, 2007 With VDEL, I can only have double-height sprites. Despite the name, VDEL does not limit you to double-height sprites. Many games with single-height sprites use VDEL a lot. ... Because you can write to PF0 at a "bad" time and get that magically copied to the real PF0 when you write to PF1, which you cleverly do at a "good" time. ... Right? My early results there are encouraging though my code is definitely still sloppy. Thanks for the hint! That's right. "VDEL" is usually said to mean "Vertical DELay," but I like "Video DELay" better, since that's a more accurate description of what it does. Likewise with another "V" register-- "VBLANK," or "Vertical BLANKing," but it's really "Video BLANKing," since it can be used anywhere, even in the middle of drawing an active scan line. Michael Quote Link to comment Share on other sites More sharing options...
vdub_bobby Posted January 30, 2007 Share Posted January 30, 2007 (edited) lda #PLAYER1HEIGHT dcp Player1Counter bcs DoDraw1 lda #0 .byte $2C DoDraw1 lda (Player1Ptr),Y sta GRP1 ;+18 76 This is impressive but I sure don't understand it yet. (: How should the player counters be initialized? To the starting scanline of the player in question? And in the spirit of actually understanding rather than blindly using stuff: You load the accumulator, you use dcp which decrements a memory location without borrow (no impact on A that I can see), you branch if carry is set, if not you load zero into the accumulator. Then waht did the first load of the accumulator accomplish? And what does .byte $2C (BIT ABS?) do? I can't find an intelligible explanation of that one. DCP decrements the memory location *and* then compares the result with A, setting flags appropriately. If you don't want to use illegal (or bonus, or...) operations, then the same effect can be achieved this way: tya sec sbc Player1Counter adc #PLAYER1HEIGHT bcs DoDraw1 lda #0 .byte $2C DoDraw1 lda (Player1Ptr),Y sta GRP1 ;+20 I can never set Player1Counter correctly on my first try, but it should be set to (I think) the height of your display minus the starting scanline of the player in question plus the height of the player. The idea is that you are decrementing that value every scanline and when it is equal to the height of the player (#PLAYER1HEIGHT) it will start drawing. The .byte $2C trick is just that, a nifty little trick to skip the next two bytes (i.e., skip LDA (),Y). You can also use branching (BEQ, JMP, etc.), but it saves a byte over a conditional branch and the timing works out perfectly, which is important if you don't want to have to hit WSYNC every line. It screws up the flags but doesn't change any registers or RAM. That make sense? Edited January 30, 2007 by vdub_bobby 1 Quote Link to comment Share on other sites More sharing options...
Cybergoth Posted February 3, 2007 Share Posted February 3, 2007 Is it also practical to change the player colors on each scanline? Or is that unrealistic given the time constraints we're under? Depends a bit on where you're objects are allowed to be horizontally. If there's no restriction at all, you're completely limited to what you get done during the couple of HBLANK cycles. Quote Link to comment Share on other sites More sharing options...
supercat Posted February 4, 2007 Share Posted February 4, 2007 (edited) Depends a bit on where you're objects are allowed to be horizontally. If there's no restriction at all, you're completely limited to what you get done during the couple of HBLANK cycles. At some expense in code size, you could use two kernels: the first when the object is nearer the left half of the screen, and the second when the object is nearer the right. Toyshop Trouble has two kernel routines for the conveyor sections based upon whether they are near the left half of the range or the right half, and it switches between the two invisibly. That particular switch was done because of different masking requirements rather than write timing, though write timing played a role as well. The key point is that it demonstrates that it's possible to switch kernels completely invisibly to the player. Incidentally, a couple of other points about Toyshop Trouble: -1- The player is seventeen scan-lines high, and the screen is divided into sixteen-line zones which are displayed with Y counting from 15 to 0. The top and bottom colors of the player are always the same color. Consequently, to color the player I have two copies of the 16-byte color in ROM consecutively, and I can set the player color with "lda (clptr0),y / sta COLUP0" without having to do any decision making. -2- If there weren't so many animation frames for the player, I would store its shape in memory preceded and followed by 15 zeroes (this is what I did in an earlier version). Zones alternate between what I call "a" and "b" zones, and so within a zone I'll use either "lda (shptr0a),y / sta GRP0" or else I'll use shptr0b; the "a" zones have enough spare time to determine whether the player should appear in the next "a" and "b" zones, so I set the pointers as appropriate. The "b" zones have no time for decision making, but can just blindly use the "shptr0b" pointer set up during the "a" zones. -3- After Nathan came up with 28 animation frames, it became clear I couldn't afford to store all of them in ROM preceded and followed by 15 zeroes. So I use 32 bytes of RAM, split into 16 bytes for the "a" zone and 16 bytes for the "b" zone. If a player occupies part of a zone, shptr0a or shptr0b will point to the appropriate RAM buffer; otherwise it will point to 16 bytes of zeroes. Note that storing the player shapes in RAM allows for a little bit of extra logic to assemble player shapes out of 16 bodies and 7 hats. Edited February 4, 2007 by supercat Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.