Jump to content

New Demo - Sonic Green Hill Zone simulation on X16


ZeroByte
 Share

Recommended Posts

It seems to have broken the "try it now" feature - lol. Maybe I need to type the PRG name in all-caps?

EDIT: Yeah, that makes it run. Still no sound though, even if I un-click the mute icon. Strange.

Edited by ZeroByte
added results
Link to comment
Share on other sites

Funny thing is, I actually built a pitch-corrected version of the music stream for R38 (which has the YM clocked at 4MHz instead of 3.5MHz) so the FM and PSG are in tune with each other... R38 runs on the real emulator as well.

Link to comment
Share on other sites

On 10/18/2021 at 10:35 PM, Ed Minchau said:

It looks like a lot more than two layers in that parallax effect.

The Background actually has 17 layers of scrolling. The clouds/tall mountains are the main BG scroll value. I created a table of 16 raster line values and the demo cycles through these, setting each one as the next line IRQ to trigger on.

When the main loop begins, it creates a table of scroll offsets based on the main BG's scroll value (which is 1/8 the FG scroll value). It divides BG scroll by 2 to create a "per line scroll amount" (delta). On each raster IRQ, the BG scroll is incremented by delta. After 16 iterations, the bottom row of water ripples will be scrolled at the same amount as the FG (this happens below the path, so you don't see it scrolling at the same speed as the FG though). All values (FG, BG, and per-rasterline) also keep a subpixel scroll amount, so the speed is very flexible - as low as 1/16 of a pixel per frame (FG scroll). This subpixel scroll amount is maintained through the creation of the 16 raster scroll values as well in order to keep it nice and smooth.

I did cheat for Sonic's Y coordinate though. The tile set is arranged very erratically. I'm convinced there must be meta-data in the tile numbers to indicate things like "vertical offset" that I'm just not seeing - and making a table of varying terrain heights from tile IDs was crazy, and required a linear search through the table, just to determine something as simple as how high Sonic is with the ground. So since the BG is fixed and repeating, I just fudged and made a "per column" table by hand and have the game cycle through that table with every 8px of scrolling performed. It works for this demo, but if I were to have more varied terrain or vertical scrolling for things like jumping or higher platforms, I'd have to do a lot more work to make Sonic properly collide with tiles. Not necessary here, so I took the path of least resistance. 🙂

 

  • Like 3
Link to comment
Share on other sites

On 10/19/2021 at 12:02 AM, ZeroByte said:

The Background actually has 17 layers of scrolling. The clouds/tall mountains are the main BG scroll value. I created a table of 16 raster line values and the demo cycles through these, setting each one as the next line IRQ to trigger on.

When the main loop begins, it creates a table of scroll offsets based on the main BG's scroll value (which is 1/8 the FG scroll value). It divides BG scroll by 2 to create a "per line scroll amount" (delta). On each raster IRQ, the BG scroll is incremented by delta. After 16 iterations, the bottom row of water ripples will be scrolled at the same amount as the FG (this happens below the path, so you don't see it scrolling at the same speed as the FG though). All values (FG, BG, and per-rasterline) also keep a subpixel scroll amount, so the speed is very flexible - as low as 1/16 of a pixel per frame (FG scroll). This subpixel scroll amount is maintained through the creation of the 16 raster scroll values as well in order to keep it nice and smooth.

I did cheat for Sonic's Y coordinate though. The tile set is arranged very erratically. I'm convinced there must be meta-data in the tile numbers to indicate things like "vertical offset" that I'm just not seeing - and making a table of varying terrain heights from tile IDs was crazy, and required a linear search through the table, just to determine something as simple as how high Sonic is with the ground. So since the BG is fixed and repeating, I just fudged and made a "per column" table by hand and have the game cycle through that table with every 8px of scrolling performed. It works for this demo, but if I were to have more varied terrain or vertical scrolling for things like jumping or higher platforms, I'd have to do a lot more work to make Sonic properly collide with tiles. Not necessary here, so I took the path of least resistance. 🙂

 

I thought I'd seen something about how collision detection in Sonic worked, and looked around some and came across this. Looks like it could be interesting to you: https://info.sonicretro.org/Sonic_Physics_Guide

In particular, https://info.sonicretro.org/SPG:Solid_Tiles and https://info.sonicretro.org/SPG:Slope_Physics

  • Thanks 1
Link to comment
Share on other sites

On 10/18/2021 at 11:31 PM, Ender said:

I thought I'd seen something about how collision detection in Sonic worked, and looked around some and came across this. Looks like it could be interesting to you: https://info.sonicretro.org/Sonic_Physics_Guide

In particular, https://info.sonicretro.org/SPG:Solid_Tiles and https://info.sonicretro.org/SPG:Slope_Physics

Interesting read. They don't get super explicit about the tile data itself, and from reading it a couple of times, it appears to me that there is another data structure not in VRAM which contains the so-called "solid tiles" of the map, and it's these solid tiles and not the graphical tiles which are used for collisions.

It makes sense because let me tell you what, there are a ba-ZILLION tiles in the set (I think just under 1000). Genesis's tilemap is close to VERA's - except it uses 11 bits for tile ID, has H-flip and V-Flip, but only 2-bit color palette choice. The final bit is a tile priority bit which makes the tile appear above sprites of the same layer, which is a bit that I really wish VERA had. The tiles are not grouped together in ways that make sense to me; definitely NOT like you see in pixel art tutorials with the tiles arranged as basic rectangles of the terrain type... No, they're scattered all over the place and only vaguely grouped as to whether they're sloped, have ground above and below, below only, etc.

I had originally planned to make my demo procedurally generate terrain and have Sonic run through it, but after several hours working with the tile set to get it converted and then playing around with them in Aseprite's tile mode, it was painfully obvious that it would take me weeks to even make a set of pre-defined terrain segments to lace together, so I figured "screw it" and just ripped the tilemap data of the start area and used that. (had to convert Genesis -> VERA format, which included a big->little endian swap)

Link to comment
Share on other sites

On 10/18/2021 at 11:59 PM, ZeroByte said:

EDIT: Yeah, that makes it run. Still no sound though, even if I un-click the mute icon. Strange.

The web based emulator has a white list for file extensions. The music files have to use the .BIN file extension, too.

I think allowed is only .PRG and .BIN, maybe .SEQ, don't remember.

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

On 10/18/2021 at 11:02 PM, ZeroByte said:

The Background actually has 17 layers of scrolling. The clouds/tall mountains are the main BG scroll value. I created a table of 16 raster line values and the demo cycles through these, setting each one as the next line IRQ to trigger on.

When the main loop begins, it creates a table of scroll offsets based on the main BG's scroll value (which is 1/8 the FG scroll value). It divides BG scroll by 2 to create a "per line scroll amount" (delta). On each raster IRQ, the BG scroll is incremented by delta. After 16 iterations, the bottom row of water ripples will be scrolled at the same amount as the FG (this happens below the path, so you don't see it scrolling at the same speed as the FG though). All values (FG, BG, and per-rasterline) also keep a subpixel scroll amount, so the speed is very flexible - as low as 1/16 of a pixel per frame (FG scroll). This subpixel scroll amount is maintained through the creation of the 16 raster scroll values as well in order to keep it nice and smooth.

I did cheat for Sonic's Y coordinate though. The tile set is arranged very erratically. I'm convinced there must be meta-data in the tile numbers to indicate things like "vertical offset" that I'm just not seeing - and making a table of varying terrain heights from tile IDs was crazy, and required a linear search through the table, just to determine something as simple as how high Sonic is with the ground. So since the BG is fixed and repeating, I just fudged and made a "per column" table by hand and have the game cycle through that table with every 8px of scrolling performed. It works for this demo, but if I were to have more varied terrain or vertical scrolling for things like jumping or higher platforms, I'd have to do a lot more work to make Sonic properly collide with tiles. Not necessary here, so I took the path of least resistance. 🙂

 

This is really neat. I was just wondering what you might do though if you wanted to make the real game or a game like it, and you need Sonic to jump on a trampoline. Wouldn't that mean updating your IRQ table on every frame then, and skipping values that are temporarily off-screen? I was also wondering how vertical parallax might be accomplished.

  • Like 1
Link to comment
Share on other sites

On 10/25/2021 at 1:02 AM, john_e79 said:

Wouldn't that mean updating your IRQ table on every frame then, and skipping values that are temporarily off-screen?

It already has to update on every frame anyway. At least it does with the method I'm using to calculate the per-raster scroll values. I've had exatly 0.0000 experience with parallax scrolling prior to this demo, so I was really experimenting a lot to find a mix of values that looked close enough to the original game.

Calculating the scroll values:

One of the tasks in the main loop is to calculate all scroll values (jsr doscroll)

I use 16.8 fixed point values for FG and BG scroll amounts, and 4.4 fixed point for sonic_speed. This gives a lot of flexibility in scroll amounts: 1/256 pixel scrolling resolution, and speed can be 1/16 pixel-per-frame up to ~16 pixels per frame. If I needed higher max or lower subpixel speed resolution, I'd just use 8.8 fixed point for speed.

FG scroll is easy:
FG_scroll += sonic_speed.

BG_scroll is just FG_scroll / 8 ( i.e. right-shift 3 times)

The raster calculations:
The BG scroll value becomes the baseline - if I want 16 divisions to reach the FG scroll value, I just right-shift BG_scroll one more time to obtain "delta" - and then increment scroll amount by delta 16 times, each value going into the raster scroll values table. This was where I did a lot of noodling around with the method because I've never done anything with even so much as simple multi-layer scrolling, let alone a smooth pseudo-3d effect like this. Long story short, since the hscroll is being increased linearly, the spacing of the raster IRQs should be linear as well in order to look continuous (as I've determined from experimenting - I didn't read any papers on the subject or anything - what's the fun in that?)

I did a little experimentation to find the exact raster lines to use for the IRQ triggers and put those into another table.

The IRQ handler itself:
The line IRQ simply reads the h_scroll amount from the current row of the table, writes it to VERA, updates the pointer, reads the next raster line number from the rasterlines table, and writes that into the LINE_IRQ register(s) of VERA.
Finally, it acks the IRQ, and exits. (using ply plx pla rti, NOT a jump into the Kernal - that's for VSYNC to do)

 

How would vertical scrolling affect this?

It depends on how far down the rabbit hole you want to go. The original game does not scroll the BG vertically on Green Hill Zone. It may LOOK like it does, but it's an illusion - the fact that it doesn't scroll vertically used to bother me when I first played the game back in the day. I always thought it did scroll but only very slowly - no it doesn't budge as far as I could see while observing for this project. Therefore, for an actual Sonic game engine, all it would need to do is make sure the water effect looks good all the way to the bottom of displayable screen, and you're done. Just update the actual tile content of the BG layer for more variety as you travel along....

But if you DID want to scroll vertically as well, you can do all kinds of things. Since the raster lines themselves are dictated by a table, you could easily update that table to account for vertical scrolling of the BG layer while computing the h_scroll amounts. In fact, it might work well enough to just keep a static table and use a "delta-y" variable that gets added in by the raster IRQ handler as it updates the LINE IRQ setting in VERA.

If you wanted to get ULTRA-fancy, and simulate a varying camera perspective on the pseudo-3d surface, you'd want to gradually increase the spacing between raster lines as the "camera" moves up (and the BG scrolls down) and crunch them together more as the "camera" goes down (and the BG scrolls up). This would totally not be worth doing on the water in GHZ because it's a very noisy paittern that's also undergoing palette rotation - your eye would not really pick up the subtle difference this makes with such a noisy pattern, but if it were something more akin to the floors in Street Fighter II, then that's how you'd do it.

 

  • Like 2
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.

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.

 Share

×
×
  • Create New...

Important Information

Please review our Terms of Use