Jump to content
IGNORED

Two player single height color-changing sprites demo and questions


boutell

Recommended Posts

I've attached a simple demo which displays two single-height sprites simultaneously. They overlap for part of their vertical extent, and they change color on every scanline. The bitmap and the colors are both loaded from tables, so you could substitute any sprite and one-color-per-scanline colormap. Maybe this will be helpful to someone else.

 

Here are my questions about the results the demo is producing:

 

Why don't the playfield bars at left and right appear normally? They vanish after their first scanline.

 

Is there a way to keep the lower of the two sprites from shifting colors around as it moves between the rightmost edge and about 20% of the way into the screen? There is no VDEL mechanism for player colors. I'm trying to simulate it with a shadow register but I don't have enough cycles after WSYNC to do it there, so I do it shortly before.

 

Any suggestions on winning back some cycles here? In the vertically overlapping case, I'm using every single scanline cycle right now.

 

Thanks!

 

P.S. Thanks to all who responded to my previous question, the impact of that advice should be obvious from the fact that I have two full-vertical-resolution sprites in this demo. (;

demo1.zip

Edited by boutell
Link to comment
Share on other sites

Why don't the playfield bars at left and right appear normally? They vanish after their first scanline.

You're setting PF0 to 0 right here:

 

ActorBlankP0
  lda #0  
  sta PF0
  jmp ActorP1  ; 2 + 3 + 3

I assume that you meant to leave PF0 set as it was all the way down the screen. So if you take out that "sta PF0," there will be a 1-playfield-pixel-wide left and right border all the way down.

 

Is there a way to keep the lower of the two sprites from shifting colors around as it moves between the rightmost edge and about 20% of the way into the screen? There is no VDEL mechanism for player colors. I'm trying to simulate it with a shadow register but I don't have enough cycles after WSYNC to do it there, so I do it shortly before.

Generally speaking, you should try to do things during some window of time when they won't cause an undesired change mid-line. Usually that means changing something *before* you reach a specific horizontal location, but it can also mean changing something *after* reaching a specific horizontal location. For instance, if you're drawing a non-reflected asymmetrical playfield, then you can set the graphics for the *right* copy of PF0 anytime after the left copy of PF0 has been drawn, but before the right copy needs to be drawn; and likewise, you can set the graphics for the *left* copy of PF0 anytime after the right copy has been drawn, but before the left copy needs to be drawn, as follows:

 

|<-- color clock 0, screen pixel -68
|
|		|<-- color clock 68, screen pixel 0
|		|
|		|		color clock 228, screen pixel 160 -->|
|		|											 |
|h. blank|PF0 |  PF1   |  PF2   |PF0 |  PF1   |  PF2   |
|		|	|		|		|	|		|		|
|		|XXXX|--------|--------|XXXX|--------|--------|
|set left|XXXX|	set right	|XXXX|	set left	 |
|copy PF0|XXXX|	copy PF0	 |XXXX|	copy PF0	 |
|		|XXXX|--------|--------|XXXX|--------|--------|

Anyway, the player graphics and player colors almost always need to be set during the horizontal blanking, otherwise the graphics or color change can occur at undesired times, as is happening here. Since you're drawing (or had wanted to draw) a 1-playfield-pixel-wide border on the left and right edges of the screen, you can make the graphics or color changes anytime between color clock 224 and color clock 71, inclusive-- or machine cycles 75 through 23. Of course, that is assuming that you never draw either player such that it overlaps the left or right playfield border.

 

Any suggestions on winning back some cycles here? In the vertically overlapping case, I'm using every single scanline cycle right now.

I'm going through your code, making some changes, and I'll post the modified code later.

 

Michael

Link to comment
Share on other sites

Okay, here is my modified version of your code. It was tougher than I thought it would be, because I kept making stupid cycle-counting errors. :)

 

I rearranged some things (e.g., I put the overscan routine in front of the vertical sync routine), and rewrote some things. The biggest changes for what you're interested in were to decrement the scan line counter instead of incrementing it, getting rid of the subtractions, adding indexes/indices for the player sprites, decrementing the indexes as the players are drawn, getting rid of WSYNC in the draw routine, making sure the draw routine always takes exactly 76 cycles no matter which branches are taken (which means adding some sleep or NOP commands in various places), etc. To get the timing just right, I started by saying that I wanted the STA COLUP1 to end at cycle 75 (because I'm making sure that the players don't go into the playfield border, so changing COLUP1 at cycle 75 won't show up until the next scan line), then counted cycles forward up to the end of the draw loop to see which cycle the loop ends on, then added a sleep in front of the loop to make sure it starts at the desired cycle, then counted forward and added a sleep 3 near the end to get things to come out just right. I tried a number of approaches until I ended up with the one posted here. I'm not saying that this is the cleanest or tightest or best code/approach, but it works! :)

 

Let me know if you have any questions about any of the changes I made. I think the only comments I put in had to do with setting the interval timer at the beginning of the overscan, because that was something that gave me problems when I first tried to use it, so I included some notes about how you calculate what value to set the interval timer to in order to get a certain number of scan lines.

 

Michael

 

Edit -- Oops, I forgot to remove the directory path from the INCLUDE statements before posting my code, and I doubt that your paths will be the same as mine are, so be sure to change those INCLUDE statements as needed before you compile.

 

Edit #2 -- I forgot to mention that since the scan line counter is being decremented, I adjusted the player Y positions accordingly. I also tinkered with the player heights and data a little bit. Since the player sprites are symmetrical in both the horizontal and vertical directions, you can't really tell it, but the player graphics and color data need to be stored upside-down (i.e., index 0 is the bottommost line, and index 14 is the topmost line). And since the scan lines are counted backwards (or decremented), the Y coordinates are as on an X-Y graph-- i.e., Y=0 is at the bottom of the screen, and Y=192 is at the top of the screen. Finally, since the X scan line counter is being set for each zone (zone 1 = top border, zone 2 = area where the players are, and zone 3 = bottom border), and the loops for each zone end when the X register decrements to 0, the actual Y coordinates for the middle zone are Y=176 at the top of the middle zone, and Y=1 at the bottom. Also, you might notice that I'm not actually setting PF0, PF1, and PF2 for the top border. This isn't an oversight, it was deliberate, because they contain the same values as they do for the bottom border, so I didn't clear them after the bottom border was drawn, hence the top border is drawn as desired.

 

Edit #3 -- One more thing: Since the cpx comparisons are done on the preceding scan lines from where the players actually start to appear, PlayerY=176 would not appear until the next line (175), etc. The code is assuming that the players will never need to appear on either the first or last lines of the middle zone. Also, note that the ldy PlayerIndex and bmi commands assume that PlayerIndex will always be <= 127 while a player is being drawn, and that once PlayerIndex decrements from 0 to 255 (or -1), the player is all done. So this will allow for players up to (only) 127 scan lines tall.

demo1a.zip

Edited by SeaGtGruff
Link to comment
Share on other sites

Okay, here is my modified version of your code. It was tougher than I thought it would be, because I kept making stupid cycle-counting errors. :)

 

Wow! Thank you so much.

 

Looks like you nailed it with... three cycles to spare, in the worst case!

 

I think I can actually use this, too. I understand your logic, it's not too bizarre. (; By switching to player counters you avoided some extra math that's in my version and won back the cycles to squeeze in COLUP0 and COLUP1 at exactly the right moments without an explicit STA WSYNC.

 

Since posting this I've done a "multiple sprites as long as they aren't on the same scanline" demo, though it's not as tight as it could be. I thought that was cool until I looked at Activision Freeway and realized they managed to put three completely independent player graphics on a scanline with no flicker whatsoever. Ahrgh! I'm pretty sure they are only able to do it because the two "bird" sprites have no freedom of motion on the X axis - they must be retriggering P0 (or P1) at a fixed point in the scanline kernel after loading a new graphic to account for differences in vertical positioning. Wow.

Link to comment
Share on other sites

Okay, here is my modified version of your code. It was tougher than I thought it would be, because I kept making stupid cycle-counting errors. :)

 

Wow! Thank you so much.

 

Looks like you nailed it with... three cycles to spare, in the worst case!

 

I think I can actually use this, too. I understand your logic, it's not too bizarre. (; By switching to player counters you avoided some extra math that's in my version and won back the cycles to squeeze in COLUP0 and COLUP1 at exactly the right moments without an explicit STA WSYNC.

If you end the sta COLUP1 at cycle 76 (or 0) instead of cycle 75, you can have the players go all the way to the edges of the screen. I didn't do that, because then the players would have overlapped the left and right borders, which would look funny (i.e., why have borders if the players can move into those borders?).

 

Since posting this I've done a "multiple sprites as long as they aren't on the same scanline" demo, though it's not as tight as it could be. I thought that was cool until I looked at Activision Freeway and realized they managed to put three completely independent player graphics on a scanline with no flicker whatsoever. Ahrgh! I'm pretty sure they are only able to do it because the two "bird" sprites have no freedom of motion on the X axis - they must be retriggering P0 (or P1) at a fixed point in the scanline kernel after loading a new graphic to account for differences in vertical positioning. Wow.

I haven't disassembled Freeway, but it looks like they just used two copies of player1, spaced at the far distance (i.e., 64 color clocks apart), so there's no need for them to trigger RESP1 while drawing the screen, other than to set player1's initial position.

 

Michael

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