1

Hi guys I am wondering what the best (fastest) way to horizontally scroll through a tile map is?

I did this once before : I had 21 sprites side by side and every time one went off the left-side of the screen I would move it to the right side of the screen. It worked fine but it wasn't very efficient because I would move each individual sprite to the left one by one.

I have thought about joining sprites (using the sticky bit) together in 2 groups and managing these. Seems a little complicated though having to unstick and re-stick them. I want to know if there is a simpler way I am missing?

I also had an idea of using the fact that the display area automatically wraps round after 512 pixels (I'm sure it does this). But it seems like I would have to use extra sprites to fill up the 512 width to do this or would I?

Thank you I appreciate any help. I am not asking for code Just for the best way to do it

2

Hi

It depends on the design and complexity of your background.

But I would choose an intermediate solution. Having 6 groups of 4 sticked sprites. When a group appears completly offscreen after a scrolling step, it would go to the other side of the screen. This offscreen group could also have his tiles changed comfortably during multiple frames.

3

CosmicR (./1) :
I did this once before : I had 21 sprites side by side and every time one went off the left-side of the screen I would move it to the right side of the screen. It worked fine but it wasn't very efficient because I would move each individual sprite to the left one by one.


Actually, even with an optimal solution, it is important to execute it immediatly after VBlank interrupt to avoid a naughty tearing effect.

4

Thank you for that idea - that is not one I would have thought of myself! It seems like a simpler solution although I guess the disavantage is that it does use more of the horizontal sprite limit up. Especially if you have 2 layer parallax

Do you know how the official Neo Geo games do this kind of horizontal scroll?

5

CosmicR (./4):Do you know how the official Neo Geo games do this kind of horizontal scroll?
there is no simple answer because it depends on the game and the requirements (number of sprites to use etc.). It also sometimes changes from level to level or layers are switched on and off.

- metal slug games use one or two background layers of 32 unlinked sprites in most level games.
- zedblade mostly uses one layer of 32 linked sprites and create the paralaxscrolling via linescroll
- blazing star uses up to 3 layers consisting of 21 unlinked sprites each
- pulstar uses 23 not linked sprites per layer
- spinmaster is very interesting, originally a layer consisted of 32 sprites, but later this was changed to 21sprites... looks a bit strange in VRAM.

if you don't want to use too many sprites then the solution with 32 linked sprites is probably the easiest but if you want to be on the safe side then you should work with 21 sprites even if it means a little more work for you.

by the way, if you use the neogeo typical black border (right and left 8 black pixels) then 20 sprites per layer are enough!

6

That's really interesting info. Thanks blastar.

I can see there could be an advantage using 32 unlinked sprites because you can turn the sprites off that aren't on the visible display (with height=0) Will be interesting to see how that compares speedwise with having 21 or 24 linked sprites in group(s)

Is there any way to use 32 linked sprites and have the non-visible sprites NOT count towards the horizontal sprite limit? (probably a dumb question but I'll ask it anyway!)

One thing I have always wondered was why Blazing Star has flicker on the first boss when you fire your weapon in line with it?. Because just at a glance it doesn't look like there are enough sprites on screen to make flicker happen.

7

I never used 32 linked sprites group, but I would not be surprised if the LSPC simply ignores the sprites outside screen and they don't count in the 96 sprite per line limit.

Did you try to have 4 x 32linked sprites to see what happens ?

8

I'm sure I have tested that - just with a ton of sprites in the past and any sprites outside the display area *DO* count towards the limit. It really bugged me because seems like a bit of a design flaw. I think the Neo Geo just puts the first 96 sprites into the display list based solely on Y position and sprite height. I did only test it in MAME and it was an older version. Maybe its different on real hardware?

9

totologic (./3):
CosmicR (./1) :
I did this once before : I had 21 sprites side by side and every time one went off the left-side of the screen I would move it to the right side of the screen. It worked fine but it wasn't very efficient because I would move each individual sprite to the left one by one.


Actually, even with an optimal solution, it is important to execute it immediatly after VBlank interrupt to avoid a naughty tearing effect.

Hmm, I get A LOT of that tearing when I just (tried the laziest method first) assign all my objects including the background to new sprites each frame.
Does that mean, the further away you get from that Vblank moment while assigning tile adresses in the Sprite control blocks, the more tearing you get? : )

Googling this, I haven't found any real explanation on how the Neo Geo is assigning stuff, unfortunately. Only that you should do this in VBlank.

I rebuilt my "engine" now to have Sprite 0 to 21 as background, and only do that sprite reordering on all the rest of the objects. Which leads to a lot less of that tearing, but still noticable here and there.
avatar

10

My input on this one is that DATLib supports 'scrollers' I believe the documentation indicates that the 'scroller' manages 21 sprites automatically. The updating of the tile gfx is managed under the hood. They are very straight forward to use and there are examples for declaring and incrementing the position of your large map. This is an ideal solution if you want to skip manually programming your own scrolling map.

I have also played around with programming my own managed sprites aka 21 or more free floating strips. I do this still using DATLib and I don't notice tearing. I believe DATLib 0.3 specifically improved tearing (I think that's in the notes from what I remember)

The trick to managing off screen sprites exceeding 21 is to hide / clear the invisible sprites to my knowledge if the sprites are cleared and not redrawn the next frame that allows for more sprites to be drawn. We are always managing 96 sprites turning off/clearing the ones we don't need.

In DATLib 'sprites' are chained aka when you use the animator tool. So I guess you could make 'sprites' that are 4 tiles wide by 512 pixels high. This would mean the act of chaining the sprites is done under the hood via DATLib solely due to the process you are creating sprites via the method DATLib requires. Then you could use the 'Sprite Pool' method to make animating / hiding and showing sprites much easier. DATLib's Sprite Pools are great because they automatically manage sprite widths that fluctuate but in your case all strips will be 64 pixels wide so that is less important but the hiding/showing could be helpful. What I mean is that the pool manages sprites in the list. I belive when they are hidden via DATLibs function call they are not counted toward the 96 sprite limit.

The issue would be updating your strips if you used this method as you would have to iterate the gfx data manually and apply it to the applicable strip.

Then of course if you don't intend on using DATLib this sugestion is not relevant. I must say I love this forum and you guys. I worry my feedback might not be ideal but it is a joy to participate in the madness that is NeoDev!

11

I like datlib very much. This is really great.

Engines like ngdevkit are also cool. But making sprites and backgrounds is not as easy as datlib. I have little development time.

Usually after I write the code. Next time I look at the last code, I can't remember what I wrote.

It's hard for me to master difficult development tools.

Datlib allows me to make some simple games. I will never forget this tool
avatar

12

I haven't used Datlib yet but i think it sounds great. I just like the flexibility of making my own functions atm (even though I am not a good 68k coder!) although I might use Datlib in the future, I wonder how Datlib manages the 21 scrolling sprites under the hood? I'm sure HpMan would be doing it very efficiently. He knows his stuff

Tigerskunk (./9) :
totologic (./3):
CosmicR (./1) :
I did this once before : I had 21 sprites side by side and every time one went off the left-side of the screen I would move it to the right side of the screen. It worked fine but it wasn't very efficient because I would move each individual sprite to the left one by one.


Actually, even with an optimal solution, it is important to execute it immediatly after VBlank interrupt to avoid a naughty tearing effect.

Hmm, I get A LOT of that tearing when I just (tried the laziest method first) assign all my objects including the background to new sprites each frame.
Does that mean, the further away you get from that Vblank moment while assigning tile adresses in the Sprite control blocks, the more tearing you get? : )

Googling this, I haven't found any real explanation on how the Neo Geo is assigning stuff, unfortunately. Only that you should do this in VBlank.

I rebuilt my "engine" now to have Sprite 0 to 21 as background, and only do that sprite reordering on all the rest of the objects. Which leads to a lot less of that tearing, but still noticable here and there.

Yes i think do the scroll straight after the Vblank starts. Yes tearing happens when you are updating an area at or after the same time as that horizontal line of pixels is being redrawn by the graphics chip. So for tall objects - like the scroll strips - make sure those are updated first. You only need to re-write character blocks in sprites that change. You can keep all the background sprite strips the same unless you are adding a new column of map tiles.

13

CosmicR (./12):
Yes i think do the scroll straight after the Vblank starts. Yes tearing happens when you are updating an area at or after the same time as that horizontal line of pixels is being redrawn by the graphics chip. So for tall objects - like the scroll strips - make sure those are updated first. You only need to re-write character blocks in sprites that change. You can keep all the background sprite strips the same unless you are adding a new column of map tiles.

Thanks mate, will try that out.. smile
avatar

14

I'm scrolling horizontally in Xevious. I use two lots of linked sprites.

Each frame (when scrolling) worst case is that you just need to reposition 2 sprites, unlink one and link another. Although the logic is a bit tricky it's still only 4 SCB accesses, which is the key here. I keep track of the left-most sprite in a variable to make things a bit quicker. I also have coded two distinct cases; scrolling that does not require the sprites to change (7/8), and scrolling that does (1/8) in my case (I'm using 50% scaled sprites on the background).

Worst case is when resetting the scroll position to an arbitrary value. Instead of trying to optimise the SCB accesses, I simply unlink and re-link/re-position everything. It's only done very infrequently, and not done during active gameplay.

Also I can confirm that any sprite with height > 0 will be placed in the sprite buffer, regardless of position (on MAME at least, but that is what the MVSTECH doc says too). Not ideal, but that's how it works.

15

That does like the ideal algorithm in terms of speed/efficency
tcdev (./14) :
I'm scrolling horizontally in Xevious. I use two lots of linked sprites.

Each frame (when scrolling) worst case is that you just need to reposition 2 sprites, unlink one and link another. Although the logic is a bit tricky it's still only 4 SCB accesses, which is the key here. I keep track of the left-most sprite in a variable to make things a bit quicker. I also have coded two distinct cases; scrolling that does not require the sprites to change (7/8), and scrolling that does (1/8) in my case (I'm using 50% scaled sprites on the background).

Worst case is when resetting the scroll position to an arbitrary value. Instead of trying to optimise the SCB accesses, I simply unlink and re-link/re-position everything. It's only done very infrequently, and not done during active gameplay.

Also I can confirm that any sprite with height > 0 will be placed in the sprite buffer, regardless of position (on MAME at least, but that is what the MVSTECH doc says too). Not ideal, but that's how it works.

That sounds like the good algorithm in terms of speed. Good to hear you are using that. I was thinking of doing something similar but was tempted by the simplicity of just using 32 linked sprites and letting them wrap around. It's a real shame that the off-screen sprites count toward the horizontal sprite limit.

I think I did read in the docs that it calculates which sprites to draw in the line buffer based on the y coordinate and the height only. That's what the tests I did indicated as well. So any missing or blank characters in a sprite also count towards the horizontal sprite limit.

16

How can you do with only two sprites?
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

17

Brunni (./16) :
How can you do with only two sprites?

He means 2 *sets* of linked sprites. Because they are linked you only need to change the position of the sprite at the head of each set and the others will follow.

As far as I know that is the best way to do it if you want to avoid eating into the horizontal sprite limit too much

18

Yeah. But you need to update the last one each time and relink them right? Because if you display them as a block, the ones going past the boundaries of the screen will eat in the horizontal sprite limit 🤔
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

19

Brunni (./18) :
Yeah. But you need to update the last one each time and relink them right? Because if you display them as a block, the ones going past the boundaries of the screen will eat in the horizontal sprite limit 🤔

Yes I think that's the most efficient way to do it. Have 21 sprites in 2 groups and then unlink. move and link again as they pass the border of the screen. For some games the horizontal sprite limit isn't an issue so you can just link 32 sprites and move as one group that wraps around the 512 pixel wide display area (The leftmost 320 pixels are visible of this)