| |
knue
Registered: Dec 2012 Posts: 37 |
sprite clipping at the top while using AGSP
Hi all,
I'm currently coding a game using an AGSP scroller. Since enemies are supposed to enter the screen from all sides, I have to clip the sprites entering from the top as the first 25+8 raster lines are used for the AGSP stuff. The question is: What is the best way to do this?
I can think of the following:
1) don't clip at all.
The sprite would simply pop up at full height when it enters from the top. This one is a bit ugly but wouldn't be the first game suffering from such problems...
2) set sprite pointers to a zeroed sprite.
While this basically works, the timing in the AGSP stuff gets incredibly complicated. I don't know whether this is even possible (without going insane). I mean I would need an immense amount of logic to time various areas in the AGSP stuff correctly depending on how many sprites are visible in this raster line.
Are there other options on the table or is 2) doable with some fancy lookup table or sth?
You can find the code here if someone is interested:
https://github.com/leissa/c64engine
Thanks in advance for any help. |
|
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
I wouldnt mind popping if otherwise it has good playability. You'll get some ppl explaining how 2) can be made working, but you'll need to pay for it with either memory or cpu time or flexibility or some of those combined I guess. |
| |
chatGPZ
Registered: Dec 2001 Posts: 11386 |
second option seems extremely tricky (doable, sure...) - for a game anyway (you probably dont want to spend a lot of memory just on this)
if i had to do this, i would probably try something with d017 based sprites stretching.... ie *always* have a certain number in all lines of the agsp area (stretched down), which gives you constant timing. then to make a sprite appear under the agsp switch pointer to whatever you want at the bottom of the agsp, and keep stretching for more lines.
another way would be to simply animate the sprite, that should be much simpler to code, but will either limit your number of sprites a lot, or need a bit of CPU to copy the data into an empty sprite |
| |
soci
Registered: Sep 2003 Posts: 480 |
Do 1) first, then finish off the rest of the game. Now if you're still motivated you may try 2). Then you'll still have something releasable after getting bored trying to get it working.
I only did VSP with variable number of sprites (in Grubz) and it was doable by counter adjusting the delay. The required delay may be looked up in a 256 byte table. There was no need for clipping there.
Try to clip by using a screen which points to all empty sprites while in the AGSP area instead of changing sprite pointers. |
| |
knue
Registered: Dec 2012 Posts: 37 |
thanks for the inpur so far. so to be clear, the clipping itself is not so much of a problem. it's just a matter of:
; enter AGSP region
inc CIA2_DATA_PORT_A
; do AGSP...
; leave AGSP region
dec CIA2_DATA_PORT_A
It's just that the timing within the AGSP region is screwed up.
However, I think you guys are right. I should concentrate on getting the game itself done than concentrating on this detail... |
| |
ChristopherJam
Registered: Aug 2004 Posts: 1409 |
As an alternate to doing sprite stretching (two d017 writes every line!), you could just precede each sprite with a blank instance.
If the AGSP region was less than 21 lines high this'd be trivial; just put a blank sprite 21 lines above each edge-crossing sprite, add blank sprites to the AGSP area to bring the total up to the max than can cross (I assume no more than seven, if you also have a sprite player), and change VM to unzero all your data pointers as you leave the region.
It's a little messier because AGSP is taller than that; you need to have all your blank sprites initially double height, and zero d017 when you leave the region. The starting position of the empty sprite then runs from y0-84 to y0-42 as y0 goes from AGSP_end_y-21 to AGSP_end_y; a lsr or table lookup will sort that.
The AGSP timing itself is then constant - you always have seven sprite fetches (or whatever your max_enemies_per_line is). Could even drop that to 5 or six if that's too many cycles, and just have only the bottom-most N entering the screen smoothly, with any extras popping in. |
| |
ChristopherJam
Registered: Aug 2004 Posts: 1409 |
(oh, and if you're deferring this until later, it might be worth positioning half a dozen or so blank sprites in the AGSP area anyway, so at least that way you know you have the DMA time available?
Hysteron Proteron used sprites in the AGSP area for the HUD, or would have if I'd ever finished it..) |
| |
lft
Registered: Jul 2007 Posts: 369 |
Quoting ChristopherJamIt's a little messier because AGSP is taller than that; you need to have all your blank sprites initially double height, and zero d017 when you leave the region.
Or you could use magic sprite stretch (i.e. sprite crunch). But that would involve some timing-critical stuff before the AGSP area, so it would just move the problem.
One thing that I thought was a bit unclear in ChristopherJam's suggestion is this: Suppose you have a y-expanded blank sprite, followed by the actual sprite at, say, line $40. And suppose the visible part of the display begins at $4a. It would be kind of messy to turn off y-expansion at line $40, especially if there are several sprites at different y-positions. So what you should do is to also expand the hidden part of the actual sprite! It will now be located at $36, and the first 10 lines (fetched from a blank sprite) are y-expanded. Then, after the VSP, you turn off y-expansion for every sprite simultaneously. |
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
You might wanna check how we did it in Pinball Dreams. Can't remember right now, but the top paddles must have been properly clipped against the AGSP-area.
@WVL: Do you remember? |
| |
ChristopherJam
Registered: Aug 2004 Posts: 1409 |
Quoting lftSo what you should do is to also expand the hidden part of the actual sprite! It will now be located at $36, and the first 10 lines (fetched from a blank sprite) are y-expanded. Then, after the VSP, you turn off y-expansion for every sprite simultaneously.
Sorry yes, that's what I was attempting to suggest! Thanks for clarifying :)
I started drawing some ascii art, but it was getting too bulky. Time to bump that request for a media area for the forums? I still need to fix the half dozen dropbox hosted images I've posted to other discussions :-/ |
| |
knue
Registered: Dec 2012 Posts: 37 |
@ChristopherJam: That's a really cool idea. But I guess this also means, that I can't use sprites for displaying game infos like life, points and so on because I'll need all sprites (assuming I can have 8 enemies coming from the top) to fight the clipping. |
| |
Compyx
Registered: Jan 2005 Posts: 631 |
How about having the sprites 'pop in', but when clipping is required, copy only the lines of the sprite that needs displaying into the temporary popped-in sprite.
Takes a bit of rastertime, but at least avoid a lot of timing issues and leaves sprites free on the linecrunch area for a score display.
Once the sprite has gone down enough, switch pointer to the normal sprite. |
| |
ChristopherJam
Registered: Aug 2004 Posts: 1409 |
Quoting knue@ChristopherJam: That's a really cool idea. But I guess this also means, that I can't use sprites for displaying game infos like life, points and so on because I'll need all sprites (assuming I can have 8 enemies coming from the top) to fight the clipping.
Thanks! But yes, losing sprites you could have otherwise used for status display is definitely an issue. I was wondering about plotting the status into the blank sprites at a corrected height, but to do that the sprites would need to be unexpanded, so you'd have to set Y at least once per sprite within the AGSP area.
Quoting CompyxHow about having the sprites 'pop in', but when clipping is required, copy only the lines of the sprite that needs displaying into the temporary popped-in sprite.
Takes a bit of rastertime, but at least avoid a lot of timing issues and leaves sprites free on the linecrunch area for a score display.
Once the sprite has gone down enough, switch pointer to the normal sprite.
I was considering that for Hysteron Proteron. It does limit your sprite density, mind. Consider a dense formation of 2x2 sprite enemies; the blank area pushed down from the first row then overlaps the next... |
| |
knue
Registered: Dec 2012 Posts: 37 |
dynamically copying stuff costs too much rastertime for a game.
BTW: Fred's back is having the same problemm. You can see that sprites pop in at the top of the screen.
Even Ghost'n'Goblins (although using a traditional scroller) sort of hast this problem. In level 2 when you climb up the ladders, you can see the halfs of the big goblins popping in out of nowhere at the bottom of the screen. |
| |
Compyx
Registered: Jan 2005 Posts: 631 |
True, when you add 2x2 sprite 'enemies', you'd indeed get overlap, unless you also render the second line of sprites, having them 'pop in' at 21 pixels from the top sprites.
But that'll take even more rastertime and specialized code, and will seriously screw with multiplexing. So things will get out of hand soon.
So yeah, my suggestion might work for simple sprite patterns (ie single sprites for enemies etc), but not for more complex stuff.
I'm also wondering about how to fix the sprite-pointers showing up in the AGSP-adjusted screen, at those locations (ie $x[37bf]f8-$x[37bf]ff) you can only use colorram and background, not vidram (assuming mc bitmap here). |
| |
Digger
Registered: Mar 2005 Posts: 437 |
Could you use one of the illegal modes for $d011 in the upper AGSP area to turn off the screen and hide the sprites behind? Then just switch the sprite priority after the line crunch.
I guess this might not work for some reason, otherwise someone would have already suggested it ;-) |
| |
knue
Registered: Dec 2012 Posts: 37 |
I'm already using the illegal screen mode to blank out the garbage you'd normally see when doing AGSP. And no, sprites are nevertheless displayed in illegal screen mode. You can see this effect in my demo I linked in my first post.
EDIT: current version uses a zero-sprite to do the clipping in software - but this screws up the timing at discussed. So you can't really see this effect in action in my current demo. |
| |
Compyx
Registered: Jan 2005 Posts: 631 |
You could try to use a DYSP over the linecrunch area. Unfortunately that'll take up most/all of the linecrunch area, so no scoreboard in that area.
I did a write-up on DYSP using cycle-counting via a table: http://codebase64.org/doku.php?id=base:dysp_cycle_table
If you adjust the $d011 table, you should be able to force line crunch. (right now it does a simple FLD).
Switch $d018 to point to 'empty sprites' before the line crunch, switch $d018 to proper sprite pointers after the line crunch.
This will require to do the VSP _before_ the line crunch. |
| |
knue
Registered: Dec 2012 Posts: 37 |
Thank you so much for all your helpful input. I'm now doing the following in this order for the AGSP:
* fld
* line crunch
* VSP
After the VSP I have naturally 8 raster lines where timing is not that critical. I do the software zero-sprite-frame trick in that area. So the remaining 21-8=13 raster lines the sprite just pops out. Some sort of middle ground.
As others have suggested, when everything else runs, I can come back to this and see whether I can come up with sth even more sophisticated. |
| |
lft
Registered: Jul 2007 Posts: 369 |
Quoting DiggerCould you use one of the illegal modes for $d011 in the upper AGSP area to turn off the screen and hide the sprites behind? Then just switch the sprite priority after the line crunch.
I guess this might not work for some reason, otherwise someone would have already suggested it ;-)
This could work if you ensure that only foreground pixels are emitted. Use for instance the ECM+multicolour mode, and select a font bank with two pages' worth of $ff.
But you would still have to deal with the timing problems, so there is no improvement over the empty-sprites approach. |
| |
knue
Registered: Dec 2012 Posts: 37 |
Quoting lftQuoting DiggerCould you use one of the illegal modes for $d011 in the upper AGSP area to turn off the screen and hide the sprites behind? Then just switch the sprite priority after the line crunch.
I guess this might not work for some reason, otherwise someone would have already suggested it ;-)
This could work if you ensure that only foreground pixels are emitted. Use for instance the ECM+multicolour mode, and select a font bank with two pages' worth of $ff.
But you would still have to deal with the timing problems, so there is no improvement over the empty-sprites approach.
ah, didn't know that. In my case memory consumption is even worse since I'm using bitmap mode. |
| |
WVL
Registered: Mar 2002 Posts: 902 |
Quote: You might wanna check how we did it in Pinball Dreams. Can't remember right now, but the top paddles must have been properly clipped against the AGSP-area.
@WVL: Do you remember?
Yes, the paddles never go into the AGSP zone :-) They only go in the lower border, never in the AGSP area.
The levels are designed that way (well, we were just lucky..) |
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
Oh!! I thought the upper paddle on Ignition would go under that area when furthest down |
| |
Tom-Cat
Registered: Apr 2003 Posts: 20 |
What upper paddle? All four Pinball Dreams tables only have lower two paddles... :)
Now PLEASE re-start the work on PD C64 because bloody CPC camp is getting an upper hand. And their ball has a black outline, for christ sake. |
| |
ptoing
Registered: Sep 2005 Posts: 271 |
Couldn't you put 8 sprites at the top that are essentially empty or otherwise invisible, but are highest prio, never flicker. So that they will clip off the incoming pixels of the sprites coming from the top.
There are several NES games that make use of similar techniques, should be doable on C64 too, I think.
But then again, I am not a coder. |
| |
knue
Registered: Dec 2012 Posts: 37 |
ChristopherJam already suggested this solution. It could definitely work. However, I wouldn't have sprites left to display points, life and other status info on the top because I would need all sprites to fight the clipping. |
| |
ptoing
Registered: Sep 2005 Posts: 271 |
Ah, I see, so you could not have stuff in the borders. Makes sense. |
| |
ptoing
Registered: Sep 2005 Posts: 271 |
This just randomly popped into my mind, but why can't you have your point/lives/whatever display up in the border, make sure it is 8 sprites for all lines, and then have those at a higher priority setting as the stuff that comes floating onto the char screen? That would work just fine, no? |
| |
knue
Registered: Dec 2012 Posts: 37 |
I don't get how you can achieve constantly 8 sprites within the AGSP area. |
| |
Mixer
Registered: Apr 2008 Posts: 452 |
What about hiding the sprite to sideborder when you wish to clip it. Or vice versa, change x to visible when you wish it to be seen. Or is the timing in the first lines the problem? |
| |
ChristopherJam
Registered: Aug 2004 Posts: 1409 |
Thinking about this a bit more, once you use sprites in the border for your point/lives/whatever display, it already becomes challenging to scroll enemies off the top even if you aren't doing AGSP.
Assume that at some point in time you have the bottom line of pixels of an enemy visible at the top of the play area. Then unless you have a 20 pixel gap between the top of the play area and the bottom of the status area, the Y position of that enemy's sprite will be within the status area.
You could possibly mitigate this a little using sprite-crunch, but the shortest possible sprite is still 17 pixels high (cf short sprites).
Only other options I can think of are either to limit the total number of status-display sprites plus border-leaving sprites to eight, or to soft scroll at least some of the status display elements within the sprites you use to display them. |
| |
ChristopherJam
Registered: Aug 2004 Posts: 1409 |
Ahahahahaah oh god, I just had a thought. If you had a spare most-of-a-bank for it you could hold the status display stationary by doing something along the lines of a sprite FLD routine.
Just change d018 every line to pick out the VM that points to the sprite definitions for that line of the status display (and have each sprite definition containing 21 repeats of the same line of graphics).
You could even mirror the top and bottom borders of the status area.. |
| |
ChristopherJam
Registered: Aug 2004 Posts: 1409 |
Quoting knueI don't get how you can achieve constantly 8 sprites within the AGSP area.
OK, ascii art time.
Say the AGSP area is three lines high, sprites are 5 lines high, and you only want 3 sprites crossing the AGSP area. Then with two enemies entering top of screen, one of which starts halfway through the AGSP area and the other completely crossing it, you position a blank sprite above each of the first three enemies like so:
+----+
| |
| b1 |
| | +----+
+----+ | |
+----+ | b2 | +----+
+aaaaaaaaaa| |aaaaaa| |aa| |aaaaaaaaaa+
+aaaaaaaaaa| e1 |aaaaaa+----+aa| b3 |aaaaaaaaaa+
+aaaaaaaaaa| |aaaaaa+----+aa| |aaaaaaaaaa+
+..........+----+......| |..+----+..........+
+......................| e2 |..................+
+......................| |..+----+..........+
+......................+----+..| |..........+
+..............................| e3 |..........+
+..............................| |..........+
+..............................+----+..........+
+..............................................+
(e1-e3 are enemy sprites, b1-b3 are blank sprites, .... is the play area, aaaa is the AGSP area) You don't really need b1 for timing purposes, it's just easier to do the diagram that way, and possibly easier to code.
The blanks are precisely one sprite-height higher than any border crossing enemy, or positioned to straddle the AGSP area if their corresponding enemy has completely entered the screen.
All that ignores the status display issue of course. |
| |
Compyx
Registered: Jan 2005 Posts: 631 |
Are the blank and enemy sprites different sprites? (ie B1 = sprite 0, E1 = sprite 1, B2= sprite 2, E2 = sprite 3, etc). Or do you intend to reuse B1 for E1 etc, because that would impact the linecruncher a lot, meaning a lot of code to handle the multiplexing, probably leaving you with enough memory for PETSCII level graphics.
Also, how about the VSP at the end of the line cruncher? I've never tried moving sprites over the VSP, but I suspect that's going to be another nice problem to solve. |
| |
lft
Registered: Jul 2007 Posts: 369 |
If the timing is consistent (i.e. all eight sprites guaranteed to be active), then doing VSP is no problem. |
| |
ChristopherJam
Registered: Aug 2004 Posts: 1409 |
Quoting CompyxAre the blank and enemy sprites different sprites? (ie B1 = sprite 0, E1 = sprite 1, B2= sprite 2, E2 = sprite 3, etc). Or do you intend to reuse B1 for E1 etc.
Reuse B1 for E1 etc. The whole point is to ensure the DMA timing is identical for each line of the AGSP routine regardless of enemy position, so any sprite ever used for any of the lines need to be used for all of them. Doesn't add that much to the multiplexor, cf earlier comments in this thread. (sprites would in practice be blank until the start of the play area for a start; no need to change sprite def mid AGSP area)
As for VSP timing, cf lft's remark. |