Jump to content
IGNORED

multi-sprite kernel strategies or examples


Recommended Posts

I'm interested in creating a multi-sprite kernel, but haven't found any good examples to build from, and my searches only turn up references to Batari Basic. Does anybody have an example they could offer, or even just some pseudocode or outline of the general strategy for fitting the logic into the time available for each scan line? 

 

The sole example I've seen is from 8bitworkshop: https://8bitworkshop.com/v3.10.0/?platform=vcs&file=examples%2Fmultisprite3.a But the way it works doesn't seem practical for a real game: lots of JSRs in the middle of the kernel, and no ability to draw the playfield or anything else.

 

I would like to make a kernel that supports updating the playfield and ball every 16 scan lines, and updating the player graphics and color every 2 scan lines. For the players, it should process items from a list sorted by Y coordinate, assigning them to P0 and P1 as they become free for re-use. When the P0 or P1 sprite is done drawing, it should grab the next item from the sorted list and prepare to draw it. I think I understand the general idea, but I'm running into a few difficulties:

 

  • The code is pretty lengthy to check if more players are pending drawing, check if P0 or P1 is available for use, assign the new player to P0/P1, update all the data pointers, etc. It can't all be done during one scan line, but will need to be done over several lines. But I'm not sure how to continue drawing the other player while that's happening, or continue updating the playfield and ball every 16 lines.
  • Part of the task of scheduling a new player is setting the horizontal position by strobing RESP0/RESP1, which requires an entire scan line worth of time, meaning that nothing new can be drawn on that line. Which seems like it forces you to have a doubled line or blank line in the middle of your game, whenever a new player is scheduled and positioned.

 

Thanks for any advice you can share!

Link to comment
Share on other sites

I've done some work on the Multi-Sprite kernel in bBasic; I added multi-color support to P0/P1 for improving 1942:

https://github.com/Al-Nafuur/1942-bB

https://github.com/Al-Nafuur/1942-bB/blob/main/src/multisprite_kernel.asm

 

I'd HIGHLY recommend you take a look at it.  It sounds like what you're asking for is covered there.  The only caveat is that only ONE of the player sprites is reused.  Swapping out sprites requires a separate 4-line kernel that interleaves with the work necessary to maintain all the rest of the drawing needed by the 2-line kernel.

 

Feel free to ask any questions, and I'll try to answer them the best I can.

  • Thanks 1
Link to comment
Share on other sites

Thanks! I took a brief skim through this kernel code, and it looks like a great example. I'll go through it more carefully later today.

 

Do you think it's practical to design a multi-sprite kernel that uses both player sprites instead of just one? That's what I'd been aiming for, but maybe it's not realistic. I thought Dig Dug did this, but haven't yet tried checking its disassembly to see exactly what it's doing.

Link to comment
Share on other sites

8 hours ago, splendidnut said:

Feel free to ask any questions, and I'll try to answer them the best I can.

OK I took a deeper look through this kernel code, and also tried the game. Extremely impressive, very nice job!

 

Multi-sprite kernel questions:

  • How does this deal with 'missed' sprites, where by the time you've finished drawing one sprite it's too late to begin drawing the next one, because they partially overlap? It seems like it doesn't - RepoKernel just sets up the next sprite index and goes on its way? Maybe this is handled earlier during the sorting phase, where overlapping sprites are removed from the list completely? Or maybe the game design guarantees you'll never have overlapping sprites?
  • Why isn't there any HMOVE comb at the left, due to repositioning P1?
  • In the regular kernel loop, I only counted 22 spare clock cycles in the worst case, spread across the two scan lines of the main loop. The RepoKernel needs to do everything the main kernel does, plus a lot more... so how the heck does it squeeze that all into the 22 spare cycles? Even spread across two pairs of lines like it is here, that's only 44 spare cycles. I need to stare at the code longer to understand how that's all possible.

Other questions and comments:

  • I'm confused by the P1 coloring. It's a type of color gradient based on the distance from the current scan line to the sprite baseline, mod 8, OR'd with another value and then used as a table lookup. Wouldn't it be faster and potentially better-looking to have a full-blown color table for P1, with a unique color for every line? Or you could reproduce the gradient look, but with fewer cycles.
  • Why are there multiple levels of indirection in the sprite lists? SpriteIndex looks up an entry in SpriteGfxIndex, and the result looks up another entry in NewSpriteX.
  • pfPixelHeight seems to be misnamed, or else I don't understand it. From source comments and usage, it's actually a row index and not the height of anything.
  • COLUP0/1 is changed on a different scan line than GRP0/1. Doesn't that create some odd-looking results? Is that why you're using a color gradient instead of a full color table?
  • The missiles are also changed on a different scan line than the players, I think. For bullets I suppose this is fine, but would be a problem if missiles need to align exactly with player boundaries?
  • There seems to be some allowance for customization in the kernel that's never used. pfheight is always #15. If the kernel just used #15 everywhere instead of pfheight, I think you could save some cycles.
  • ENAM1 is set a cycle 71 on line 461. It seems like this would create a visual glitch for bullets near the right screen edge.
  • COLUP0 looks like it's set too late on line 478, you can see a glitch in the hero's plane when it's at the far left side of the screen.
Link to comment
Share on other sites

Thanks!   @Al_Nafuur @Pat Brady @homerhomer are the ones that deserve all the credit for 1942.  I really only contributed the addition of multi-color to the multi-sprite kernel.

 

Just now, bigmessowires said:

How does this deal with 'missed' sprites, where by the time you've finished drawing one sprite it's too late to begin drawing the next one, because they partially overlap? It seems like it doesn't - RepoKernel just sets up the next sprite index and goes on its way? Maybe this is handled earlier during the sorting phase, where overlapping sprites are removed from the list completely? Or maybe the game design guarantees you'll never have overlapping sprites?

 

The sprites are flickered when they overlap, the sorting routine is designed in such a way that it takes care of this by alternating / rotating the sprites.

 

1 minute ago, bigmessowires said:

Why isn't there any HMOVE comb at the left, due to repositioning P1?

Early HMOVE -> an HMOVE triggered on cycle 73/74 doesn't cause the black comb on the left.

 

3 minutes ago, bigmessowires said:

I'm confused by the P1 coloring. It's a type of color gradient based on the distance from the current scan line to the sprite baseline, mod 8, OR'd with another value and then used as a table lookup. Wouldn't it be faster and potentially better-looking to have a full-blown color table for P1, with a unique color for every line? Or you could reproduce the gradient look, but with fewer cycles.

It uses a color table that is split into groups each containing 8-lines of color.  The "color" of a sprite is actually the index into that table.  The current sprite scanline is OR'd with the index to do the color lookup for the appropriate sprite line.

 

It's a trick I employed because I didn't have enough time / RAM to track and swap out color table pointers during the repositioning kernel.

 

11 minutes ago, bigmessowires said:

Why are there multiple levels of indirection in the sprite lists? SpriteIndex looks up an entry in SpriteGfxIndex, and the result looks up another entry in NewSpriteX.

Sorting / flickering of the sprites requires a bit of indirection.  SpriteIndex is a counter.  SpriteGfxIndex is the sorted sprite table containing indexes into the actual sprite data arrays.

 

32 minutes ago, bigmessowires said:

pfPixelHeight seems to be misnamed, or else I don't understand it. From source comments and usage, it's actually a row index and not the height of anything.

Correct.  I don't know why that is;  I wasn't the one who named it.  I don't think I changed any of the variable names.

 

36 minutes ago, bigmessowires said:

COLUP0/1 is changed on a different scan line than GRP0/1. Doesn't that create some odd-looking results? Is that why you're using a color gradient instead of a full color table?

When I added the color changing stuff, I had to stick it where it would fit.  It just happens to work out nicely with the gradients.

 

39 minutes ago, bigmessowires said:

There seems to be some allowance for customization in the kernel that's never used. pfheight is always #15. If the kernel just used #15 everywhere instead of pfheight, I think you could save some cycles.

1942 does use different values for pfheight.  If you look in the BAS source file, you can see this.  It uses the values of 0, 1, and 3.

 

42 minutes ago, bigmessowires said:
  • ENAM1 is set a cycle 71 on line 461. It seems like this would create a visual glitch for bullets near the right screen edge.
  • COLUP0 looks like it's set too late on line 478, you can see a glitch in the hero's plane when it's at the far left side of the screen.

Yup.  Compromises had to be made.  It's not perfect, but it gets the job done.

  • Like 1
  • Thanks 1
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...