Mode 72 development

Topics related to the API, programming discussions & questions, coding tips, bugs, etc. should go here.
rocifier
Posts: 71
Joined: Thu Jan 22, 2015 6:35 am

Re: Mode 72 development

Post by rocifier »

Jubatian wrote: Thu Mar 29, 2018 6:40 am
rocifier wrote: Thu Mar 29, 2018 6:27 amAh I see. So in my case I am just going to try and use m72_rowoff. But I can't notice any visual difference with the following code I adapted from the sample, not sure why.
If you are just doing a full-screen horizontal scroll, there shouldn't be a visual difference (both methods are equally capable of doing it, it is just that with the default method, you can scroll each tile row independently for parallax effects). The code you posted should work all right for the default configuration (M72_USE_XPOS zero or not set).
rocifier wrote: Thu Mar 29, 2018 6:27 amEDIT: I can see the vram scrolling in the emulator debug, but the tiles don't change on the display ?
I don't understand what do you mean here (what is exactly happening and what are you expecting). Could you send some sample in PM? (I know that these features work correctly the way I intended them to work as I tested them, however I can't know how are you expecting it to work. Maybe resolving this will be good source for clarifying documentations then)
LOL you know why I couldn't see it? After taking a break I realized that I was testing it looking at a view that contained full rows of single coloured tiles and sprites. Well, of course the tiles were scrolling but there was no way to see that! And sprites don't scroll! I'm really laughing out loud about this now: my test setup was a complete failure.
rocifier
Posts: 71
Joined: Thu Jan 22, 2015 6:35 am

Re: Mode 72 development

Post by rocifier »

Hi Jubatian, I'm finding it practically quite difficult to work with the sprites in mode72. Ideally what I want to do is have a list of 40 enemy sprites and enable/disable them during gameplay (as well as set other info on them), and not have to worry about re-configuring sprite chains. Right now I'm handling the enable/disable by setting the height to 0 but from what I understand when it comes across a sprite with height 0 it just doesn't go any further in the sprite chain rendering?

How would you advise I handle this situation of spawning enemies?

Unfortunately I've been stuck for a while on getting two sprites to render. I've set up the sprite chain with 40 linked together using .next, but only the first one is being rendered. I've compared with the example and can't tell why it's not working. Any ideas how to debug this?

Here is how I am setting up the enemies sprite chain (index 2):

Code: Select all

void InitEnemies() {
	for (u8 i = 0; i < MAX_ENEMY_COUNT; i++) {
		enemy[i].type = 0;
		enemy[i].health = 0;
		enemy[i].sprite.height = 0;
		enemy[i].sprite.off = 0;
		enemy[i].sprite.xpos = 0;
		enemy[i].sprite.ypos = 0;
		enemy[i].sprite.next = &enemy[i + 1].sprite;
	}
	enemy[MAX_ENEMY_COUNT - 1].sprite.next = NULL;
	sprites[SPRITE_INDEX_ENEMIES] = &enemy[0].sprite;
}
User avatar
Jubatian
Posts: 1561
Joined: Thu Oct 01, 2015 9:44 pm
Location: Hungary
Contact:

Re: Mode 72 development

Post by Jubatian »

rocifier wrote: Sun Apr 01, 2018 9:14 amHi Jubatian, I'm finding it practically quite difficult to work with the sprites in mode72. (...)
There are limitations in the chaining technique allowing reusing sprite slots. The most important is that the mode can not order sprites. The display is drawn from top to bottom, the mode operates like hardware sprite solutions of old microcomputers (such as the VIC II in the C64), a sprite's display starts when the sprite Y "register" matches the scanline counter. When this happens, internally the mode selects the next sprite in the chain.

The Mode 72 solution is a bit more flexible. It loads the next sprite on a slot when the current one just finished display (so after it's bottommost scanline, that scanline just below the bottom will be empty as it is used to load the next sprite). This means that if the loaded sprite never displays (it was above the previous), then no more sprites will display on that slot. However if the sprite still displays (partial overlapping), then things will continue as normal, the sprite's bottommost scanline can be reached, and then again a further sprite of the slot can load.

So to have everything displaying for a sprite slot, you have to:
  • Have the sprites belonging to that slot Y ordered (top to bottom).
  • Don't have two sprites sharing the same Y value
You may get away with fixed chains if your game design is such that you can plan your enemy movements so they fulfill the above. Otherwise you need to create some logic to have the sprites properly sorted (the problem is similar to what you would have to cope with if you wrote a sprite multiplexer for the C64's VIC II).
rocifier
Posts: 71
Joined: Thu Jan 22, 2015 6:35 am

Re: Mode 72 development

Post by rocifier »

Jubatian wrote: Sun Apr 01, 2018 11:44 am
rocifier wrote: Sun Apr 01, 2018 9:14 amHi Jubatian, I'm finding it practically quite difficult to work with the sprites in mode72. (...)
There are limitations in the chaining technique allowing reusing sprite slots. The most important is that the mode can not order sprites. The display is drawn from top to bottom, the mode operates like hardware sprite solutions of old microcomputers (such as the VIC II in the C64), a sprite's display starts when the sprite Y "register" matches the scanline counter. When this happens, internally the mode selects the next sprite in the chain.

The Mode 72 solution is a bit more flexible. It loads the next sprite on a slot when the current one just finished display (so after it's bottommost scanline, that scanline just below the bottom will be empty as it is used to load the next sprite). This means that if the loaded sprite never displays (it was above the previous), then no more sprites will display on that slot. However if the sprite still displays (partial overlapping), then things will continue as normal, the sprite's bottommost scanline can be reached, and then again a further sprite of the slot can load.

So to have everything displaying for a sprite slot, you have to:
  • Have the sprites belonging to that slot Y ordered (top to bottom).
  • Don't have two sprites sharing the same Y value
You may get away with fixed chains if your game design is such that you can plan your enemy movements so they fulfill the above. Otherwise you need to create some logic to have the sprites properly sorted (the problem is similar to what you would have to cope with if you wrote a sprite multiplexer for the C64's VIC II).
Hmm yes this is indeed challenging. I didn't realise two sprites in a slot couldn't share the same y value, that explains why the second one doesn't render. Thank you. How did you handle the situation in FOAD with so many sprites all over the place?
User avatar
Jubatian
Posts: 1561
Joined: Thu Oct 01, 2015 9:44 pm
Location: Hungary
Contact:

Re: Mode 72 development

Post by Jubatian »

rocifier wrote: Sun Apr 01, 2018 12:07 pmHmm yes this is indeed challenging. I didn't realise two sprites in a slot couldn't share the same y value, that explains why the second one doesn't render. Thank you. How did you handle the situation in FOAD with so many sprites all over the place?
FoaD is Mode 74, which is a blitting video mode, see this post in which I made suggestions, then lower I explain the advantages and drawbacks of each. In Mode 74 the total sprite coverage is limited, and lots of CPU power is also taken for utilizing it. To cope with it, FoaD runs at half frame rate, one frame dedicated to rendering, the other to game logic.

In Mode 72 no RAM and CPU is taken for realizing sprites. Any kind of sorting you implement for preparing the sprite chains will take a lot less CPU than blitting.

The simplest "brute force" method for your game is probably just sorting all the sprites by Y, then allocating them to sprite slots in a round-robin manner. First sprite to slot 0, second to slot 1, etc. Your game (I guess) doesn't need to care much about which sprite shows over which, so this works, and it is fairly simple to do.

Then you just make sure that your enemy waves are designed so they don't exhaust the horizontal limit (with the above method you will have sprites partially not shown long before sprite chains would halt).
rocifier
Posts: 71
Joined: Thu Jan 22, 2015 6:35 am

Re: Mode 72 development

Post by rocifier »

Hi Jubatian, I have rewritten the code so that each sprite chain goes like this:

Code: Select all

TOP
\/
MID
\/
GROUND
Basically there are three regions which don't overlap that sprites can spawn at, and hover around. However what I'm finding is still that only the first sprite in each chain is rendering. I've tried flipping all the Y values. The first sprites in the chain are of 0 height, and the third sprite is 8 high. I assumed the height of 0 is valid to go to the next one down the chain, since you didn't mention it. I have also tried setting the first sprites to a height of 1 and rendering them off-screen. Here is my setup code below for the chains:

Code: Select all

void InitEnemies() {
    // enemy zones for rendering Y:
    // 0-7 top zone
    // 8-15 mid zone
    // 16-23 ground zone
    u8 i = 0;
    for (; i < MAX_ENEMY_COUNT; i++) {
		enemy[i].type = 0;
		enemy[i].health = 0;
		enemy[i].sprite.height = 1;
		enemy[i].sprite.off = 0;
		enemy[i].sprite.xpos = 0;
		enemy[i].sprite.ypos = WorldYToScreenY(0);
    }
    // link higher zones to render the next zone down
    for (i = 0; i < 8; i++) {
		enemy[i].sprite.next = &enemy[i + 8].sprite;
		enemy[i + 8].sprite.next = &enemy[i + 16].sprite;
		enemy[i + 16].sprite.next = NULL;
        sprites[SPRITE_INDEX_ENEMIES + i] = &enemy[i].sprite;
    }
}
User avatar
Jubatian
Posts: 1561
Joined: Thu Oct 01, 2015 9:44 pm
Location: Hungary
Contact:

Re: Mode 72 development

Post by Jubatian »

Although you say you tried Y flipping, I would still recommend checking that (the code you posted doesn't show what you use to fill the Y coordinate).

A quirk of the mode is that you need to negate Y values (like on Line 279 of the example). The sprites must occur in top to down order in the chain, that is, topmost sprite first, bottommost sprite last. You will have the largest written Y value for the topmost sprite.

If you use sprite slots this way, a fixed layout, use the X coordinate to hide the sprite (set it to 255), and keep Y within the zone the sprite is supposed to belong to. This will still make the sprite using the slot at that position, but since the layout is fixed, this is OK. If it still doesn't want to work right, first try it with fixed Y coordinates, and start adding code adjusting Y in small steps to see where things break. A height of 0 is valid.

You may also take a look at the video frame structure described in the main assembly file. The topmost visible scanline is line 32, so if you position a sprite at line 1 (writing 0U - 1U into the Y register), it likely won't display as it is off-screen on the top.
rocifier
Posts: 71
Joined: Thu Jan 22, 2015 6:35 am

Re: Mode 72 development

Post by rocifier »

Jubatian wrote: Thu Apr 05, 2018 10:49 am Although you say you tried Y flipping, I would still recommend checking that (the code you posted doesn't show what you use to fill the Y coordinate).

A quirk of the mode is that you need to negate Y values (like on Line 279 of the example). The sprites must occur in top to down order in the chain, that is, topmost sprite first, bottommost sprite last. You will have the largest written Y value for the topmost sprite.

If you use sprite slots this way, a fixed layout, use the X coordinate to hide the sprite (set it to 255), and keep Y within the zone the sprite is supposed to belong to. This will still make the sprite using the slot at that position, but since the layout is fixed, this is OK. If it still doesn't want to work right, first try it with fixed Y coordinates, and start adding code adjusting Y in small steps to see where things break. A height of 0 is valid.

You may also take a look at the video frame structure described in the main assembly file. The topmost visible scanline is line 32, so if you position a sprite at line 1 (writing 0U - 1U into the Y register), it likely won't display as it is off-screen on the top.
Thanks this gives me some more ideas to try tonight. What is the y order supposed to be? From low to high integer values even though they will show "bottom-up"?
User avatar
Jubatian
Posts: 1561
Joined: Thu Oct 01, 2015 9:44 pm
Location: Hungary
Contact:

Re: Mode 72 development

Post by Jubatian »

rocifier wrote: Thu Apr 05, 2018 9:31 pmThanks this gives me some more ideas to try tonight. What is the y order supposed to be? From low to high integer values even though they will show "bottom-up"?
No, the opposite. It is better to remember that the topmost sprite on the display needs to belong to the first element in a sprite chain. Usually you would set up the Y register by "sprite.ypos = 0U - variable;", where "variable" is the intended scanline position.

(This quirk can not be fixed as it would demand additional instructions within the HBlank period of display scanlines, which of course don't fit there)
rocifier
Posts: 71
Joined: Thu Jan 22, 2015 6:35 am

Re: Mode 72 development

Post by rocifier »

Jubatian wrote: Thu Apr 05, 2018 10:49 am You may also take a look at the video frame structure described in the main assembly file. The topmost visible scanline is line 32, so if you position a sprite at line 1 (writing 0U - 1U into the Y register), it likely won't display as it is off-screen on the top.
I finally got it, the above comment tipped me off. So the sprite actually needs to be in the "Render Zone" for it to render the next one in the chain, which totally makes sense now. Before I was setting the Y position to around 224 pixels, but I needed to subtract the 32 mentioned above from that so that it renders in the screen area (even though the height is 0 and the offset is NULL).

TOP (180 pixel Y)
\/
MID (128 pixel Y)
\/
GROUND (64 pixel Y)

enables the ground sprite to render
Post Reply